summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--LICENSE15
-rw-r--r--assembly.xml1
-rwxr-xr-xdocker/Dockerfile2
-rw-r--r--docs/platform/APIs/NSLCM_API/NSLCM_API_Specification_v0.1.rst1693
-rw-r--r--docs/platform/APIs/VNFLCM_API/VNFLCM_API.rst7
-rw-r--r--docs/platform/APIs/VNFMDriver_API/VNFM_Driver_API.rst2
-rw-r--r--docs/platform/APIs/index.rst8
-rw-r--r--docs/platform/Auto-healing.pngbin0 -> 138954 bytes
-rw-r--r--docs/platform/Instantiation.pngbin0 -> 260486 bytes
-rw-r--r--docs/platform/Termination.pngbin0 -> 246810 bytes
-rw-r--r--docs/platform/architecture.rst16
-rw-r--r--docs/platform/consumedapis.rst1
-rw-r--r--docs/platform/delivery.rst44
-rw-r--r--docs/platform/index.rst24
-rw-r--r--docs/platform/vfc-component.pngbin0 -> 8497 bytes
-rw-r--r--docs/release-notes.rst.bak77
-rw-r--r--lcm/__init__.py3
-rw-r--r--lcm/jobs/serializers.py48
-rw-r--r--lcm/jobs/tests/tests.py9
-rw-r--r--lcm/jobs/urls.py8
-rw-r--r--lcm/jobs/views.py77
-rw-r--r--lcm/log.yml50
-rw-r--r--lcm/middleware.py60
-rw-r--r--lcm/ns/data/scalemapping.json58
-rw-r--r--lcm/ns/ns_manual_scale.py46
-rw-r--r--lcm/ns/ns_terminate.py3
-rw-r--r--lcm/ns/serializers.py132
-rw-r--r--lcm/ns/sfcs/detail_views.py48
-rw-r--r--lcm/ns/sfcs/serializers.py65
-rw-r--r--lcm/ns/sfcs/urls.py18
-rw-r--r--lcm/ns/sfcs/views.py96
-rw-r--r--lcm/ns/tests/sfcs/test_create_flow_classifier.py101
-rw-r--r--lcm/ns/tests/sfcs/test_create_port_chain.py103
-rw-r--r--lcm/ns/tests/sfcs/test_create_port_pair_group.py158
-rw-r--r--lcm/ns/tests/sfcs/test_data.py1
-rw-r--r--lcm/ns/tests/sfcs/test_sfc.py3269
-rw-r--r--lcm/ns/tests/sfcs/test_sfc_instance.py70
-rw-r--r--lcm/ns/tests/test_ns_create.py4
-rw-r--r--lcm/ns/tests/test_ns_delete.py31
-rw-r--r--lcm/ns/tests/test_ns_get.py2
-rw-r--r--lcm/ns/tests/test_ns_heal.py3
-rw-r--r--lcm/ns/tests/test_ns_manual_scale.py248
-rw-r--r--lcm/ns/tests/tests_ns_terminate.py8
-rw-r--r--lcm/ns/tests/vls/tests.py6
-rw-r--r--lcm/ns/tests/vnfs/tests.py83
-rw-r--r--lcm/ns/urls.py25
-rw-r--r--lcm/ns/views.py231
-rw-r--r--lcm/ns/vls/serializers.py39
-rw-r--r--lcm/ns/vls/urls.py10
-rw-r--r--lcm/ns/vls/views.py59
-rw-r--r--lcm/ns/vnfs/notify_lcm.py5
-rw-r--r--lcm/ns/vnfs/scale_vnfs.py68
-rw-r--r--lcm/ns/vnfs/serializers.py223
-rw-r--r--lcm/ns/vnfs/terminate_nfs.py2
-rw-r--r--lcm/ns/vnfs/urls.py29
-rw-r--r--lcm/ns/vnfs/views.py165
-rw-r--r--lcm/pub/config/config.py5
-rw-r--r--lcm/pub/database/models.py2
-rw-r--r--lcm/pub/msapi/catalog.py11
-rw-r--r--lcm/pub/msapi/extsys.py2
-rw-r--r--lcm/pub/tests/__init__.py13
-rw-r--r--lcm/pub/tests/test_scaleaspect.py398
-rw-r--r--lcm/pub/utils/jobutil.py2
-rw-r--r--lcm/pub/utils/scaleaspect.py202
-rw-r--r--lcm/samples/serializers.py19
-rw-r--r--lcm/samples/views.py34
-rw-r--r--lcm/settings.py105
-rw-r--r--lcm/swagger/urls.py18
-rw-r--r--lcm/swagger/vfc.nslcm.swagger.json22
-rw-r--r--lcm/swagger/vfc.vnfdriver.swagger.json23
-rw-r--r--lcm/swagger/views.py9
-rw-r--r--lcm/urls.py13
-rw-r--r--lcm/v2/__init__.py13
-rw-r--r--lcm/v2/grant_vnf.py35
-rw-r--r--lcm/v2/serializers.py1001
-rw-r--r--lcm/v2/tests.py217
-rw-r--r--lcm/v2/urls.py24
-rw-r--r--lcm/v2/views.py84
-rwxr-xr-xmvn-phase-script.sh86
-rw-r--r--pom.xml65
-rw-r--r--requirements.txt16
-rwxr-xr-xrun.sh12
-rw-r--r--tox.ini2
83 files changed, 6578 insertions, 3409 deletions
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 00000000..7b59118f
--- /dev/null
+++ b/LICENSE
@@ -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
index afb97eff..5e7aef75 100644
--- a/assembly.xml
+++ b/assembly.xml
@@ -31,6 +31,7 @@
<include>**/*.wsdl</include>
<include>**/*.xsd</include>
<include>**/*.bpel</include>
+ <include>**/*.yml</include>
</includes>
</fileSet>
<fileSet>
diff --git a/docker/Dockerfile b/docker/Dockerfile
index 28b259c9..ec325137 100755
--- a/docker/Dockerfile
+++ b/docker/Dockerfile
@@ -30,7 +30,7 @@ ADD . /service
WORKDIR /service
# get binary zip from nexus - vfc-nfvo-lcm
-RUN wget -q -O vfc-nfvo-lcm.zip 'https://nexus.onap.org/service/local/artifact/maven/redirect?r=staging&g=org.onap.vfc.nfvo.lcm&a=vfc-nfvo-lcm&v=LATEST&e=zip' && \
+RUN wget -q -O vfc-nfvo-lcm.zip 'https://nexus.onap.org/service/local/artifact/maven/redirect?r=snapshots&g=org.onap.vfc.nfvo.lcm&a=vfc-nfvo-lcm&v=LATEST&e=zip' && \
unzip vfc-nfvo-lcm.zip && \
rm -rf vfc-nfvo-lcm.zip
diff --git a/docs/platform/APIs/NSLCM_API/NSLCM_API_Specification_v0.1.rst b/docs/platform/APIs/NSLCM_API/NSLCM_API_Specification_v0.1.rst
index 7188dc7f..6ed6196a 100644
--- a/docs/platform/APIs/NSLCM_API/NSLCM_API_Specification_v0.1.rst
+++ b/docs/platform/APIs/NSLCM_API/NSLCM_API_Specification_v0.1.rst
@@ -1,1086 +1,651 @@
Network services lifecycle management northbound APIs
-==========
-
- {
- "swagger": "2.0",
-
- "info": {
-
- "version": "1.0.0",
-
- "title": "ONAP VFC Network Service Lifecycle Management API",
-
- "description": "VFC Network Service Lifecycle Management Rest API.",
-
- "contact": {
-
- "name": "ONAP VFC team",
-
- "email": "onap-discuss@lists.onap.org",
-
- "url": "https://gerrit.onap.org/r/#/admin/projects/vfc/nfvo/lcm"
-
- }
-
- },
-
- "basePath": "/api/nslcm/v1",
-
- "schemes": [
-
- "http",
- "https"
-
- ],
-
- "consumes": [
-
- "application/json"
-
- ],
- "produces": [
-
- "application/json"
-
- ],
- "paths": {
-
- "/ns": {
-
- "post": {
-
- "tags": [
-
- "ns"
-
- ],
- "summary": "ns create",
-
- "description": "ns create",
-
- "operationId": "ns_create",
-
- "parameters": [
-
- {
-
- "in": "body",
-
- "name": "NSCreateRequest",
-
- "description": "NS Instance Create Request",
-
- "required": true,
-
- "schema": {
-
- "$ref": "#/definitions/NsCreateRequest"
-
- }
-
- }
-
- ],
-
- "responses": {
-
- "200": {
-
- "description": "successful operation",
-
- "schema": {
-
- "$ref": "#/definitions/NsCreateResponse"
-
- }
-
- }
-
- }
-
- },
-
- "get": {
-
- "tags": [
-
- "ns"
-
- ],
-
- "summary": "ns get",
-
- "description": "ns get",
-
- "operationId": "ns_get",
-
- "parameters": [],
-
- "responses": {
-
- "200": {
-
- "description": "successful operation",
-
- "schema": {
-
- "$ref": "#/definitions/NsInfo"
-
- }
-
- }
-
- }
-
- }
-
- },
-
- "/ns/{nsInstanceId}/Instantiate": {
-
- "post": {
-
- "tags": [
-
- "ns"
-
- ],
-
- "summary": "ns Instantiate",
-
- "description": "ns Instantiate",
-
- "operationId": "ns_Instantiate",
-
- "parameters": [
-
- {
- "required": true,
-
- "type": "string",
-
- "description": "",
-
- "name": "nsInstanceId",
-
- "in": "path"
-
- },
- {
-
- "in": "body",
-
- "name": "NSInstantiateRequest",
-
- "description": "NS Instantiate Request Body",
-
- "required": true,
-
- "schema": {
-
- "$ref": "#/definitions/NsInstantiateRequest"
-
- }
-
- }
-
- ],
-
- "responses": {
-
- "200": {
-
- "description": "",
-
- "schema": {
-
- "$ref": "#/definitions/JobInfo"
-
- }
-
- },
-
- "201": {
-
- "description": "Invalid Request"
-
- }
-
- }
-
- }
-
- },
-
- "/ns/{nsInstanceId}/scale": {
-
- "post": {
-
- "tags": [
-
- "ns"
-
- ],
-
- "summary": "ns scale",
-
- "description": "ns scale",
-
- "operationId": "ns_scale",
-
- "parameters": [
-
- {
-
- "required": true,
-
- "type": "string",
-
- "description": "",
-
- "name": "nsInstanceId",
-
- "in": "path"
-
- },
-
- {
-
- "in": "body",
-
- "name": "ScaleNSRequest",
-
- "description": "Scale NS Request Body",
-
- "required": true,
-
- "schema": {
-
- "$ref": "#/definitions/NsScaleRequest"
-
- }
-
- }
-
- ],
-
- "responses": {
-
- "200": {
-
- "description": "",
-
- "schema": {
-
- "$ref": "#/definitions/JobInfo"
-
- }
-
- },
-
- "201": {
-
- "description": "Invalid Request"
-
- }
-
- }
-
- }
-
- },
-
- "/ns/{ns_instance_id}/heal": {
-
- "post": {
-
- "tags": [
-
- "ns"
-
- ],
-
- "summary": "ns heal",
-
- "description": "ns heal",
-
- "operationId": "ns_heal",
-
- "parameters": [
-
- {
- "required": true,
-
- "type": "string",
-
- "description": "Identifier of the NS instance.",
-
- "name": "ns_instance_id",
-
- "in": "path"
-
- },
-
- {
-
- "in": "body",
-
- "name": "healVnfData",
-
- "description": "healVnfData",
-
- "required": true,
-
- "schema": {
-
- "$ref": "#/definitions/NsHealRequest"
-
- }
-
- }
-
- ],
-
- "responses": {
-
- "202": {
-
- "description": "",
-
- "schema": {
-
- "$ref": "#/definitions/JobInfo"
-
- }
-
- },
-
- "500": {
-
- "description": "the url is invalid"
-
- }
-
- }
-
- }
-
- },
-
- "/ns/{ns_instance_id}/terminate": {
-
- "post": {
-
- "tags": [
-
- "ns"
-
- ],
-
- "summary": "ns terminate",
-
- "description": "ns terminate",
-
- "operationId": "ns_terminate",
-
- "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/JobInfo"
-
- }
-
- },
-
- "500": {
-
- "description": "the url is invalid"
-
- }
-
- }
-
- }
-
- },
- "/ns/{ns_instance_id}": {
-
- "delete": {
-
- "tags": [
-
- "ns"
-
- ],
-
- "summary": "ns delete",
-
- "description": "ns delete",
-
- "operationId": "ns_delete",
-
- "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."
-
- }
-
- }
-
- }
-
- },
-
- "/jobs/{jobId}": {
-
- "post": {
-
- "tags": [
-
- "job"
-
- ],
-
- "summary": "jobstatus",
-
- "description": "",
-
- "operationId": "jobstatus",
-
- "parameters": [
-
- {
- "required": true,
-
- "type": "string",
-
- "description": "",
-
- "name": "jobId",
-
- "in": "path"
-
- },
-
- {
-
- "in": "body",
-
- "name": "body",
-
- "description": "request param",
-
- "required": true,
-
+=====================================================
+
+{
+ "swagger": "2.0",
+ "info": {
+ "version": "1.0.0",
+ "title": "ONAP VFC Network Service Lifecycle Management API",
+ "description": "VFC Network Service Lifecycle Management Rest API.",
+ "contact": {
+ "name": "ONAP VFC team",
+ "email": "onap-discuss@lists.onap.org",
+ "url": "https://gerrit.onap.org/r/#/admin/projects/vfc/nfvo/lcm"
+ }
+ },
+ "basePath": "/api/nslcm/v1",
+ "schemes": [
+ "http",
+ "https"
+ ],
+ "consumes": [
+ "application/json"
+ ],
+ "produces": [
+ "application/json"
+ ],
+ "paths": {
+ "/ns": {
+ "post": {
+ "tags": [
+ "ns"
+ ],
+ "summary": "ns create",
+ "description": "ns create",
+ "operationId": "ns_create",
+ "parameters": [
+ {
+ "in": "body",
+ "name": "NSCreateRequest",
+ "description": "NS Instance Create Request",
+ "required": true,
+ "schema": {
+ "$ref": "#/definitions/NsCreateRequest"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "successful operation",
+ "schema": {
+ "$ref": "#/definitions/NsCreateResponse"
+ }
+ },
+ "404": {
+ "description": "URL not found"
+ }
+ }
+ },
+ "get": {
+ "tags": [
+ "ns"
+ ],
+ "summary": "ns get",
+ "description": "ns get",
+ "operationId": "ns_instantces_get",
+ "parameters": [
+ {
+ "required": true,
+ "type": "string",
+ "description": "job response message id",
+ "name": "csarId",
+ "in": "query"
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "successful operation",
+ "schema": {
+ "$ref": "#/definitions/NsInstancesInfo"
+ }
+ },
+ "404": {
+ "description": "URL not found"
+ }
+ }
+ }
+ },
+ "/ns/{nsInstanceId}/Instantiate": {
+ "post": {
+ "tags": [
+ "ns"
+ ],
+ "summary": "ns Instantiate",
+ "description": "ns Instantiate",
+ "operationId": "ns_Instantiate",
+ "parameters": [
+ {
+ "required": true,
+ "type": "string",
+ "description": "",
+ "name": "nsInstanceId",
+ "in": "path"
+ },
+ {
+ "in": "body",
+ "name": "NSInstantiateRequest",
+ "description": "NS Instantiate Request Body",
+ "required": true,
+ "schema": {
+ "$ref": "#/definitions/NsInstantiateRequest"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "",
+ "schema": {
+ "$ref": "#/definitions/JobInfo"
+ }
+ },
+ "201": {
+ "description": "Invalid Request"
+ },
+ "404": {
+ "description": "URL not found"
+ }
+ }
+ }
+ },
+ "/ns/{nsInstanceId}/scale": {
+ "post": {
+ "tags": [
+ "ns"
+ ],
+ "summary": "ns scale",
+ "description": "ns scale",
+ "operationId": "ns_scale",
+ "parameters": [
+ {
+ "required": true,
+ "type": "string",
+ "description": "",
+ "name": "nsInstanceId",
+ "in": "path"
+ },
+ {
+ "in": "body",
+ "name": "ScaleNSRequest",
+ "description": "Scale NS Request Body",
+ "required": true,
+ "schema": {
+ "$ref": "#/definitions/NsScaleRequest"
+ }
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "",
+ "schema": {
+ "$ref": "#/definitions/JobInfo"
+ }
+ },
+ "201": {
+ "description": "Invalid Request"
+ },
+ "404": {
+ "description": "URL not found"
+ }
+ }
+ }
+ },
+ "/ns/{nsInstanceId}/heal": {
+ "post": {
+ "tags": [
+ "ns"
+ ],
+ "summary": "ns heal",
+ "description": "ns heal",
+ "operationId": "ns_heal",
+ "parameters": [
+ {
+ "required": true,
+ "type": "string",
+ "description": "Identifier of the NS instance.",
+ "name": "nsInstanceId",
+ "in": "path"
+ },
+ {
+ "in": "body",
+ "name": "healVnfData",
+ "description": "healVnfData",
+ "required": true,
+ "schema": {
+ "$ref": "#/definitions/NsHealRequest"
+ }
+ }
+ ],
+ "responses": {
+ "202": {
+ "description": "",
+ "schema": {
+ "$ref": "#/definitions/JobInfo"
+ }
+ },
+ "404": {
+ "description": "URL not found"
+ },
+ "500": {
+ "description": "the url is invalid"
+ }
+ }
+ }
+ },
+ "/ns/{nsInstanceId}/terminate": {
+ "post": {
+ "tags": [
+ "ns"
+ ],
+ "summary": "ns terminate",
+ "description": "ns terminate",
+ "operationId": "ns_terminate",
+ "parameters": [
+ {
+ "required": true,
+ "type": "string",
+ "description": "Identifier of the NS instance.",
+ "name": "nsInstanceId",
+ "in": "path"
+ },
+ {
+ "in": "body",
+ "name": "NsTerminateRequest",
+ "description": "NsTerminateRequest",
+ "required": true,
+ "schema": {
+ "$ref": "#/definitions/NsTerminateRequest"
+ }
+ }
+ ],
+ "responses": {
+ "202": {
+ "description": "",
+ "schema": {
+ "$ref": "#/definitions/JobInfo"
+ }
+ },
+ "500": {
+ "description": "the url is invalid"
+ }
+ }
+ }
+ },
+ "/ns/{nsInstanceId}": {
+ "get": {
+ "tags": [
+ "ns"
+ ],
+ "summary": "ns get",
+ "description": "ns get",
+ "operationId": "ns_instance_get",
+ "parameters": [
+ {
+ "required": true,
+ "type": "string",
+ "description": "Identifier of the NS instance.",
+ "name": "nsInstanceId",
+ "in": "path"
+ }
+ ],
+ "responses": {
+ "200": {
+ "description": "successful operation",
+ "schema": {
+ "$ref": "#/definitions/NsInstanceInfo"
+ }
+ }
+ }
+ },
+ "delete": {
+ "tags": [
+ "ns"
+ ],
+ "summary": "ns delete",
+ "description": "ns delete",
+ "operationId": "ns_delete",
+ "parameters": [
+ {
+ "required": true,
+ "type": "string",
+ "description": "Identifier of the NS instance.",
+ "name": "nsInstanceId",
+ "in": "path"
+ }
+ ],
+ "responses": {
+ "204": {
+ "description": "The NS instance resource and the associated NS identifier were deleted successfully."
+ }
+ }
+ }
+ },
+ "/jobs/{jobId}": {
+ "get": {
+ "tags": [
+ "job"
+ ],
+ "summary": "jobstatus",
+ "description": "",
+ "operationId": "get_jobstatus",
+ "parameters": [
+ {
+ "required": true,
+ "type": "string",
+ "description": "job Id",
+ "name": "jobId",
+ "in": "path"
+ },
+ {
+ "required": true,
+ "type": "string",
+ "description": "job response message id",
+ "name": "responseId",
+ "in": "query"
+ }
+ ],
+ "responses": {
+ "202": {
+ "description": "",
"schema": {
-
- "$ref": "#/definitions/JobProgressRequest"
-
- }
-
- }
-
- ],
-
- "responses": {
-
- "202": {
-
- "description": ""
-
- }
-
- }
-
- }
-
- }
-
- },
-
- "definitions": {
-
- "NsCreateRequest": {
-
- "type": "object",
-
- "properties": {
-
- "context":{
-
- "type": "object",
-
- "properties": {
-
+ "$ref": "#/definitions/JobDetailInfo"
+ }
+ }
+ }
+ }
+ }
+ },
+ "definitions": {
+ "NsCreateRequest": {
+ "type": "object",
+ "properties": {
+ "context":{
+ "type": "object",
+ "properties": {
"globalCustomerId":{
-
"type": "string",
"description": "the global customer id"
-
},
-
"serviceType":{
"type": "string",
-
"description": "service type"
-
}
-
}
-
- },
-
- "csarId": {
-
- "type": "string",
-
- "description": "the NS package ID"
-
- },
-
- "nsName": {
-
- "type": "string"
-
- },
-
- "description": {
-
- "type": "string"
-
- }
-
- }
-
- },
-
- "NsCreateResponse": {
-
- "type": "object",
-
- "properties": {
-
- "nsInstanceId": {
-
- "type": "string"
-
- }
-
- }
-
- },
- "NsInstantiateRequest": {
-
- "type": "object",
-
- "properties": {
-
- "LocationConstraints": {
-
- "type": "array",
-
- "items": {
-
- "$ref": "#/definitions/LocationConstraint"
-
- }
-
- },
-
- "additionalParamForNs": {
-
- "type": "string"
-
- }
-
- }
-
- },
-
- "LocationConstraint": {
-
- "type": "object",
-
- "properties": {
-
- "vnfProfileId": {
-
- "type": "string"
-
- },
- "locationConstraints": {
-
- "type": "object",
-
- "properties": {
-
- "vimid": {
-
- "type": "string"
-
- }
-
- }
-
- }
-
- }
-
- },
-
- "NsScaleRequest": {
-
+ },
+ "csarId": {
+ "type": "string",
+ "description": "the NS package ID"
+ },
+ "nsName": {
+ "type": "string"
+ },
+ "description": {
+ "type": "string"
+ }
+ }
+ },
+ "NsCreateResponse": {
+ "type": "object",
+ "properties": {
+ "nsInstanceId": {
+ "type": "string"
+ }
+ }
+ },
+ "NsInstantiateRequest": {
+ "type": "object",
+ "properties": {
+ "LocationConstraints": {
+ "type": "array",
+ "items": {
+ "$ref": "#/definitions/LocationConstraint"
+ }
+ },
+ "additionalParamForNs": {
+ "type": "string"
+ }
+ }
+ },
+ "LocationConstraint": {
+ "type": "object",
+ "properties": {
+ "vnfProfileId": {
+ "type": "string"
+ },
+ "locationConstraints": {
+ "type": "object",
+ "properties": {
+ "vimid": {
+ "type": "string"
+ }
+ }
+ }
+ }
+ },
+ "NsScaleRequest": {
+ "type": "object",
+ "properties": {
+ "scaleType": {
+ "type": "string"
+ },
+ "scaleNsByStepsData": {
+ "$ref": "#/definitions/NsScaleByStepsData"
+ }
+ }
+ },
+ "NsScaleByStepsData": {
+ "type": "object",
+ "properties": {
+ "scalingDirection": {
+ "type": "string"
+ },
+ "aspectId": {
+ "type": "string"
+ },
+ "numberOfSteps": {
+ "type": "integer"
+ }
+ }
+ },
+ "NsHealRequest": {
+ "type": "object",
+ "properties": {
+ "vnfInstanceId": {
+ "type": "string"
+ },
+ "cause": {
+ "type": "string"
+ },
+ "additionalParams": {
+ "type": "object",
+ "properties": {
+ "action": {
+ "type": "string"
+ },
+ "actionvminfo": {
+ "type": "object",
+ "properties": {
+ "vmid": {
+ "type": "string"
+ },
+ "vmname": {
+ "type": "string"
+ }
+ }
+ }
+ }
+ }
+ }
+ },
+ "NsTerminateRequest": {
+ "type": "object",
+ "properties": {
+ "terminationType": {
+ "type": "string"
+ },
+ "gracefulTerminationTimeout": {
+ "type": "string"
+ }
+ }
+ },
+ "JobInfo": {
+ "type": "object",
+ "properties": {
+ "jobId": {
+ "type": "string"
+ }
+ }
+ },
+ "NsInstancesInfo":{
+ "type": "array",
+ "items": {
+ "$ref": "#/definitions/NsInstanceInfo"
+ }
+ },
+ "NsInstanceInfo": {
+ "type": "object",
+ "properties": {
+ "nsInstanceId": {
+ "type": "string"
+ },
+ "nsName": {
+ "type": "string"
+ },
+ "description": {
+ "type": "string"
+ },
+ "nsdId": {
+ "type": "string"
+ },
+ "vnfInfo": {
+ "type": "array",
+ "items": {
+ "$ref": "#/definitions/vnfInfo"
+ }
+ },
+ "vlInfo": {
+ "type": "array",
+ "items": {
+ "$ref": "#/definitions/vlInfo"
+ }
+ },
+ "vnffgInfo": {
+ "type": "array",
+ "items": {
+ "$ref": "#/definitions/vnffgInfo"
+ }
+ },
+ "nsState": {
+ "type": "string"
+ }
+ }
+ },
+ "vnfInfo": {
+ "type": "object",
+ "properties": {
+ "vnfInstanceId": {
+ "type": "string"
+ },
+ "vnfInstanceName": {
+ "type": "string"
+ },
+ "vnfdId": {
+ "type": "string"
+ }
+ }
+ },
+ "vlInfo": {
+ "type": "object",
+ "properties": {
+ "vlInstanceId": {
+ "type": "string"
+ },
+ "vlInstanceName": {
+ "type": "string"
+ },
+ "vldId": {
+ "type": "string"
+ },
+ "relatedCpInstanceId": {
+ "type": "array",
+ "items": {
+ "$ref": "#/definitions/cpInfo"
+ }
+ }
+ }
+ },
+ "cpInfo": {
+ "type": "object",
+ "properties": {
+ "cpInstanceId": {
+ "type": "string"
+ },
+ "cpInstanceName": {
+ "type": "string"
+ },
+ "cpdId": {
+ "type": "string"
+ }
+ }
+ },
+ "vnffgInfo": {
+ "type": "object",
+ "properties": {
+ "vnffgInstanceId": {
+ "type": "string"
+ },
+ "vnfId": {
+ "type": "string"
+ },
+ "pnfId": {
+ "type": "string"
+ },
+ "virtualLinkId": {
+ "type": "string"
+ },
+ "cpId": {
+ "type": "string"
+ },
+ "nfp": {
+ "type": "string"
+ }
+ }
+ },
+ "jobResponseInfo": {
"type": "object",
-
"properties": {
-
- "scaleType": {
-
- "type": "string"
-
+ "status": {
+ "type": "string"
+ },
+ "progress":{
+ "type": "string"
},
-
- "scaleNsByStepsData": {
-
- "$ref": "#/definitions/NsScaleByStepsData"
-
- }
-
- }
-
- },
-
- "NsScaleByStepsData": {
-
- "type": "object",
-
- "properties": {
-
- "scalingDirection": {
-
- "type": "string"
-
+ "statusDescription": {
+ "type": "string"
},
-
- "aspectId": {
-
- "type": "string"
-
+ "errorCode": {
+ "type": "string"
},
-
- "numberOfSteps": {
-
- "type": "integer"
-
- }
-
+ "responseId": {
+ "type": "string"
+ }
}
-
- },
-
- "NsHealRequest": {
-
- "type": "object",
-
- "properties": {
-
- "vnfInstanceId": {
-
- "type": "string"
-
- },
-
- "cause": {
-
- "type": "string"
-
- },
-
- "additionalParams": {
-
- "type": "object",
-
- "properties": {
-
- "action": {
-
+ },
+ "JobDetailInfo":{
+ "type": "object",
+ "properties": {
+ "jobId": {
"type": "string"
-
},
-
- "actionvminfo": {
-
- "type": "object",
-
- "properties": {
-
- "vmid": {
-
- "type": "string"
-
- },
-
- "vmname": {
-
- "type": "string"
-
- }
-
- }
-
- }
-
+ "responseDescriptor":
+ {
+ "type":"object",
+ "properties": {
+ "status": {
+ "type": "string"
+ },
+ "progress":{
+ "type": "string"
+ },
+ "statusDescription": {
+ "type": "string"
+ },
+ "errorCode": {
+ "type": "string"
+ },
+ "responseId": {
+ "type": "string"
+ },
+ "responseHistoryList": {
+ "type": "array",
+ "items": {
+ "$ref": "#/definitions/jobResponseInfo"
+ }
+ }
+ }
}
-
- }
-
- }
-
- },
-
- "NsTerminateRequest": {
-
- "type": "object",
-
- "properties": {
-
- "terminationType": {
-
- "type": "string"
-
- },
-
- "gracefulTerminationTimeout": {
-
- "type": "string"
-
- }
-
- }
-
- },
-
- "JobInfo": {
-
- "type": "object",
-
- "properties": {
-
- "jobId": {
-
- "type": "string"
-
- }
-
- }
-
- },
-
- "JobProgressRequest": {
-
- "type": "object",
-
- "properties": {
-
- "progress": {
-
- "type": "string"
-
- },
-
- "desc": {
-
- "type": "string"
-
- },
-
- "errcode": {
-
- "type": "string"
-
- }
-
- }
-
- },
-
- "NsInfo": {
-
- "type": "object",
-
- "properties": {
-
- "nsInstanceId": {
-
- "type": "string"
-
- },
-
- "nsName": {
-
- "type": "string"
-
- },
-
- "description": {
-
- "type": "string"
-
- },
-
- "nsdId": {
-
- "type": "string"
-
- },
-
- "vnfInfo": {
-
- "type": "array",
-
- "items": {
-
- "$ref": "#/definitions/vnfInfo"
-
- }
-
- },
-
- "vlInfo": {
-
- "type": "array",
-
- "items": {
-
- "$ref": "#/definitions/vlInfo"
-
- }
-
- },
-
- "vnffgInfo": {
-
- "type": "array",
-
- "items": {
-
- "$ref": "#/definitions/vnffgInfo"
-
- }
-
- },
-
- "nsState": {
-
- "type": "string"
-
- }
-
- }
-
- },
-
- "vnfInfo": {
-
- "type": "object",
-
- "properties": {
-
- "vnfInstanceId": {
-
- "type": "string"
-
- },
-
- "vnfInstanceName": {
-
- "type": "string"
-
- },
-
- "vnfdId": {
-
- "type": "string"
-
- }
-
- }
-
- },
-
- "vlInfo": {
-
- "type": "object",
-
- "properties": {
-
- "vlInstanceId": {
-
- "type": "string"
-
- },
-
- "vlInstanceName": {
-
- "type": "string"
-
- },
-
- "vldId": {
-
- "type": "string"
-
- },
-
- "relatedCpInstanceId": {
-
- "type": "array",
-
- "items": {
-
- "$ref": "#/definitions/cpInfo"
-
- }
-
- }
-
- }
-
- },
-
- "cpInfo": {
-
- "type": "object",
-
- "properties": {
-
- "cpInstanceId": {
-
- "type": "string"
-
- },
-
- "cpInstanceName": {
-
- "type": "string"
-
- },
-
- "cpdId": {
-
- "type": "string"
-
- }
-
- }
-
- },
- "vnffgInfo": {
-
- "type": "object",
-
- "properties": {
-
- "vnffgInstanceId": {
-
- "type": "string"
-
- },
-
- "vnfId": {
-
- "type": "string"
-
- },
- "pnfId": {
-
- "type": "string"
-
- },
-
- "virtualLinkId": {
-
- "type": "string"
-
- },
-
- "cpId": {
-
- "type": "string"
-
- },
-
- "nfp": {
-
- "type": "string"
-
- }
-
- }
-
- }
-
- }
-
- } \ No newline at end of file
+ }
+ }
+ }
+} \ No newline at end of file
diff --git a/docs/platform/APIs/VNFLCM_API/VNFLCM_API.rst b/docs/platform/APIs/VNFLCM_API/VNFLCM_API.rst
index 8d9cff6a..c5c63c85 100644
--- a/docs/platform/APIs/VNFLCM_API/VNFLCM_API.rst
+++ b/docs/platform/APIs/VNFLCM_API/VNFLCM_API.rst
@@ -8,8 +8,9 @@
**1 Scope**
=============
- The scope of the present document is to describe the GVNFM exposed
- API specification over Or-Vnfm reference point and Ve-Vnfm-vnf reference point.
+The scope of the present document is to describe the GVNFM exposed API specification over Or-Vnfm reference point and Ve-Vnfm-vnf reference point.
+Some content has been updated, about the API Swagger definition, you can find here 'GVNFM_LCM_APIs<https://gerrit.onap.org/r/gitweb?p=vfc/gvnfm/vnflcm.git;a=blob;f=lcm/lcm/swagger/swagger.json;h=f098d282927d3535f5e9e6950f26b9171e04d30c;hb=HEAD>'.
+
**2 Terms, Definitions and Abbreviations**
===========================================
@@ -1681,4 +1682,4 @@ Table 2-1 abbreviations
.. |image0| image:: VNFM_API.png
:width: 5.07047in
- :height: 5.6320 \ No newline at end of file
+ :height: 5.6320in \ No newline at end of file
diff --git a/docs/platform/APIs/VNFMDriver_API/VNFM_Driver_API.rst b/docs/platform/APIs/VNFMDriver_API/VNFM_Driver_API.rst
index c289626d..a88e29e0 100644
--- a/docs/platform/APIs/VNFMDriver_API/VNFM_Driver_API.rst
+++ b/docs/platform/APIs/VNFMDriver_API/VNFM_Driver_API.rst
@@ -8,6 +8,8 @@
**1. Scope**
==============
The scope of the present document is to describe the VNFM driver integrated related API specification.
+Some content has been updated, about the API Swagger definition, you can find here 'VNFM driver development related API<https://gerrit.onap.org/r/gitweb?p=vfc/nfvo/lcm.git;a=blob;f=lcm/swagger/vfc.vnfdriver.swagger.json;h=fc35adbdc75df1307ca2c43a11bfb472da2a27c6;hb=HEAD>'
+
**2. Terms, Definitions and Abbreviations**
=============================================
diff --git a/docs/platform/APIs/index.rst b/docs/platform/APIs/index.rst
index c6f561be..816bad25 100644
--- a/docs/platform/APIs/index.rst
+++ b/docs/platform/APIs/index.rst
@@ -3,12 +3,12 @@
VF-C Offered APIs
-=================
+==================
List VF-C APIs offered.
VFC Northbound API
-----------
+------------------
Network services lifecycle management APIs
@@ -20,7 +20,7 @@ Network services lifecycle management APIs
VNFM Integration APIs
----------------
+---------------------
VNFM Driver Integration Related APIs
@@ -32,7 +32,7 @@ VNFM Driver Integration Related APIs
GVNFM Northbound & Southbound APIs
------------
+----------------------------------
GVNFM Northbound & Southbound APIs for VNF Integration
diff --git a/docs/platform/Auto-healing.png b/docs/platform/Auto-healing.png
new file mode 100644
index 00000000..6ebb8910
--- /dev/null
+++ b/docs/platform/Auto-healing.png
Binary files differ
diff --git a/docs/platform/Instantiation.png b/docs/platform/Instantiation.png
new file mode 100644
index 00000000..b26347ca
--- /dev/null
+++ b/docs/platform/Instantiation.png
Binary files differ
diff --git a/docs/platform/Termination.png b/docs/platform/Termination.png
new file mode 100644
index 00000000..311d78a4
--- /dev/null
+++ b/docs/platform/Termination.png
Binary files differ
diff --git a/docs/platform/architecture.rst b/docs/platform/architecture.rst
index dc7ef09b..ca015792 100644
--- a/docs/platform/architecture.rst
+++ b/docs/platform/architecture.rst
@@ -4,22 +4,22 @@
VF-C Architecture
-----------------
-Following is the VF-C architecture.
+VF-C High Level Architecture.
|image0|
.. |image0| image:: vfc-arc.png
:width: 5.97047in
- :height: 5.63208in
+ :height: 4.63208in
-
-VF-C as one controller in ONAP includes two components NFV-O and GVNFM.
+As you can see in this picture, VF-C has many dependencies with other projects, such as SO, Policy, A&AI, SDC, DCAE, Multi-cloud and so on.
+
+* NFVO provides north bound interface to SO to take part in fulfilling the orchestration and operation of end2end service.And provides standard south bound interface to VNFMs.
-For NFV-O, it provides north bound interface to SO to take part in fulfilling the orchestration and operation of end2end service.and provides standard south bound interface to VNFMs.
+* GVNFM provides LCM for VNFs which do not require a vendor VNFM and works with NFV-O component to take part in fulfilling the LCM of NS.
-For GVNFM, it provides LCM for VNFs which do not require a vendor VNFM and works with NFV-O component to take part in fulfilling the LCM of NS.
+* VF-C provides VNFM driver interfaces, vendor can implement these integrates to integrate with VF-C. Now, VF-C has integrated with three vendor VNFM, including ZTE, Huawe, Nokia.
-In addition, VF-C provides interface to Policy and works with DCAE for Close Loop Automation.
+* In addition, VF-C also provides interface to Policy and works with DCAE for Close Loop Automation.
-As you can see in this picture,VF-C has many dependencies with other projects,such as SO,Policy,A&AI,SDC,DCAE,Multi-cloud and so on. \ No newline at end of file
diff --git a/docs/platform/consumedapis.rst b/docs/platform/consumedapis.rst
index 2aef466e..08439551 100644
--- a/docs/platform/consumedapis.rst
+++ b/docs/platform/consumedapis.rst
@@ -10,6 +10,7 @@ References to APIs offered by other components
- DCAE: Use DCAE Ves collector API to report FCAPS data to DCAE
- MSB: Use MSB to register and find microservice
- Modeling: Use nfvparser API to parse tosca template
+ - Multicloud: Use Multicloud API to CRUD virtual resource
diff --git a/docs/platform/delivery.rst b/docs/platform/delivery.rst
index 13d1e0f8..5f717146 100644
--- a/docs/platform/delivery.rst
+++ b/docs/platform/delivery.rst
@@ -6,23 +6,21 @@ VF-C includes the following components in R1.
.. |image0| image:: components.png
:width: 5.97047in
- :height: 5.63208in
+ :height: 4.63208in
VF-C includes several components in ONAP R1.
-Catalog is used to store the package distributed by SDC, it is a runtime catalog.
-
-Workflow include two micro service, one is workflow manage service and the other is workflow-activiti engine service, this two service will onboard workflow to workflow engine and parse workflow.
+* Catalog is used to store the package distributed by SDC, it is a runtime catalog.
+* Workflow include two micro service, one is workflow manage service and the other is workflow-activiti engine service, this two service will onboard workflow to workflow engine and parse workflow.
-For NS lifecycle manager,it mainly completes the NS lifecycle management,such as NS Instantiation/termination and auto-healing.
+* For NS lifecycle manager,it mainly completes the NS lifecycle management,such as NS Instantiation/termination and auto-healing.
-For Resource manager, it will communicate with NS lifecycle manager to update instance data to A&AI.
+* For Resource manager, it will communicate with NS lifecycle manager to update instance data to A&AI.
-In VF-C southbound, it includes Gvnfmdriver and SVNFM driver which will interact with GVNFM and Vendor VNFM respectively to execute VNF lifecycle management,
-VF-C provides vnfm driver northbound api,then Vendor can implement this APIs to integrate with VF-C.
+* In VF-C southbound, it includes Gvnfmdriver and SVNFM driver which will interact with GVNFM and Vendor VNFM respectively to execute VNF lifecycle management,VF-C provides vnfm driver northbound api,then Vendor can implement this APIs to integrate with VF-C.
-For the EMS driver,it can collect VNF lay’s Fcaps data from Vendor EMS, and then translate and put these data to DCAE Vescollector
+* For the EMS driver,it can collect VNF lay’s Fcaps data from Vendor EMS, and then translate and put these data to DCAE Vescollector
For the Amsterdam release, VF-C includes the following components:
@@ -44,4 +42,30 @@ GVNFM
- vfc-gvnfm-vnfres
Workflow
- workflow-engine-mgr-service
- - activiti-extension \ No newline at end of file
+ - activiti-extension
+
+VF-C support VolTE use case in R1 and R2, following are the vVoLTE releated Workflow in VF-C.
+
+* VoLTE Use Case Instantiation In VF-C
+
+|image1|
+
+.. |image1| image:: Instantiation.png
+ :width: 5.97047in
+ :height: 5.63208in
+
+* VoLTE Use Case Termination in VF-C
+
+|image2|
+
+.. |image2| image:: Termination.png
+ :width: 5.97047in
+ :height: 5.63208in
+
+* VoLTE Use Case Auto-healing in VF-C
+
+|image3|
+
+.. |image3| image:: Auto-healing.png
+ :width: 5.97047in
+ :height: 5.63208in \ No newline at end of file
diff --git a/docs/platform/index.rst b/docs/platform/index.rst
index 12fa0be0..364a4c94 100644
--- a/docs/platform/index.rst
+++ b/docs/platform/index.rst
@@ -15,6 +15,30 @@ As part of the integration between OpenECOMP and OPEN-O, VF-C leverages ETSI NFV
* support microservice architecture and model driven resource orchestration and management
+|image0|
+
+.. |image0| image:: vfc-component.png
+ :width: 3.97047in
+ :height: 2.63208in
+
+VF-C as one controller in ONAP includes two components NFV-O and GVNFM.
+
+* NFVO component
+
+ * compliant with ETSI NFV MANO architecture and information model,
+ * providing resource orchestration and full life cycle management and FCAPS for NS,
+ * providing standard south bound interface to VNFMs,
+ * providing north bound interface to SO, to take part in fulfilling the orchestraion and operation of end2end service,
+ * providing interface and work with DCAE and Policy for Close Loop Automation.
+
+* GVNFM component
+
+ * compliant with ETSI NFV MANO architecture and information model
+ * providing full life cycle management and FCAPS for VNFs which do not require a vendor VNFM,
+ * providing interface and work with NFV-O component, to take part in fulfiiling the LCM and FCAPS management of NS,
+ * providing interface and work with DCAE and Policy for Close Loop Automation.
+
+
.. toctree::
:maxdepth: 1
diff --git a/docs/platform/vfc-component.png b/docs/platform/vfc-component.png
new file mode 100644
index 00000000..8fbb83ca
--- /dev/null
+++ b/docs/platform/vfc-component.png
Binary files differ
diff --git a/docs/release-notes.rst.bak b/docs/release-notes.rst.bak
deleted file mode 100644
index 79cf95d4..00000000
--- a/docs/release-notes.rst.bak
+++ /dev/null
@@ -1,77 +0,0 @@
-.. This work is licensed under a Creative Commons Attribution 4.0 International License.
-.. http://creativecommons.org/licenses/by/4.0
-
-
-VF-C Release Notes
-==================
-
-.. note::
- * This Release Notes must be updated each time the team decides to Release new artifacts.
- * The scope of this Release Notes is for this particular component. In other words, each ONAP component has its Release Notes.
- * This Release Notes is cumulative, the most recently Released artifact is made visible in the top of this Release Notes.
- * Except the date and the version number, all the other sections are optional but there must be at least one section describing the purpose of this new release.
- * This note must be removed after content has been added.
-
-VF-C includes two main component:NFV-O and GVNFM, can implement life cycle management and FCAPS of VNF and NS. VF-C takes part in end2end service orchestration and close loop automatiion by working with SO,DCAE and Policy.
-VF-C also provides standard south bound interface to VNFMs and can integration with multi vendor VNFMs via drivers.
-
-
-
-Version: 1.0.0
---------------
-
-
-:Release Date: 2017-11-16
-
-
-
-**New Features**
-
- - NS lifecycle management, including NS instance creation,termination and healing
- - VNF lifecycle management, including VNF nstance creation,termination and healing
- - VNF FCAPS, collecting FCAPS data from vendor EMS
- - VNFM Integration, integration with specific VNFMs of vendors to deploy commercial VNFs
- - VNF Integration, integration with VNF via GVNFM
-
-released components:
-
-NFVO
- - vfc-nfvo-lcm
- - vfc-nfvo-catalog
- - vfc-nfvo-resmgr
- - vfc-nfvo-driver-emsdriver
- - vfc-nfvo-driver-gvnfm-gvnfmadapter
- - vfc-nfvo-driver-gvnfm-jujudriver
- - vfc-nfvo-driver-svnfm-ztedriver
- - vfc-nfvo-driver-svnfm-huaweidriver
- - vfc-nfvo-driver-svnfm-nokiadriver
- - vfc-nfvo-driver-sfc-ztesfcdriver
-GVNFM
- - vfc-gvnfm-vnflcm
- - vfc-gvnfm-vnfmgr
- - vfc-gvnfm-vnfres
-Workflow
- - workflow-engine-mgr-service
- - activiti-extension
-
-**Bug Fixes**
-
-This is the initial release
-**Known Issues**
-
-None
-
-**Security Issues**
-
-None
-**Upgrade Notes**
-
-This is the initial release
-**Deprecation Notes**
-
-This is the initial release
-**Other**
-
-===========
-
-End of Release Notes
diff --git a/lcm/__init__.py b/lcm/__init__.py
index 5580cc3d..a1f872b9 100644
--- a/lcm/__init__.py
+++ b/lcm/__init__.py
@@ -11,3 +11,6 @@
# 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 pymysql
+
+pymysql.install_as_MySQLdb()
diff --git a/lcm/jobs/serializers.py b/lcm/jobs/serializers.py
new file mode 100644
index 00000000..61fa2dda
--- /dev/null
+++ b/lcm/jobs/serializers.py
@@ -0,0 +1,48 @@
+# Copyright 2018 ZTE Corporation.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+from rest_framework import serializers
+
+
+class JobHistorySerializer(serializers.Serializer):
+ status = serializers.CharField(help_text="Status of job", required=True)
+ progress = serializers.CharField(help_text="Progress of job", required=True)
+ statusDescription = serializers.CharField(help_text="Description of job", required=False, allow_null=True)
+ errorCode = serializers.CharField(help_text="Error code of job", required=False, allow_null=True)
+ responseId = serializers.CharField(help_text="Response index of job", required=True)
+
+
+class JobDescriptorSerializer(serializers.Serializer):
+ status = serializers.CharField(help_text="Status of job", required=True)
+ progress = serializers.CharField(help_text="Progress of job", required=True)
+ statusDescription = serializers.CharField(help_text="Description of job", required=False, allow_null=True)
+ errorCode = serializers.CharField(help_text="Error code of job", required=False, allow_null=True)
+ responseId = serializers.CharField(help_text="Response index of job", required=True)
+ responseHistoryList = JobHistorySerializer(help_text="History of job", many=True)
+
+
+class JobQueryRespSerializer(serializers.Serializer):
+ jobId = serializers.CharField(help_text="UUID of job", required=True)
+ responseDescriptor = JobDescriptorSerializer(help_text="Descriptor of job", required=False)
+
+
+class JobUpdReqSerializer(serializers.Serializer):
+ progress = serializers.CharField(help_text="Progress of job", required=True)
+ desc = serializers.CharField(help_text="Desc of job", required=False)
+ errcode = serializers.CharField(help_text="Error code of job", required=False)
+
+
+class JobUpdRespSerializer(serializers.Serializer):
+ result = serializers.CharField(help_text="Result of job update", required=True)
+ msg = serializers.CharField(help_text="Detail of job update", required=False)
diff --git a/lcm/jobs/tests/tests.py b/lcm/jobs/tests/tests.py
index 7b97c724..84ae29f9 100644
--- a/lcm/jobs/tests/tests.py
+++ b/lcm/jobs/tests/tests.py
@@ -27,14 +27,17 @@ class JobsViewTest(TestCase):
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()
+ JobStatusModel(indexid=1, jobid=self.job_id, status='inst', progress=20, descp='inst', errcode="0").save()
response = self.client.get("/api/nslcm/v1/jobs/%s" % self.job_id)
- self.failUnlessEqual(status.HTTP_200_OK, response.status_code)
+ self.assertEqual(status.HTTP_200_OK, response.status_code, response.data)
+ self.assertIn('jobId', response.data)
+ self.assertIn('responseDescriptor', response.data)
def test_non_exiting_job(self):
job_id = 'test_new_job_id'
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()
+ JobStatusModel(indexid=1, jobid=self.job_id, status='inst', progress=20, descp='inst', errcode="0").save()
response = self.client.get("/api/nslcm/v1/jobs/%s" % job_id)
+ self.assertEqual(status.HTTP_200_OK, response.status_code)
self.assertIn('jobId', response.data)
self.assertNotIn('responseDescriptor', response.data)
diff --git a/lcm/jobs/urls.py b/lcm/jobs/urls.py
index 6919d05f..3ddfc8a9 100644
--- a/lcm/jobs/urls.py
+++ b/lcm/jobs/urls.py
@@ -11,13 +11,13 @@
# 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 django.conf.urls import url
from rest_framework.urlpatterns import format_suffix_patterns
from lcm.jobs.views import JobView
-urlpatterns = patterns('',
- url(r'^api/nslcm/v1/jobs/(?P<job_id>[0-9a-zA-Z_-]+)$', JobView.as_view()),
- )
+urlpatterns = [
+ url(r'^api/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
index acbb5fe9..7439b630 100644
--- a/lcm/jobs/views.py
+++ b/lcm/jobs/views.py
@@ -12,34 +12,87 @@
# See the License for the specific language governing permissions and
# limitations under the License.
import logging
+import traceback
+from drf_yasg import openapi
from rest_framework.response import Response
from rest_framework.views import APIView
+from rest_framework import status
+from drf_yasg.utils import swagger_auto_schema
from lcm.jobs.job_get import GetJobInfoService
from lcm.pub.utils.jobutil import JobUtil
from lcm.pub.utils.values import ignore_case_get
+from lcm.jobs.serializers import JobUpdReqSerializer, JobUpdRespSerializer
+from lcm.jobs.serializers import JobQueryRespSerializer
+from lcm.pub.exceptions import NSLCMException
logger = logging.getLogger(__name__)
class JobView(APIView):
+ @swagger_auto_schema(
+ manual_parameters=[
+ openapi.Parameter('responseId',
+ openapi.IN_QUERY,
+ "responseId",
+ type=openapi.TYPE_INTEGER
+ ),
+ ],
+ responses={
+ status.HTTP_200_OK: JobQueryRespSerializer(),
+ status.HTTP_500_INTERNAL_SERVER_ERROR: "Inner error"
+ }
+ )
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)
+ try:
+ response_id = ignore_case_get(request.META, 'responseId')
+ ret = GetJobInfoService(job_id, response_id).do_biz()
+ resp_serializer = JobQueryRespSerializer(data=ret)
+ if not resp_serializer.is_valid():
+ raise NSLCMException(resp_serializer.errors)
+ return Response(data=resp_serializer.data, status=status.HTTP_200_OK)
+ except Exception as e:
+ logger.error(traceback.format_exc())
+ return Response(data={'error': e.message}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
+ @swagger_auto_schema(
+ request_body=JobUpdReqSerializer(),
+ responses={
+ status.HTTP_202_ACCEPTED: JobUpdRespSerializer()
+ }
+ )
def post(self, request, job_id):
try:
logger.debug("Enter JobView:post, %s, %s ", job_id, request.data)
+
+ req_serializer = JobUpdReqSerializer(data=request.data)
+ if not req_serializer.is_valid():
+ raise NSLCMException(req_serializer.errors)
+
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'})
+ if not jobs:
+ raise NSLCMException("Job(%s) does not exist.")
+
+ if jobs[-1].errcode != '255':
+ 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)
+
+ resp_serializer = JobUpdRespSerializer(data={'result': 'ok'})
+ if not resp_serializer.is_valid():
+ raise NSLCMException(req_serializer.errors)
+
+ return Response(data=resp_serializer.data, status=status.HTTP_202_ACCEPTED)
except Exception as e:
- return Response(data={'result': 'error', 'msg': e.message})
+ resp_serializer = JobUpdRespSerializer(data={
+ 'result': 'error',
+ 'msg': e.message})
+ if not resp_serializer.is_valid():
+ logger.error(resp_serializer.errors)
+ return Response(data={
+ 'result': 'error',
+ 'msg': resp_serializer.errors}, status=status.HTTP_202_ACCEPTED)
+ return Response(data=resp_serializer.data, status=status.HTTP_202_ACCEPTED)
diff --git a/lcm/log.yml b/lcm/log.yml
new file mode 100644
index 00000000..4ae7ab16
--- /dev/null
+++ b/lcm/log.yml
@@ -0,0 +1,50 @@
+version: 1
+disable_existing_loggers: False
+
+loggers:
+ nslcm:
+ handlers: [nslcmlocal_handler, nslcm_handler]
+ level: "DEBUG"
+ propagate: False
+ django:
+ handlers: [django_handler]
+ level: "DEBUG"
+ propagate: False
+handlers:
+ nslcmlocal_handler:
+ level: "DEBUG"
+ class:
+ "logging.handlers.RotatingFileHandler"
+ filename: "logs/runtime_nslcm.log"
+ formatter:
+ "standard"
+ maxBytes: 52428800
+ backupCount: 10
+ nslcm_handler:
+ level: "DEBUG"
+ class:
+ "logging.handlers.RotatingFileHandler"
+ filename: "/var/log/onap/vfc/nslcm/runtime_nslcm.log"
+ formatter:
+ "mdcFormat"
+ maxBytes: 52428800
+ backupCount: 10
+ django_handler:
+ level: "DEBUG"
+ class:
+ "logging.handlers.RotatingFileHandler"
+ filename: "logs/django.log"
+ formatter:
+ "standard"
+ maxBytes: 52428800
+ backupCount: 10
+formatters:
+ standard:
+ format:
+ "%(asctime)s:[%(name)s]:[%(filename)s]-[%(lineno)d] [%(levelname)s]:%(message)s"
+ mdcFormat:
+ format:
+ "%(asctime)s|||||%(name)s||%(thread)s||%(funcName)s||%(levelname)s||%(message)s||||%(mdc)s \t"
+ mdcfmt: "{requestID} {invocationID} {serviceName} {serviceIP}"
+ datefmt: "%Y-%m-%d %H:%M:%S"
+ (): onaplogging.mdcformatter.MDCFormatter
diff --git a/lcm/middleware.py b/lcm/middleware.py
new file mode 100644
index 00000000..7bf6868f
--- /dev/null
+++ b/lcm/middleware.py
@@ -0,0 +1,60 @@
+# Copyright (c) 2017-2018 ZTE, Inc.
+#
+# 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.
+
+import uuid
+from onaplogging.mdcContext import MDC
+
+from lcm.pub.config.config import FORWARDED_FOR_FIELDS, SERVICE_NAME
+
+
+class LogContextMiddleware(object):
+ # the last IP behind multiple proxies, if no exist proxies
+ # get local host ip.
+ def _getLastIp(self, request):
+
+ ip = ""
+ try:
+ for field in FORWARDED_FOR_FIELDS:
+ if field in request.META:
+ if ',' in request.META[field]:
+ parts = request.META[field].split(',')
+ ip = parts[-1].strip().split(":")[0]
+ else:
+ ip = request.META[field].split(":")[0]
+
+ if ip == "":
+ ip = request.META.get("HTTP_HOST").split(":")[0]
+
+ except Exception:
+ pass
+
+ return ip
+
+ def process_request(self, request):
+ # Fetch TRANSACTIONID Id and pass to plugin server
+ ReqeustID = request.META.get("HTTP_X_TRANSACTIONID", None)
+ if ReqeustID is None:
+ ReqeustID = uuid.uuid3(uuid.NAMESPACE_URL, SERVICE_NAME)
+ request.META["HTTP_X_TRANSACTIONID"] = ReqeustID
+ MDC.put("requestID", ReqeustID)
+ # generate the unique id
+ InovocationID = uuid.uuid3(uuid.NAMESPACE_DNS, SERVICE_NAME)
+ MDC.put("invocationID", InovocationID)
+ MDC.put("serviceName", SERVICE_NAME)
+ # access ip
+ MDC.put("serviceIP", self._getLastIp(request))
+
+ return None
+
+ def process_response(self, request, response):
+ MDC.clear()
+ return response
diff --git a/lcm/ns/data/scalemapping.json b/lcm/ns/data/scalemapping.json
index 410332c9..07e74b6e 100644
--- a/lcm/ns/data/scalemapping.json
+++ b/lcm/ns/data/scalemapping.json
@@ -1,55 +1,55 @@
{
"scale_options": [
{
- "ns_instanceId":"23",
+ "nsd_id":"23",
"ns_scale_aspect": "TIC_EDGE_IMS",
- "ns_scale_info_list": [
+ "ns_scale_info": [
{
"step": "1",
- "vnf_scale_list":[
+ "vnf_scale_info":[
{
- "vnfInstanceId":"nf_zte_cscf",
- "vnf_scaleAspectId": "gpu",
+ "vnfd_id":"nf_zte_cscf",
+ "vnf_scaleAspectId": "gsu",
"numberOfSteps": "1"
},
{
- "vnfInstanceId":"nf_zte_hss",
+ "vnfd_id":"nf_zte_hss",
"vnf_scaleAspectId": "gpu",
- "numberOfSteps": "1"
+ "numberOfSteps": "3"
}
]
},
{
"step": "2",
- "vnf_scale_list":[
+ "vnf_scale_info":[
{
- "vnfInstanceId":"nf_zte_cscf",
+ "vnfd_id":"nf_zte_cscf",
"vnf_scaleAspectId": "mpu",
- "numberOfSteps": "1"
+ "numberOfSteps": "2"
},
{
- "vnfInstanceId":"nf_zte_hss",
+ "vnfd_id":"nf_zte_hss",
"vnf_scaleAspectId": "mpu",
- "numberOfSteps": "1"
+ "numberOfSteps": "4"
}
]
}
]
},
{
- "ns_instanceId":"23",
+ "nsd_id":"23",
"ns_scale_aspect": "TIC_EDGE_HW",
- "ns_scale_info_list": [
+ "ns_scale_info": [
{
"step": "4",
- "vnf_scale_list":[
+ "vnf_scale_info":[
{
- "vnfInstanceId":"nf_hw_cscf",
- "vnf_scaleAspectId": "gpu",
+ "vnfd_id":"nf_hw_cscf",
+ "vnf_scaleAspectId": "gsu",
"numberOfSteps": "1"
},
{
- "vnfInstanceId":"nf_hw_hss",
+ "vnfd_id":"nf_hw_hss",
"vnf_scaleAspectId": "gpu",
"numberOfSteps": "1"
}
@@ -57,14 +57,14 @@
},
{
"step": "6",
- "vnf_scale_list":[
+ "vnf_scale_info":[
{
- "vnfInstanceId":"nf_HW_cscf",
+ "vnfd_id":"nf_HW_cscf",
"vnf_scaleAspectId": "gpu",
"numberOfSteps": "1"
},
{
- "vnfInstanceId":"nf_HW_hss",
+ "vnfd_id":"nf_HW_hss",
"vnf_scaleAspectId": "gpu",
"numberOfSteps": "1"
}
@@ -73,19 +73,19 @@
]
},
{
- "ns_instanceId":"235",
+ "nsd_id":"235",
"ns_scale_aspect": "TIC_EDGE_HW",
- "ns_scale_info_list": [
+ "ns_scale_info": [
{
"step": "4",
- "vnf_scale_list":[
+ "vnf_scale_info":[
{
- "vnfInstanceId":"nf_hw_cscf",
+ "vnfd_id":"nf_hw_cscf",
"vnf_scaleAspectId": "gpu",
"numberOfSteps": "123"
},
{
- "vnfInstanceId":"nf_hw_hss",
+ "vnfd_id":"nf_hw_hss",
"vnf_scaleAspectId": "gpu",
"numberOfSteps": "456"
}
@@ -93,14 +93,14 @@
},
{
"step": "6",
- "vnf_scale_list":[
+ "vnf_scale_info":[
{
- "vnfInstanceId":"nf_HW_cscf",
+ "vnfd_id":"nf_HW_cscf",
"vnf_scaleAspectId": "gpu",
"numberOfSteps": "1"
},
{
- "vnfInstanceId":"nf_HW_hss",
+ "vnfd_id":"nf_HW_hss",
"vnf_scaleAspectId": "gpu",
"numberOfSteps": "1"
}
diff --git a/lcm/ns/ns_manual_scale.py b/lcm/ns/ns_manual_scale.py
index 4fcfbbe3..71897aee 100644
--- a/lcm/ns/ns_manual_scale.py
+++ b/lcm/ns/ns_manual_scale.py
@@ -23,7 +23,7 @@ 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
+from lcm.pub.utils.scaleaspect import get_scale_vnf_data_info_list
JOB_ERROR = 255
SCALE_TYPE = ("SCALE_NS", "SCALE_VNF")
@@ -45,7 +45,8 @@ class NSManualScaleService(threading.Thread):
self.do_biz()
except NSLCMException as e:
JobUtil.add_job_status(self.job_id, JOB_ERROR, e.message)
- except:
+ except Exception as ex:
+ logger.error(ex.message)
logger.error(traceback.format_exc())
JobUtil.add_job_status(self.job_id, JOB_ERROR, 'ns scale fail')
finally:
@@ -54,35 +55,45 @@ class NSManualScaleService(threading.Thread):
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.check_and_set_params()
self.do_vnfs_scale()
self.update_job(100, desc='ns scale success')
- def get_and_check_params(self):
+ def check_and_set_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.')
+ 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)
+ self.scale_vnf_data = get_scale_vnf_data_info_list(
+ self.scale_ns_data, self.ns_instance_id)
logger.debug('scale_vnf_data = %s' % self.scale_vnf_data)
# Get data if SCALE_VNF
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')
+ 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])
+ 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'))
+ 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')
@@ -101,7 +112,10 @@ class NSManualScaleService(threading.Thread):
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)
+ 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
@@ -125,4 +139,6 @@ class NSManualScaleService(threading.Thread):
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)
+ 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
index 57ba659b..5b93f58d 100644
--- a/lcm/ns/ns_terminate.py
+++ b/lcm/ns/ns_terminate.py
@@ -53,7 +53,8 @@ class TerminateNsService(threading.Thread):
JobUtil.add_job_status(self.job_id, 100, "ns terminate ends.", '')
except NSLCMException as e:
JobUtil.add_job_status(self.job_id, JOB_ERROR, e.message)
- except:
+ except Exception as ex:
+ logger.error(ex.message)
logger.error(traceback.format_exc())
JobUtil.add_job_status(self.job_id, JOB_ERROR, "ns terminate fail.")
diff --git a/lcm/ns/serializers.py b/lcm/ns/serializers.py
new file mode 100644
index 00000000..a3b14127
--- /dev/null
+++ b/lcm/ns/serializers.py
@@ -0,0 +1,132 @@
+# Copyright 2018 ZTE Corporation.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+from rest_framework import serializers
+
+
+class ContextSerializer(serializers.Serializer):
+ globalCustomerId = serializers.CharField(help_text="Global customer ID", required=False, allow_null=True)
+ serviceType = serializers.CharField(help_text="Service type", required=False, allow_null=True)
+
+
+class CreateNsReqSerializer(serializers.Serializer):
+ csarId = serializers.CharField(help_text="Package ID of NS", required=False, allow_null=True)
+ nsName = serializers.CharField(help_text="Name of NS", required=False, allow_null=True)
+ description = serializers.CharField(help_text="Description of NS", required=False, allow_null=True)
+ context = ContextSerializer(help_text="Context of NS", required=False)
+
+
+class CreateNsRespSerializer(serializers.Serializer):
+ nsInstanceId = serializers.CharField(help_text="ID of NS instance", required=True)
+
+
+class VnfInstSerializer(serializers.Serializer):
+ vnfInstanceId = serializers.CharField(help_text="ID of VNF instance", required=True)
+ vnfInstanceName = serializers.CharField(help_text="Name of VNF instance", required=False, allow_null=True)
+ vnfdId = serializers.CharField(help_text="ID of VNFD", required=False, allow_null=True)
+
+
+class CpInstInfoSerializer(serializers.Serializer):
+ cpInstanceId = serializers.CharField(help_text="ID of CP instance", required=True)
+ cpInstanceName = serializers.CharField(help_text="Name of CP instance", required=False, allow_null=True)
+ cpdId = serializers.CharField(help_text="ID of CPD", required=False, allow_null=True)
+
+
+class VlInstSerializer(serializers.Serializer):
+ vlInstanceId = serializers.CharField(help_text="ID of VL instance", required=True)
+ vlInstanceName = serializers.CharField(help_text="Name of VL instance", required=False, allow_null=True)
+ vldId = serializers.CharField(help_text="ID of VLD", required=False, allow_null=True)
+ relatedCpInstanceId = CpInstInfoSerializer(help_text="Related CP instances", many=True)
+
+
+class VnffgInstSerializer(serializers.Serializer):
+ vnffgInstanceId = serializers.CharField(help_text="ID of VNFFG instance", required=True)
+ vnfdId = serializers.CharField(help_text="ID of VNFD", required=False, allow_null=True)
+ pnfId = serializers.CharField(help_text="ID of PNF", required=False, allow_null=True)
+ virtualLinkId = serializers.CharField(help_text="ID of virtual link", required=False, allow_null=True)
+ cpdId = serializers.CharField(help_text="ID of CPD", required=False, allow_null=True)
+ nfp = serializers.CharField(help_text="nfp", required=False, allow_null=True)
+
+
+class QueryNsRespSerializer(serializers.Serializer):
+ nsInstanceId = serializers.CharField(help_text="ID of NS instance", required=True)
+ nsName = serializers.CharField(help_text="Name of NS instance", required=False, allow_null=True)
+ description = serializers.CharField(help_text="Description of NS instance", required=False, allow_null=True)
+ nsdId = serializers.CharField(help_text="ID of NSD", required=True)
+ vnfInfo = VnfInstSerializer(help_text="VNF instances", many=True, required=False, allow_null=True)
+ vlInfo = VlInstSerializer(help_text="VL instances", many=True, required=False, allow_null=True)
+ vnffgInfo = VnffgInstSerializer(help_text="VNFFG instances", many=True, required=False, allow_null=True)
+ nsState = serializers.CharField(help_text="State of NS instance", required=False, allow_null=True)
+
+
+class VimSerializer(serializers.Serializer):
+ vimid = serializers.CharField(help_text="ID of VIM", required=False, allow_null=True)
+
+
+class LocationConstraintSerializer(serializers.Serializer):
+ vnfProfileId = serializers.CharField(help_text="ID of VNF profile", required=False, allow_null=True)
+ locationConstraints = VimSerializer(help_text="Location constraints", required=False, allow_null=True)
+
+
+class InstantNsReqSerializer(serializers.Serializer):
+ locationConstraints = LocationConstraintSerializer(required=False, allow_null=True)
+ additionalParamForNs = serializers.CharField(help_text="Additional param for NS", required=False, allow_null=True)
+
+
+class NsOperateJobSerializer(serializers.Serializer):
+ jobId = serializers.CharField(help_text="ID of NS operate job", required=True)
+
+
+class TerminateNsReqSerializer(serializers.Serializer):
+ terminationType = serializers.CharField(help_text="Type of NS termination", required=False, allow_null=True)
+ gracefulTerminationTimeout = serializers.CharField(help_text="Timeout of NS graceful termination", required=False, allow_null=True)
+
+
+class ActionVmSerializer(serializers.Serializer):
+ vmid = serializers.CharField(help_text="ID of VM", required=False, allow_null=True)
+ vmname = serializers.CharField(help_text="Name of VM", required=False, allow_null=True)
+
+
+class HealNsAdditionalParamsSerializer(serializers.Serializer):
+ action = serializers.CharField(help_text="Action of NS heal", required=False, allow_null=True)
+ actionvminfo = ActionVmSerializer(help_text="VM info of action", required=False, allow_null=True)
+
+
+class HealVnfDataSerializer(serializers.Serializer):
+ vnfInstanceId = serializers.CharField(help_text="ID of VNF Instance", required=True)
+ cause = serializers.CharField(help_text="Cause of NS heal", required=False, allow_null=True)
+ additionalParams = HealNsAdditionalParamsSerializer(help_text="Additional params of NS heal", required=False, allow_null=True)
+
+
+class HealNsReqSerializer(serializers.Serializer):
+ healVnfData = HealVnfDataSerializer(help_text="Data of heal VNF", required=False, allow_null=True)
+
+
+class InstNsPostDealReqSerializer(serializers.Serializer):
+ status = serializers.CharField(help_text="Status of NS Inst", required=True)
+
+
+class ScaleNsByStepsSerializer(serializers.Serializer):
+ aspectId = serializers.CharField(help_text="ID of aspect", required=True)
+ numberOfSteps = serializers.CharField(help_text="Number of steps", required=True)
+ scalingDirection = serializers.CharField(help_text="Scaling direction", required=True)
+
+
+class ScaleNsDataSerializer(serializers.Serializer):
+ scaleNsByStepsData = ScaleNsByStepsSerializer(help_text="Scale NS by steps data", many=True)
+
+
+class ManualScaleNsReqSerializer(serializers.Serializer):
+ scaleType = serializers.CharField(help_text="Type of NS Scale", required=True)
+ scaleNsData = ScaleNsDataSerializer(help_text="Scale NS data", many=True)
diff --git a/lcm/ns/sfcs/detail_views.py b/lcm/ns/sfcs/detail_views.py
index b5646f5f..6d92f39d 100644
--- a/lcm/ns/sfcs/detail_views.py
+++ b/lcm/ns/sfcs/detail_views.py
@@ -11,31 +11,61 @@
# 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 import status
from rest_framework.response import Response
from rest_framework.views import APIView
+from drf_yasg.utils import swagger_auto_schema
from lcm.ns.sfcs.delete_sfcs import DeleteSfcs
from lcm.ns.sfcs.get_sfcs import GetSfcs
+from lcm.ns.sfcs.serializers import GetSfcRespSerializer
+from lcm.ns.sfcs.serializers import DeleteSfcRespSerializer
+
+logger = logging.getLogger(__name__)
class SfcDetailView(APIView):
+ @swagger_auto_schema(
+ request_body=None,
+ responses={
+ status.HTTP_200_OK: GetSfcRespSerializer(),
+ status.HTTP_500_INTERNAL_SERVER_ERROR: "Inner error",
+ status.HTTP_404_NOT_FOUND: "SFC not found"
+ }
+ )
def get(self, request, sfc_inst_id):
- print "SfcCreateView--get::> %s" % sfc_inst_id
+ logger.debug("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})
+ resp_data = {'sfcInstId': sfc_inst_id,
+ 'sfcName': "xxx",
+ 'sfcStatus': sfc_inst_info[0].status}
+
+ resp_serializer = GetSfcRespSerializer(data=resp_data)
+ if not resp_serializer.is_valid():
+ logger.error(resp_serializer.errors)
+ return Response(data={'error': resp_serializer.errors},
+ status=status.HTTP_500_INTERNAL_SERVER_ERROR)
+
+ return Response(status=status.HTTP_200_OK, data=resp_serializer.data)
+
+ @swagger_auto_schema(
+ request_body=None,
+ responses={
+ status.HTTP_202_ACCEPTED: DeleteSfcRespSerializer()
+ }
+ )
def delete(self, request_paras, sfc_inst_id):
resp = DeleteSfcs(sfc_inst_id).do()
- return Response(data=resp, status=status.HTTP_202_ACCEPTED)
+ resp_serializer = DeleteSfcRespSerializer(data=resp)
+ if not resp_serializer.is_valid():
+ logger.error(resp_serializer.errors)
+ return Response(data={"result": 1, "detail": resp_serializer.errors},
+ 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)
+ return Response(data=resp, status=status.HTTP_202_ACCEPTED)
diff --git a/lcm/ns/sfcs/serializers.py b/lcm/ns/sfcs/serializers.py
new file mode 100644
index 00000000..1284f2f3
--- /dev/null
+++ b/lcm/ns/sfcs/serializers.py
@@ -0,0 +1,65 @@
+# Copyright 2018 ZTE Corporation.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+from rest_framework import serializers
+
+
+class CreateSfcInstReqSerializer(serializers.Serializer):
+ fpindex = serializers.CharField(help_text="Index of FP", required=True)
+ nsInstanceId = serializers.CharField(help_text="ID of NS instance", required=False, allow_null=True)
+ context = serializers.CharField(help_text="Context of NS instance", required=False, allow_null=True)
+ sdnControllerId = serializers.CharField(help_text="ID of SDN controller", required=False, allow_null=True)
+
+
+class CreateSfcInstRespSerializer(serializers.Serializer):
+ fpinstid = serializers.CharField(help_text="ID of FP instance", required=True)
+
+
+class CreateSfcReqSerializer(serializers.Serializer):
+ fpindex = serializers.CharField(help_text="Index of FP", required=True)
+ nsInstanceId = serializers.CharField(help_text="ID of NS instance", required=False, allow_null=True)
+ context = serializers.CharField(help_text="Context of NS instance", required=False, allow_null=True)
+ sdnControllerId = serializers.CharField(help_text="ID of SDN controller", required=False, allow_null=True)
+
+
+class CreateSfcRespSerializer(serializers.Serializer):
+ jobId = serializers.CharField(help_text="ID of job", required=True)
+ sfcInstId = serializers.CharField(help_text="ID of SFC instance", required=True)
+
+
+class GetSfcRespSerializer(serializers.Serializer):
+ sfcInstId = serializers.CharField(help_text="ID of SFC instance", required=True)
+ sfcName = serializers.CharField(help_text="Name of SFC instance", required=True)
+ sfcStatus = serializers.CharField(help_text="Status of SFC instance", required=True)
+
+
+class DeleteSfcRespSerializer(serializers.Serializer):
+ result = serializers.CharField(help_text="Delete SFC result(0: success, 1: failed)", required=True)
+ detail = serializers.CharField(help_text="Result detail", required=False, allow_null=True)
+
+
+class CreatePortPairGpSerializer(serializers.Serializer):
+ fpinstid = serializers.CharField(help_text="ID of FP instance", required=False, allow_null=True)
+ context = serializers.CharField(help_text="Context of NS instance", required=False, allow_null=True)
+ nsinstanceid = serializers.CharField(help_text="ID of NS instance", required=False, allow_null=True)
+
+
+class CreateFlowClaSerializer(serializers.Serializer):
+ fpinstid = serializers.CharField(help_text="ID of FP instance", required=False, allow_null=True)
+ context = serializers.CharField(help_text="Context of NS instance", required=False, allow_null=True)
+
+
+class CreatePortChainSerializer(serializers.Serializer):
+ fpinstid = serializers.CharField(help_text="ID of FP instance", required=False, allow_null=True)
+ context = serializers.CharField(help_text="Context of NS instance", required=False, allow_null=True)
diff --git a/lcm/ns/sfcs/urls.py b/lcm/ns/sfcs/urls.py
index 6b852567..cfca2c30 100644
--- a/lcm/ns/sfcs/urls.py
+++ b/lcm/ns/sfcs/urls.py
@@ -11,19 +11,19 @@
# 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 django.conf.urls import 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'^api/nslcm/v1/ns/sfcs$', SfcView.as_view()),
- url(r'^api/nslcm/v1/ns/sfcs/(?P<sfc_inst_id>[0-9a-zA-Z_-]+)$', SfcDetailView.as_view()),
- url(r'^api/nslcm/v1/ns/sfc_instance$', SfcInstanceView.as_view()),
- url(r'^api/nslcm/v1/ns/create_port_pair_group$', PortPairGpView.as_view()),
- url(r'^api/nslcm/v1/ns/create_flow_classifier$', FlowClaView.as_view()),
- url(r'^api/nslcm/v1/ns/create_port_chain$', PortChainView.as_view()),
- )
+urlpatterns = [
+ url(r'^api/nslcm/v1/ns/sfcs$', SfcView.as_view()),
+ url(r'^api/nslcm/v1/ns/sfcs/(?P<sfc_inst_id>[0-9a-zA-Z_-]+)$', SfcDetailView.as_view()),
+ url(r'^api/nslcm/v1/ns/sfc_instance$', SfcInstanceView.as_view()),
+ url(r'^api/nslcm/v1/ns/create_port_pair_group$', PortPairGpView.as_view()),
+ url(r'^api/nslcm/v1/ns/create_flow_classifier$', FlowClaView.as_view()),
+ url(r'^api/nslcm/v1/ns/create_port_chain$', PortChainView.as_view()),
+]
urlpatterns = format_suffix_patterns(urlpatterns)
diff --git a/lcm/ns/sfcs/views.py b/lcm/ns/sfcs/views.py
index 644dc95a..4403ffe6 100644
--- a/lcm/ns/sfcs/views.py
+++ b/lcm/ns/sfcs/views.py
@@ -22,6 +22,7 @@ import time
from rest_framework import status
from rest_framework.response import Response
from rest_framework.views import APIView
+from drf_yasg.utils import swagger_auto_schema
from lcm.ns.sfcs.create_flowcla import CreateFlowClassifier
from lcm.ns.sfcs.create_port_chain import CreatePortChain
@@ -29,24 +30,59 @@ 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
+from lcm.ns.sfcs.serializers import CreateSfcInstReqSerializer, CreateSfcInstRespSerializer
+from lcm.ns.sfcs.serializers import CreateSfcReqSerializer, CreateSfcRespSerializer
+from lcm.ns.sfcs.serializers import CreatePortPairGpSerializer
+from lcm.ns.sfcs.serializers import CreateFlowClaSerializer
+from lcm.ns.sfcs.serializers import CreatePortChainSerializer
logger = logging.getLogger(__name__)
class SfcInstanceView(APIView):
+ @swagger_auto_schema(
+ request_body=CreateSfcInstReqSerializer(),
+ responses={
+ status.HTTP_200_OK: CreateSfcInstRespSerializer(),
+ status.HTTP_500_INTERNAL_SERVER_ERROR: "Inner error"
+ }
+ )
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)
+ try:
+ req_serializer = CreateSfcInstReqSerializer(data=request.data)
+ if not req_serializer.is_valid():
+ raise Exception(req_serializer.errors)
+
+ 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()
+
+ resp_serializer = CreateSfcInstRespSerializer(data=rsp)
+ if not resp_serializer.is_valid():
+ raise Exception(resp_serializer.errors)
+
+ return Response(data=rsp, status=status.HTTP_200_OK)
+ except Exception as e:
+ logger.error(traceback.format_exc())
+ return Response(data={'error': e.message}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
class PortPairGpView(APIView):
+ @swagger_auto_schema(
+ request_body=CreatePortPairGpSerializer(),
+ responses={
+ status.HTTP_200_OK: 'successful'
+ }
+ )
def post(self, request):
+ req_serializer = CreatePortPairGpSerializer(data=request.data)
+ if not req_serializer.is_valid():
+ logger.error(req_serializer.errors)
+
data = {
'fpinstid': request.data["fpinstid"],
"ns_model_data": json.loads(request.data['context']),
@@ -56,7 +92,17 @@ class PortPairGpView(APIView):
class FlowClaView(APIView):
+ @swagger_auto_schema(
+ request_body=CreateFlowClaSerializer(),
+ responses={
+ status.HTTP_200_OK: 'successful'
+ }
+ )
def post(self, request):
+ req_serializer = CreateFlowClaSerializer(data=request.data)
+ if not req_serializer.is_valid():
+ logger.error(req_serializer.errors)
+
data = {
'fpinstid': request.data["fpinstid"],
"ns_model_data": json.loads(request.data['context'])}
@@ -65,7 +111,17 @@ class FlowClaView(APIView):
class PortChainView(APIView):
+ @swagger_auto_schema(
+ request_body=CreatePortChainSerializer(),
+ responses={
+ status.HTTP_200_OK: 'successful'
+ }
+ )
def post(self, request):
+ req_serializer = CreatePortChainSerializer(data=request.data)
+ if not req_serializer.is_valid():
+ logger.error(req_serializer.errors)
+
data = {
'fpinstid': request.data["fpinstid"],
"ns_model_data": json.loads(request.data['context'])}
@@ -74,25 +130,35 @@ class PortChainView(APIView):
class SfcView(APIView):
+ @swagger_auto_schema(
+ request_body=CreateSfcReqSerializer(),
+ responses={
+ status.HTTP_200_OK: CreateSfcRespSerializer()
+ }
+ )
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_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']
+
+ req_serializer = CreateSfcReqSerializer(data=request.data)
+ if not req_serializer.is_valid():
+ raise Exception(req_serializer.errors)
except Exception as e:
logger.error("Exception occurs: %s", e.message)
logger.error(traceback.format_exc())
data = {
- 'nsinstid': ignorcase_get(request.data, 'nsinstanceid'),
+ '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')
+ 'sdncontrollerid': ignorcase_get(request.data, 'sdnControllerId')
}
logger.info("Save FPInstModel start: ")
SfcInstance(data).do_biz()
@@ -104,6 +170,12 @@ class SfcView(APIView):
time.sleep(2)
logger.info("Service Function Chain Thread Sleep end: %s" % time.ctime())
logger.info("Create Service Function Chain end")
+
+ resp_serializer = CreateSfcRespSerializer(data={"jobId": job_id,
+ "sfcInstId": data["fpinstid"]})
+ if not resp_serializer.is_valid():
+ logger.error(resp_serializer.errors)
+
return Response(data={"jobId": job_id,
"sfcInstId": data["fpinstid"]},
status=status.HTTP_200_OK)
diff --git a/lcm/ns/tests/sfcs/test_create_flow_classifier.py b/lcm/ns/tests/sfcs/test_create_flow_classifier.py
index 2c48c293..1f69931d 100644
--- a/lcm/ns/tests/sfcs/test_create_flow_classifier.py
+++ b/lcm/ns/tests/sfcs/test_create_flow_classifier.py
@@ -11,46 +11,61 @@
# 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 = {
-# "/api/aai-esr-server/v1/sdncontrollers/test":
-# [0, json.JSONEncoder().encode({"url": "url_1"}), '200'],
-# "/api/sdncdriver/v1.0/createflowclassfier":
-# [0, json.JSONEncoder().encode({"id": "test_id_1"}), '200'],
-# "/api/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("/api/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)
+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 = {
+ "/external-system/esr-thirdparty-sdnc-list/esr-thirdparty-sdnc/test?depth=all":
+ [0, json.JSONEncoder().encode({
+ "thirdparty-sdnc-id": "1",
+ "esr-system-info-list": {
+ "esr-system-info": [{
+ "service-url": "url_1",
+ "thirdparty-sdnc-id": "1",
+ "user-name": "aa",
+ "password": "123",
+ "vendor": "zte",
+ "version": "v1.0",
+ "protocal": "http",
+ "product-name": "bbb",
+ "type": "11"
+ }]
+ }
+ }), '200'],
+ "/api/ztesdncdriver/v1/createflowclassfier":
+ [0, json.JSONEncoder().encode({"id": "test_id_1"}), '200'],
+ "/api/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("/api/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
index 7391dac9..978d5f6a 100644
--- a/lcm/ns/tests/sfcs/test_create_port_chain.py
+++ b/lcm/ns/tests/sfcs/test_create_port_chain.py
@@ -11,47 +11,62 @@
# 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 = {
-# "/api/aai-esr-server/v1/sdncontrollers/test_sdncontrollerid":
-# [0, json.JSONEncoder().encode({"url": "url_1"}), '200'],
-# "/api/sdncdriver/v1.0/createportchain":
-# [0, json.JSONEncoder().encode({"id": "test_id_1"}), '200'],
-# "/api/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("/api/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)
+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 = {
+ "/external-system/esr-thirdparty-sdnc-list/esr-thirdparty-sdnc/test_sdncontrollerid?depth=all":
+ [0, json.JSONEncoder().encode({
+ "thirdparty-sdnc-id": "1",
+ "esr-system-info-list": {
+ "esr-system-info": [{
+ "service-url": "url_1",
+ "thirdparty-sdnc-id": "1",
+ "user-name": "aa",
+ "password": "123",
+ "vendor": "zte",
+ "version": "v1.0",
+ "protocal": "http",
+ "product-name": "bbb",
+ "type": "11"
+ }]
+ }
+ }), '200'],
+ "/api/ztesdncdriver/v1/createportchain":
+ [0, json.JSONEncoder().encode({"id": "test_id_1"}), '200'],
+ "/api/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("/api/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
index d8c03cf6..490a9994 100644
--- a/lcm/ns/tests/sfcs/test_create_port_pair_group.py
+++ b/lcm/ns/tests/sfcs/test_create_port_pair_group.py
@@ -11,71 +11,93 @@
# 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 = {
-# "/api/aai-esr-server/v1/sdncontrollers/sdn_controller_1":
-# [0, json.JSONEncoder().encode({"url": "url_1"}), '200'],
-# "/api/sdncdriver/v1.0/createportpair":
-# [0, json.JSONEncoder().encode({"id": "createportpair_id"}), '200'],
-# "/api/sdncdriver/v1.0/createportpairgroup":
-# [0, json.JSONEncoder().encode({"id": "createportpairgroup_id"}), '200'],
-# "/api/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("/api/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"])
+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 = {
+ "/external-system/esr-thirdparty-sdnc-list/esr-thirdparty-sdnc/sdn_controller_1?depth=all":
+ [0, json.JSONEncoder().encode({
+ "thirdparty-sdnc-id": "1",
+ "esr-system-info-list": {
+ "esr-system-info": [{
+ "service-url": "url_1",
+ "thirdparty-sdnc-id": "1",
+ "user-name": "aa",
+ "password": "123",
+ "vendor": "zte",
+ "version": "v1.0",
+ "protocal": "http",
+ "product-name": "bbb",
+ "type": "11"
+ }]
+ }
+ }), '200'],
+ "/api/ztesdncdriver/v1/createportpair":
+ [0, json.JSONEncoder().encode({"id": "createportpair_id"}), '200'],
+ "/api/ztesdncdriver/v1/createportpairgroup":
+ [0, json.JSONEncoder().encode({"id": "createportpairgroup_id"}), '200'],
+ "/api/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("/api/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
index 8d58c692..72f0b430 100644
--- a/lcm/ns/tests/sfcs/test_data.py
+++ b/lcm/ns/tests/sfcs/test_data.py
@@ -102,6 +102,7 @@ nsd_model = {
"pnf_type": "TTGW",
"request_reclassification": False,
"nsh_aware": False,
+ "management_address": "10.34.45.67"
},
"cps": [
"cpd_1", "cpd_22",
diff --git a/lcm/ns/tests/sfcs/test_sfc.py b/lcm/ns/tests/sfcs/test_sfc.py
index 4fced43b..9eeff0dc 100644
--- a/lcm/ns/tests/sfcs/test_sfc.py
+++ b/lcm/ns/tests/sfcs/test_sfc.py
@@ -1,4 +1,4 @@
-# Copyright 2016 ZTE Corporation.
+# Copyright 2018 ZTE Corporation.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -12,1641 +12,1632 @@
# 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("/api/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("/api/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("/api/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("/api/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("/api/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",
-# ],
-# },
-# ],
-# },
-# ],
-# }
+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):
+ pass
+ # data = {
+ # "nsInstanceId": "ns_inst_1",
+ # "context": nsd_model,
+ # "fpindex": "fpd_1",
+ # "sdnControllerId": "sdnControllerId_1"
+ # }
+ # resp = self.client.post("/api/nslcm/v1/ns/sfc_instance", data, format='json')
+ # self.assertEqual(resp.status_code, status.HTTP_200_OK, resp.data)
+
+ @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("/api/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("/api/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("/api/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):
+ pass
+ # data = {
+ # "nsInstanceId": "ns_inst_1",
+ # "context": json.dumps(nsd_model),
+ # "fpindex": "1",
+ # 'fpinstid': str(uuid.uuid4()),
+ # "sdnControllerId": "sdnControllerId_1"
+ # }
+ # resp = self.client.post("/api/nslcm/v1/ns/sfcs", data, format='json')
+ # self.assertEqual(resp.status_code, status.HTTP_200_OK, resp.data)
+
+ 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):
+ pass
+ # 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",
+ 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",
+ 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,
+ "management_address": "10.44.56.78"
+ },
+ "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
index 981376fd..a0613b35 100644
--- a/lcm/ns/tests/sfcs/test_sfc_instance.py
+++ b/lcm/ns/tests/sfcs/test_sfc_instance.py
@@ -1,4 +1,4 @@
-# Copyright 2016 ZTE Corporation.
+# Copyright 2018 ZTE Corporation.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
@@ -11,37 +11,37 @@
# 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("/api/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)
+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("/api/nslcm/v1/ns/sfc_instance", data, format='json')
+
+ self.assertEqual(resp.status_code, status.HTTP_200_OK, resp.data)
+ vnffg = VNFFGInstModel.objects.get(vnffginstid="vnffg_inst_1")
+ ret = FPInstModel.objects.get(fpinstid=resp.data["fpinstid"])
+ self.assertEqual(vnffg.fplist, resp.data["fpinstid"])
+ self.assertIsNotNone(ret)
diff --git a/lcm/ns/tests/test_ns_create.py b/lcm/ns/tests/test_ns_create.py
index e462e1c3..61d87913 100644
--- a/lcm/ns/tests/test_ns_create.py
+++ b/lcm/ns/tests/test_ns_create.py
@@ -70,8 +70,8 @@ class TestNsInstantiate(TestCase):
mock_do_biz.side_effect = NSLCMException("nsd not exists.")
new_nsd_id = '1'
data = {
- 'nsdid': new_nsd_id,
- 'nsname': 'ns',
+ 'csarId': new_nsd_id,
+ 'nsName': 'ns',
'description': 'description'
}
response = self.client.post("/api/nslcm/v1/ns", data=data)
diff --git a/lcm/ns/tests/test_ns_delete.py b/lcm/ns/tests/test_ns_delete.py
index 892528d4..4397ef52 100644
--- a/lcm/ns/tests/test_ns_delete.py
+++ b/lcm/ns/tests/test_ns_delete.py
@@ -11,6 +11,7 @@
# 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
@@ -29,41 +30,11 @@ class TestNsDelelete(TestCase):
NSInstModel.objects.filter().delete()
NSInstModel(id=self.ns_inst_id, nspackage_id="7", nsd_id="2").save()
- # 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()
@mock.patch.object(restcall, 'call_req')
def test_delete_ns(self, mock_call_req):
- # customer_info = {
- # "global-customer-id": "global-customer-id-9b9348f2-f75d-4559-823d-db7ac138ed34",
- # "subscriber-name": "subscriber-name-9b9348f2-f75d-4559-823d-db7ac138ed34",
- # "subscriber-type": "subscriber-type-9b9348f2-f75d-4559-823d-db7ac138ed34",
- # "resource-version": "1505350719754",
- # "service-subscriptions": {
- # "service-subscription": [
- # {
- # "service-type": "service-type-9b9348f2-f75d-4559-823d-db7ac138ed34",
- # "resource-version": "1505350719887",
- # "service-instances": {
- # "service-instance": [
- # {
- # "service-instance-id": "service-instance-id-9b9348f2-f75d-4559-823d-db7ac138ed34",
- # "service-instance-name": "service-instance-name-9b9348f2-f75d-4559-823d-db7ac138ed34",
- # "service-type": "service-type-9b9348f2-f75d-4559-823d-db7ac138ed34",
- # "service-role": "service-role-9b9348f2-f75d-4559-823d-db7ac138ed34",
- # "resource-version": "1505350720009"
- # }
- # ]
- # }
- # }
- # ]
- # }
- # }
ns_info = {
"service-instance-id": "service-instance-id-9b9348f2-f75d-4559-823d-db7ac138ed34",
"service-instance-name": "service-instance-name-9b9348f2-f75d-4559-823d-db7ac138ed34",
diff --git a/lcm/ns/tests/test_ns_get.py b/lcm/ns/tests/test_ns_get.py
index e41f397a..32e5d1fb 100644
--- a/lcm/ns/tests/test_ns_get.py
+++ b/lcm/ns/tests/test_ns_get.py
@@ -31,7 +31,7 @@ class TestNsQuery(TestCase):
def test_query_all_nsinstance(self):
response = self.client.get("/api/nslcm/v1/ns")
- self.failUnlessEqual(status.HTTP_200_OK, response.status_code)
+ self.failUnlessEqual(status.HTTP_200_OK, response.status_code, response.data)
self.assertIsNotNone(response.data)
self.assertEqual(2, len(response.data))
diff --git a/lcm/ns/tests/test_ns_heal.py b/lcm/ns/tests/test_ns_heal.py
index 46f13ce6..a3b8498e 100644
--- a/lcm/ns/tests/test_ns_heal.py
+++ b/lcm/ns/tests/test_ns_heal.py
@@ -66,7 +66,7 @@ class TestHealNsViews(TestCase):
}
response = self.client.post("/api/nslcm/v1/ns/%s/heal" % self.ns_inst_id, data=data)
- self.assertEqual(status.HTTP_202_ACCEPTED, response.status_code)
+ self.assertEqual(status.HTTP_202_ACCEPTED, response.status_code, response.data)
self.assertIsNotNone(response.data)
self.assertIn("jobId", response.data)
self.assertNotIn("error", response.data)
@@ -128,6 +128,5 @@ class TestHealNsViews(TestCase):
data = {}
response = self.client.post("/api/nslcm/v1/ns/%s/heal" % self.ns_inst_id, data=data)
- self.assertEqual(response.data["error"], "healVnfData parameter does not exist or value is incorrect.")
self.assertEqual(response.status_code, status.HTTP_500_INTERNAL_SERVER_ERROR)
self.assertIn("error", response.data)
diff --git a/lcm/ns/tests/test_ns_manual_scale.py b/lcm/ns/tests/test_ns_manual_scale.py
index a25a0e9f..ceb7498e 100644
--- a/lcm/ns/tests/test_ns_manual_scale.py
+++ b/lcm/ns/tests/test_ns_manual_scale.py
@@ -13,36 +13,172 @@
# limitations under the License.
import uuid
-
+import os
import mock
from django.test import Client
from django.test import TestCase
from rest_framework import status
-
from lcm.ns.const import NS_INST_STATUS
from lcm.ns.ns_manual_scale import NSManualScaleService
-from lcm.pub.database.models import NSInstModel
+from lcm.pub.database.models import NSInstModel, JobModel, NfInstModel
from lcm.pub.exceptions import NSLCMException
from lcm.pub.utils import restcall
-from lcm.pub.utils.jobutil import JobUtil, JOB_TYPE
+from lcm.pub.utils.jobutil import JobUtil, JOB_TYPE, JOB_MODEL_STATUS
+from lcm.pub.msapi import catalog
+from lcm.pub.utils.scaleaspect import get_json_data
+
+
+SCALING_JSON = {
+ "scale_options": [
+ {
+ "nsd_id": "ns_ims",
+ "ns_scale_aspect": "TIC_CORE_IMS",
+ "ns_scale_info": [
+ {
+ "step": "1",
+ "scale_list": [
+ {
+ "vnfd_id": "zte_ims_cscf",
+ "vnf_scale_aspect": "mpu",
+ "numberOfSteps": "1"
+ },
+ {
+ "vnfd_id": "zte_ims_hss",
+ "vnf_scale_aspect": "fpu",
+ "numberOfSteps": "3"
+ }
+ ]
+ },
+ {
+ "step": "2",
+ "scale_list": [
+ {
+ "vnfd_id": "zte_ims_cscf",
+ "vnf_scale_aspect": "mpu",
+ "numberOfSteps": "2"
+ },
+ {
+ "vnfd_id": "zte_ims_hss",
+ "vnf_scale_aspect": "fpu",
+ "numberOfSteps": "6"
+ }
+ ]
+ }
+ ]
+ },
+ {
+ "nsd_id": "ns_epc",
+ "ns_scale_aspect": "TIC_EDGE_EPC",
+ "ns_scale_info": [
+ {
+ "step": "1",
+ "scale_list": [
+ {
+ "vnfd_id": "zte_epc_spgw",
+ "vnf_scale_aspect": "gpu",
+ "numberOfSteps": "1"
+ },
+ {
+ "vnfd_id": "zte_epc_tas",
+ "vnf_scale_aspect": "fpu",
+ "numberOfSteps": "2"
+ }
+ ]
+ },
+ {
+ "step": "2",
+ "scale_list": [
+ {
+ "vnfd_id": "zte_epc_spgw",
+ "vnf_scale_aspect": "mpu",
+ "numberOfSteps": "2"
+ },
+ {
+ "vnfd_id": "zte_epc_tas",
+ "vnf_scale_aspect": "fpu",
+ "numberOfSteps": "4"
+ }
+ ]
+ }
+ ]
+ }
+ ]
+}
class TestNsManualScale(TestCase):
def setUp(self):
self.ns_inst_id = str(uuid.uuid4())
- self.job_id = JobUtil.create_job("NS", JOB_TYPE.MANUAL_SCALE_VNF, self.ns_inst_id)
-
+ self.job_id = JobUtil.create_job(
+ "NS", JOB_TYPE.MANUAL_SCALE_VNF, self.ns_inst_id)
+ self.package_id = "7"
self.client = Client()
- NSInstModel(id=self.ns_inst_id, name="abc", nspackage_id="7", nsd_id="111").save()
+ NSInstModel(
+ id=self.ns_inst_id,
+ name="abc",
+ nspackage_id=self.package_id,
+ nsd_id="111").save()
+
+ self.init_scaling_map_json()
def tearDown(self):
NSInstModel.objects.filter().delete()
+ JobModel.objects.filter().delete()
+
+ def init_scaling_map_json(self):
+ curdir_path = os.path.dirname(
+ os.path.dirname(
+ os.path.dirname(
+ os.path.abspath(__file__))))
+ filename = curdir_path + "/ns/data/scalemapping.json"
+ self.scaling_map_json = get_json_data(filename)
+
+ def insert_new_ns(self):
+ ns_inst_id = str(uuid.uuid4())
+ job_id = JobUtil.create_job(
+ "NS", JOB_TYPE.MANUAL_SCALE_VNF, self.ns_inst_id)
+ package_id = "23"
+ NSInstModel(
+ id=ns_inst_id,
+ name="abc",
+ nspackage_id=package_id,
+ nsd_id=package_id).save()
+ return ns_inst_id, job_id
+
+ def insert_new_nf(self):
+ # Create a third vnf instance
+ self.nf_name = "name_1"
+ self.vnf_id = "1"
+ self.vnfm_inst_id = "1"
+ nf_inst_id = "233"
+ package_id = "nf_zte_hss"
+ nf_uuid = "ab34-3g5j-de13-ab85-ij93"
+
+ NfInstModel.objects.create(
+ nfinstid=nf_inst_id,
+ nf_name=self.nf_name,
+ vnf_id=self.vnf_id,
+ vnfm_inst_id=self.vnfm_inst_id,
+ ns_inst_id=self.ns_inst_id,
+ max_cpu='14',
+ max_ram='12296',
+ max_hd='101',
+ max_shd="20",
+ max_net=10,
+ status='active',
+ mnfinstid=nf_uuid,
+ package_id=package_id,
+ 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"}}')
@mock.patch.object(NSManualScaleService, 'run')
def test_ns_manual_scale(self, mock_run):
data = {
"scaleType": "SCALE_NS",
- "scaleNsByStepsData": [{
+ "scaleNsData": [{
"scaleNsByStepsData": [{
"aspectId": "1",
"numberOfSteps": 1,
@@ -50,14 +186,87 @@ class TestNsManualScale(TestCase):
}]
}]
}
- response = self.client.post("/api/nslcm/v1/ns/%s/scale" % self.ns_inst_id, data=data)
+ response = self.client.post(
+ "/api/nslcm/v1/ns/%s/scale" %
+ self.ns_inst_id, data=data)
self.failUnlessEqual(status.HTTP_202_ACCEPTED, response.status_code)
+ def test_ns_manual_scale_error_scaletype(self):
+ data = {
+ "scaleType": "SCALE_ERR",
+ "scaleNsData": [{
+ "scaleNsByStepsData": [{
+ "aspectId": "sss_zte",
+ "numberOfSteps": 1,
+ "scalingDirection": "0"
+ }]
+ }]
+ }
+ NSManualScaleService(self.ns_inst_id, data, self.job_id).run()
+ jobs = JobModel.objects.filter(jobid=self.job_id)
+ self.assertEqual(255, jobs[0].progress)
+
+ def test_ns_manual_scale_error_nsd_id(self):
+ data = {
+ "scaleType": "SCALE_NS",
+ "scaleNsData": [{
+ "scaleNsByStepsData": [{
+ "aspectId": "sss_zte",
+ "numberOfSteps": 1,
+ "scalingDirection": "0"
+ }]
+ }]
+ }
+ NSManualScaleService(self.ns_inst_id, data, self.job_id).run()
+ jobs = JobModel.objects.filter(jobid=self.job_id)
+ self.assertEqual(255, jobs[0].progress)
+
+ def test_ns_manual_scale_error_aspect(self):
+ data = {
+ "scaleType": "SCALE_NS",
+ "scaleNsData": [{
+ "scaleNsByStepsData": [{
+ "aspectId": "sss_zte",
+ "numberOfSteps": 1,
+ "scalingDirection": "0"
+ }]
+ }]
+ }
+ ns_inst_id, job_id = self.insert_new_ns()
+ job_id = JobUtil.create_job(
+ "NS", JOB_TYPE.MANUAL_SCALE_VNF, ns_inst_id)
+ NSManualScaleService(ns_inst_id, data, job_id).run()
+ jobs = JobModel.objects.filter(jobid=job_id)
+ self.assertEqual(255, jobs[0].progress)
+
+ @mock.patch.object(catalog, 'get_scalingmap_json_package')
+ @mock.patch.object(NSManualScaleService, 'do_vnfs_scale')
+ def test_ns_manual_scale_success(self, mock_do_vnfs_scale, mock_get_scalingmap_json_package):
+ data = {
+ "scaleType": "SCALE_NS",
+ "scaleNsData": [{
+ "scaleNsByStepsData": [{
+ "aspectId": "TIC_EDGE_IMS",
+ "numberOfSteps": "1",
+ "scalingDirection": "0"
+ }]
+ }]
+ }
+ mock_get_scalingmap_json_package.return_value = self.scaling_map_json
+ mock_do_vnfs_scale.return_value = JOB_MODEL_STATUS.FINISHED
+ ns_inst_id, job_id = self.insert_new_ns()
+ job_id = JobUtil.create_job(
+ "NS", JOB_TYPE.MANUAL_SCALE_VNF, ns_inst_id)
+ self.insert_new_nf()
+ NSManualScaleService(ns_inst_id, data, job_id).run()
+ jobs = JobModel.objects.filter(jobid=job_id)
+ self.assertEqual(100, jobs[0].progress)
+
@mock.patch.object(restcall, 'call_req')
def test_ns_manual_scale_thread(self, mock_call):
data = {
"scaleType": "SCALE_NS",
- "scaleNsByStepsData": [{
+ "scaleNsData": [{
"scaleNsByStepsData": [{
"aspectId": "1",
"numberOfSteps": 1,
@@ -66,7 +275,10 @@ class TestNsManualScale(TestCase):
}]
}
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)
+ self.assertTrue(
+ NSInstModel.objects.get(
+ id=self.ns_inst_id).status,
+ NS_INST_STATUS.ACTIVE)
def test_swagger_ok(self):
resp = self.client.get("/api/nslcm/v1/swagger.json", format='json')
@@ -75,8 +287,12 @@ class TestNsManualScale(TestCase):
@mock.patch.object(NSManualScaleService, 'start')
def test_ns_manual_scale_empty_data(self, mock_start):
mock_start.side_effect = NSLCMException("NS scale failed.")
- response = self.client.post("/api/nslcm/v1/ns/%s/scale" % self.ns_inst_id, data={})
- self.assertEqual(response.status_code, status.HTTP_500_INTERNAL_SERVER_ERROR)
+ response = self.client.post(
+ "/api/nslcm/v1/ns/%s/scale" %
+ self.ns_inst_id, data={})
+ self.assertEqual(
+ response.status_code,
+ status.HTTP_500_INTERNAL_SERVER_ERROR)
self.assertIn("error", response.data)
@mock.patch.object(NSManualScaleService, 'start')
@@ -84,7 +300,7 @@ class TestNsManualScale(TestCase):
mock_start.side_effect = NSLCMException("NS scale failed.")
data = {
"scaleType": "SCALE_NS",
- "scaleNsByStepsData": [{
+ "scaleNsData": [{
"scaleNsByStepsData": [{
"aspectId": "1",
"numberOfSteps": 1,
@@ -93,5 +309,7 @@ class TestNsManualScale(TestCase):
}]
}
response = self.client.post("/api/nslcm/v1/ns/11/scale", data=data)
- self.assertEqual(response.status_code, status.HTTP_500_INTERNAL_SERVER_ERROR)
+ self.assertEqual(
+ response.status_code,
+ status.HTTP_500_INTERNAL_SERVER_ERROR)
self.assertIn("error", response.data)
diff --git a/lcm/ns/tests/tests_ns_terminate.py b/lcm/ns/tests/tests_ns_terminate.py
index 4a33105d..d7091882 100644
--- a/lcm/ns/tests/tests_ns_terminate.py
+++ b/lcm/ns/tests/tests_ns_terminate.py
@@ -51,12 +51,12 @@ class TestTerminateNsViews(TestCase):
@mock.patch.object(TerminateNsService, 'run')
def test_terminate_vnf_url(self, mock_run):
- mock_run.re.return_value = None
+ mock_run.re.return_value = "1"
req_data = {
"terminationType": "forceful",
"gracefulTerminationTimeout": "600"}
response = self.client.post("/api/nslcm/v1/ns/%s/terminate" % self.ns_inst_id, data=req_data)
- self.failUnlessEqual(status.HTTP_202_ACCEPTED, response.status_code)
+ self.failUnlessEqual(status.HTTP_202_ACCEPTED, response.status_code, response.data)
response = self.client.delete("/api/nslcm/v1/ns/%s" % self.ns_inst_id)
self.failUnlessEqual(status.HTTP_204_NO_CONTENT, response.status_code)
@@ -100,7 +100,7 @@ class TestTerminateNsViews(TestCase):
@mock.patch.object(TerminateNsService, 'run')
def test_terminate_non_existing_ns_inst_id(self, mock_run):
- mock_run.re.return_value = None
+ mock_run.re.return_value = "1"
ns_inst_id = '100'
@@ -108,6 +108,6 @@ class TestTerminateNsViews(TestCase):
"terminationType": "forceful",
"gracefulTerminationTimeout": "600"}
response = self.client.post("/api/nslcm/v1/ns/%s/terminate" % ns_inst_id, data=req_data)
- self.failUnlessEqual(status.HTTP_202_ACCEPTED, response.status_code)
+ self.failUnlessEqual(status.HTTP_202_ACCEPTED, response.status_code, response.data)
self.assertRaises(NSInstModel.DoesNotExist, NSInstModel.objects.get, id=ns_inst_id)
diff --git a/lcm/ns/tests/vls/tests.py b/lcm/ns/tests/vls/tests.py
index 288c70e4..2966c908 100644
--- a/lcm/ns/tests/vls/tests.py
+++ b/lcm/ns/tests/vls/tests.py
@@ -84,10 +84,10 @@ class TestVlViews(TestCase):
req_data = {
"nsInstanceId": self.ns_inst_id,
"context": json.JSONEncoder().encode(self.context),
- "vlindex": vl_id}
+ "vlIndex": vl_id}
response = self.client.post("/api/nslcm/v1/ns/vls", data=req_data)
self.assertEqual(status.HTTP_201_CREATED, response.status_code)
- self.assertEqual(0, response.data["result"])
+ self.assertEqual(0, response.data["result"], response.data)
@mock.patch.object(restcall, "call_req")
@mock.patch.object(vimadaptor.VimAdaptor, "create_network")
@@ -96,7 +96,7 @@ class TestVlViews(TestCase):
req_data = {
"nsInstanceId": self.ns_inst_id,
"context": json.JSONEncoder().encode(self.context),
- "vlindex": self.vl_id_1}
+ "vlIndex": self.vl_id_1}
mock_uuid4.return_value = '999'
mock_req_by_rest.return_value = [0, json.JSONEncoder().encode(vim_info), '200']
mock_create_network.return_value = [1, (1)]
diff --git a/lcm/ns/tests/vnfs/tests.py b/lcm/ns/tests/vnfs/tests.py
index 57924822..1406fae2 100644
--- a/lcm/ns/tests/vnfs/tests.py
+++ b/lcm/ns/tests/vnfs/tests.py
@@ -303,10 +303,7 @@ class TestScaleVnfViews(TestCase):
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)
-
+ def test_scale_vnf(self):
vnfd_info = {
"vnf_flavours": [{
"flavour_id": "flavour1",
@@ -361,22 +358,72 @@ class TestScaleVnfViews(TestCase):
]
}
- mock_vals = {
- "/api/ztevnfmdriver/v1/1/vnfs/111/terminate":
- [0, json.JSONEncoder().encode({"jobId": job_id}), '200']
- }
-
- def side_effect(*args):
- return mock_vals[args[4]]
+ NFManualScaleService(self.nf_inst_id, req_data).run()
+ nsIns = NfInstModel.objects.filter(nfinstid=self.nf_inst_id)
+ self.assertIsNotNone(nsIns)
- mock_call_req.side_effect = side_effect
+ @mock.patch.object(NFManualScaleService, "send_nf_scaling_request")
+ def test_scale_vnf_success(self, mock_send_nf_scaling_request):
+ 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"]
+ }]
+ }
- NFManualScaleService(self.nf_inst_id, req_data).run()
+ 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
+ }
+ ]
+ }
+ scale_service = NFManualScaleService(self.nf_inst_id, req_data)
+ scale_service.run()
nsIns = NfInstModel.objects.filter(nfinstid=self.nf_inst_id)
- if nsIns:
- self.failUnlessEqual(1, 1)
- else:
- self.failUnlessEqual(1, 0)
+ self.assertIsNotNone(nsIns)
+
+ jobs = JobModel.objects.filter(jobid=scale_service.job_id)
+ self.assertIsNotNone(100, jobs[0].progress)
class TestHealVnfViews(TestCase):
@@ -520,7 +567,7 @@ class TestGetVnfmInfoViews(TestCase):
}
response = self.client.get("/api/nslcm/v1/vnfms/%s" % self.vnfm_id)
- self.failUnlessEqual(status.HTTP_200_OK, response.status_code)
+ self.failUnlessEqual(status.HTTP_200_OK, response.status_code, response.content)
context = json.loads(response.content)
self.assertEqual(expect_data, context)
diff --git a/lcm/ns/urls.py b/lcm/ns/urls.py
index f61b4444..6fa06587 100644
--- a/lcm/ns/urls.py
+++ b/lcm/ns/urls.py
@@ -11,25 +11,20 @@
# 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 django.conf.urls import url
from rest_framework.urlpatterns import format_suffix_patterns
from lcm.ns.views import CreateNSView, NSInstView, TerminateNSView, NSDetailView, NSInstPostDealView, \
NSManualScaleView, NSHealView
-urlpatterns = patterns('',
- url(r'^api/nslcm/v1/ns$', CreateNSView.as_view()),
- url(r'^api/nslcm/v1/ns/(?P<ns_instance_id>[0-9a-zA-Z_-]+)/instantiate$',
- NSInstView.as_view()),
- url(r'^api/nslcm/v1/ns/(?P<ns_instance_id>[0-9a-zA-Z_-]+)/terminate$',
- TerminateNSView.as_view()),
- url(r'^api/nslcm/v1/ns/(?P<ns_instance_id>[0-9a-zA-Z_-]+)$', NSDetailView.as_view()),
- url(r'^api/nslcm/v1/ns/(?P<ns_instance_id>[0-9a-zA-Z_-]+)/postdeal$',
- NSInstPostDealView.as_view()),
- url(r'^api/nslcm/v1/ns/(?P<ns_instance_id>[0-9a-zA-Z_-]+)/scale$',
- NSManualScaleView.as_view()),
- url(r'^api/nslcm/v1/ns/(?P<ns_instance_id>[0-9a-zA-Z_-]+)/heal$',
- NSHealView.as_view())
- )
+urlpatterns = [
+ url(r'^api/nslcm/v1/ns$', CreateNSView.as_view()),
+ url(r'^api/nslcm/v1/ns/(?P<ns_instance_id>[0-9a-zA-Z_-]+)/instantiate$', NSInstView.as_view()),
+ url(r'^api/nslcm/v1/ns/(?P<ns_instance_id>[0-9a-zA-Z_-]+)/terminate$', TerminateNSView.as_view()),
+ url(r'^api/nslcm/v1/ns/(?P<ns_instance_id>[0-9a-zA-Z_-]+)$', NSDetailView.as_view()),
+ url(r'^api/nslcm/v1/ns/(?P<ns_instance_id>[0-9a-zA-Z_-]+)/postdeal$', NSInstPostDealView.as_view()),
+ url(r'^api/nslcm/v1/ns/(?P<ns_instance_id>[0-9a-zA-Z_-]+)/scale$', NSManualScaleView.as_view()),
+ url(r'^api/nslcm/v1/ns/(?P<ns_instance_id>[0-9a-zA-Z_-]+)/heal$', NSHealView.as_view())
+]
urlpatterns = format_suffix_patterns(urlpatterns)
diff --git a/lcm/ns/views.py b/lcm/ns/views.py
index 03a5763d..413a89a6 100644
--- a/lcm/ns/views.py
+++ b/lcm/ns/views.py
@@ -13,12 +13,12 @@
# 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 drf_yasg.utils import swagger_auto_schema
from lcm.ns.ns_create import CreateNSService
from lcm.ns.ns_delete import DeleteNsService
@@ -31,110 +31,223 @@ from lcm.pub.database.models import NSInstModel, ServiceBaseInfoModel
from lcm.pub.utils.jobutil import JobUtil, JOB_TYPE
from lcm.pub.utils.restcall import req_by_msb
from lcm.pub.utils.values import ignore_case_get
+from lcm.ns.serializers import CreateNsReqSerializer, CreateNsRespSerializer
+from lcm.ns.serializers import QueryNsRespSerializer
+from lcm.ns.serializers import NsOperateJobSerializer
+from lcm.ns.serializers import InstantNsReqSerializer
+from lcm.ns.serializers import TerminateNsReqSerializer
+from lcm.ns.serializers import HealNsReqSerializer
+from lcm.ns.serializers import InstNsPostDealReqSerializer
+from lcm.ns.serializers import ManualScaleNsReqSerializer
+from lcm.pub.exceptions import NSLCMException
logger = logging.getLogger(__name__)
class CreateNSView(APIView):
+ @swagger_auto_schema(
+ request_body=None,
+ responses={
+ status.HTTP_200_OK: QueryNsRespSerializer(help_text="NS instances", many=True),
+ status.HTTP_500_INTERNAL_SERVER_ERROR: "Inner error"
+ }
+ )
def get(self, request):
- logger.debug("CreateNSView::get")
- filter = None
- csarId = ignore_case_get(request.META, 'csarId')
- if csarId:
- filter = {"csarId": csarId}
+ try:
+ logger.debug("CreateNSView::get")
+ filter = None
+ csarId = ignore_case_get(request.META, 'csarId')
+ if csarId:
+ filter = {"csarId": csarId}
- ret = GetNSInfoService(filter).get_ns_info()
- logger.debug("CreateNSView::get::ret=%s", ret)
- return Response(data=ret, status=status.HTTP_200_OK)
+ ret = GetNSInfoService(filter).get_ns_info()
+ logger.debug("CreateNSView::get::ret=%s", ret)
+ resp_serializer = QueryNsRespSerializer(data=ret, many=True)
+ if not resp_serializer.is_valid():
+ raise NSLCMException(resp_serializer.errors)
+ return Response(data=resp_serializer.data, status=status.HTTP_200_OK)
+ except Exception as e:
+ logger.error(traceback.format_exc())
+ logger.error("Exception in GetNS: %s", e.message)
+ return Response(data={'error': e.message}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
+ @swagger_auto_schema(
+ request_body=CreateNsReqSerializer(),
+ responses={
+ status.HTTP_201_CREATED: CreateNsRespSerializer(),
+ status.HTTP_500_INTERNAL_SERVER_ERROR: "Inner error"
+ }
+ )
def post(self, request):
logger.debug("Enter CreateNS: %s", request.data)
- if ignore_case_get(request.data, 'test') == "test":
- return Response(data={'nsInstanceId': "test"}, status=status.HTTP_201_CREATED)
- # nsd_id = ignore_case_get(request.data, 'nsdId')
- csar_id = ignore_case_get(request.data, 'csarId')
- ns_name = ignore_case_get(request.data, 'nsName')
- description = ignore_case_get(request.data, 'description')
- context = ignore_case_get(request.data, 'context')
try:
+ req_serializer = CreateNsReqSerializer(data=request.data)
+ if not req_serializer.is_valid():
+ raise NSLCMException(req_serializer.errors)
+
+ if ignore_case_get(request.data, 'test') == "test":
+ return Response(data={'nsInstanceId': "test"}, status=status.HTTP_201_CREATED)
+ csar_id = ignore_case_get(request.data, 'csarId')
+ ns_name = ignore_case_get(request.data, 'nsName')
+ description = ignore_case_get(request.data, 'description')
+ context = ignore_case_get(request.data, 'context')
ns_inst_id = CreateNSService(csar_id, ns_name, description, context).do_biz()
+
+ logger.debug("CreateNSView::post::ret={'nsInstanceId':%s}", ns_inst_id)
+ resp_serializer = CreateNsRespSerializer(data={'nsInstanceId': ns_inst_id})
+ if not resp_serializer.is_valid():
+ raise NSLCMException(resp_serializer.errors)
+ return Response(data=resp_serializer.data, status=status.HTTP_201_CREATED)
except Exception as e:
logger.error(traceback.format_exc())
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):
+ @swagger_auto_schema(
+ request_body=InstantNsReqSerializer(),
+ responses={
+ status.HTTP_200_OK: NsOperateJobSerializer(),
+ status.HTTP_500_INTERNAL_SERVER_ERROR: "Inner error"
+ }
+ )
def post(self, request, ns_instance_id):
+ logger.debug("Enter NSInstView::post::ns_instance_id=%s", ns_instance_id)
+ req_serializer = InstantNsReqSerializer(data=request.data)
+ if not req_serializer.is_valid():
+ return Response({'error': req_serializer.errors},
+ status=status.HTTP_500_INTERNAL_SERVER_ERROR)
ack = InstantNSService(ns_instance_id, request.data).do_biz()
+ resp_serializer = NsOperateJobSerializer(data=ack['data'])
+ if not resp_serializer.is_valid():
+ return Response({'error': resp_serializer.errors},
+ status=status.HTTP_500_INTERNAL_SERVER_ERROR)
logger.debug("Leave NSInstView::post::ack=%s", ack)
- return Response(data=ack['data'], status=ack['status'])
+ return Response(data=resp_serializer.data, status=ack['status'])
class TerminateNSView(APIView):
+ @swagger_auto_schema(
+ request_body=TerminateNsReqSerializer(),
+ responses={
+ status.HTTP_202_ACCEPTED: NsOperateJobSerializer(),
+ status.HTTP_500_INTERNAL_SERVER_ERROR: "Inner error"
+ }
+ )
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:
+ logger.debug("Enter TerminateNSView::post %s", request.data)
+ req_serializer = TerminateNsReqSerializer(data=request.data)
+ if not req_serializer.is_valid():
+ raise NSLCMException(req_serializer.errors)
+
+ 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)
TerminateNsService(ns_instance_id, termination_type, graceful_termination_timeout, job_id).start()
+
+ resp_serializer = NsOperateJobSerializer(data={'jobId': job_id})
+ if not resp_serializer.is_valid():
+ raise NSLCMException(resp_serializer.errors)
+ logger.debug("Leave TerminateNSView::post ret=%s", resp_serializer.data)
+ return Response(data=resp_serializer.data, status=status.HTTP_202_ACCEPTED)
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 NSHealView(APIView):
+ @swagger_auto_schema(
+ request_body=HealNsReqSerializer(),
+ responses={
+ status.HTTP_202_ACCEPTED: NsOperateJobSerializer(),
+ status.HTTP_500_INTERNAL_SERVER_ERROR: "Inner error"
+ }
+ )
def post(self, request, ns_instance_id):
- logger.debug("Enter HealNSView::post %s", request.data)
- job_id = JobUtil.create_job("VNF", JOB_TYPE.HEAL_VNF, ns_instance_id)
try:
+ logger.debug("Enter HealNSView::post %s", request.data)
+ logger.debug("Enter HealNSView:: %s", ns_instance_id)
+ req_serializer = HealNsReqSerializer(data=request.data)
+ if not req_serializer.is_valid():
+ raise NSLCMException(req_serializer.errors)
+
+ job_id = JobUtil.create_job("VNF", JOB_TYPE.HEAL_VNF, ns_instance_id)
NSHealService(ns_instance_id, request.data, job_id).start()
+
+ resp_serializer = NsOperateJobSerializer(data={'jobId': job_id})
+ if not resp_serializer.is_valid():
+ raise NSLCMException(resp_serializer.errors)
+
+ logger.debug("Leave HealNSView::post ret=%s", resp_serializer.data)
+ return Response(data=resp_serializer.data, status=status.HTTP_202_ACCEPTED)
except Exception as e:
logger.error("Exception in HealNSView: %s", e.message)
return Response(data={'error': e.message}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
- ret = {'jobId': job_id}
- logger.debug("Leave HealNSView::post ret=%s", ret)
- return Response(data=ret, status=status.HTTP_202_ACCEPTED)
class NSDetailView(APIView):
+ @swagger_auto_schema(
+ request_body=None,
+ responses={
+ status.HTTP_200_OK: QueryNsRespSerializer(help_text="NS instance", many=True),
+ status.HTTP_500_INTERNAL_SERVER_ERROR: "Inner error",
+ status.HTTP_404_NOT_FOUND: "Ns instance does not exist"
+ }
+ )
def get(self, request, ns_instance_id):
- logger.debug("Enter NSDetailView::get ns(%s)", ns_instance_id)
- ns_filter = {"ns_inst_id": ns_instance_id}
- ret = GetNSInfoService(ns_filter).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)
+ try:
+ logger.debug("Enter NSDetailView::get ns(%s)", ns_instance_id)
+ ns_filter = {"ns_inst_id": ns_instance_id}
+ ret = GetNSInfoService(ns_filter).get_ns_info()
+ if not ret:
+ return Response(status=status.HTTP_404_NOT_FOUND)
+ logger.debug("Leave NSDetailView::get::ret=%s", ret)
+ resp_serializer = QueryNsRespSerializer(data=ret, many=True)
+ if not resp_serializer.is_valid():
+ raise NSLCMException(resp_serializer.errors)
+ return Response(data=resp_serializer.data, status=status.HTTP_200_OK)
+ except Exception as e:
+ logger.error(traceback.format_exc())
+ logger.error("Exception in GetNSDetail: %s", e.message)
+ return Response(data={'error': e.message}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
+ @swagger_auto_schema(
+ request_body=None,
+ responses={
+ status.HTTP_204_NO_CONTENT: 'successful',
+ status.HTTP_500_INTERNAL_SERVER_ERROR: "Inner error"
+ }
+ )
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)
+ try:
+ 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)
+ except Exception as e:
+ logger.error(traceback.format_exc())
+ logger.error("Exception in delete NS: %s", e.message)
+ return Response(data={'error': e.message}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
class NSInstPostDealView(APIView):
+ @swagger_auto_schema(
+ request_body=InstNsPostDealReqSerializer(help_text="NS instant post deal"),
+ responses={
+ status.HTTP_202_ACCEPTED: "NS instant post deal success",
+ status.HTTP_500_INTERNAL_SERVER_ERROR: "Inner error"
+ }
+ )
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:
+ req_serializer = InstNsPostDealReqSerializer(data=request.data)
+ if not req_serializer.is_valid():
+ raise NSLCMException(req_serializer.errors)
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)
@@ -170,14 +283,30 @@ class NSInstPostDealView(APIView):
class NSManualScaleView(APIView):
+ @swagger_auto_schema(
+ request_body=ManualScaleNsReqSerializer(help_text="NS manual scale"),
+ responses={
+ status.HTTP_202_ACCEPTED: NsOperateJobSerializer(),
+ status.HTTP_500_INTERNAL_SERVER_ERROR: "Inner error"
+ }
+ )
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:
+ req_serializer = ManualScaleNsReqSerializer(data=request.data)
+ if not req_serializer.is_valid():
+ raise NSLCMException(req_serializer.errors)
+
NSManualScaleService(ns_instance_id, request.data, job_id).start()
+
+ resp_serializer = NsOperateJobSerializer(data={'jobId': job_id})
+ if not resp_serializer.is_valid():
+ raise NSLCMException(resp_serializer.errors)
+
+ return Response(data=resp_serializer.data, status=status.HTTP_202_ACCEPTED)
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)
diff --git a/lcm/ns/vls/serializers.py b/lcm/ns/vls/serializers.py
new file mode 100644
index 00000000..70437ac2
--- /dev/null
+++ b/lcm/ns/vls/serializers.py
@@ -0,0 +1,39 @@
+# Copyright 2018 ZTE Corporation.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+from rest_framework import serializers
+
+
+class CreateVlReqSerializer(serializers.Serializer):
+ vlIndex = serializers.CharField(help_text="Index of VL instance", required=True)
+ nsInstanceId = serializers.CharField(help_text="ID of NS instance", required=False, allow_null=True)
+ context = serializers.CharField(help_text="Context of VL instance", required=False, allow_null=True)
+ additionalParamForNs = serializers.CharField(help_text="Additional param for NS", required=False, allow_null=True)
+
+
+class CreateVlRespSerializer(serializers.Serializer):
+ result = serializers.IntegerField(help_text="VL create result(0: success, 1: failed)", required=True)
+ detail = serializers.CharField(help_text="Detail of result", required=False, allow_null=True)
+ vlId = serializers.CharField(help_text="ID of VL instance", required=True)
+
+
+class GetVlRespSerializer(serializers.Serializer):
+ vlId = serializers.CharField(help_text="ID of VL instance", required=False, allow_null=True)
+ vlName = serializers.CharField(help_text="Name of VL instance", required=False, allow_null=True)
+ vlStatus = serializers.CharField(help_text="Status of VL instance", required=False, allow_null=True)
+
+
+class DeleteVlRespSerializer(serializers.Serializer):
+ result = serializers.IntegerField(help_text="VL delete result(0: success)", required=True)
+ detail = serializers.CharField(help_text="Detail of result", required=False, allow_null=True)
diff --git a/lcm/ns/vls/urls.py b/lcm/ns/vls/urls.py
index a6f6adc5..597404d8 100644
--- a/lcm/ns/vls/urls.py
+++ b/lcm/ns/vls/urls.py
@@ -12,14 +12,14 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-from django.conf.urls import patterns, url
+from django.conf.urls import url
from rest_framework.urlpatterns import format_suffix_patterns
from lcm.ns.vls.views import VlView, VlDetailView
-urlpatterns = patterns('',
- url(r'^api/nslcm/v1/ns/vls$', VlView.as_view()),
- url(r'^api/nslcm/v1/ns/vls/(?P<vl_inst_id>[0-9a-zA-Z_-]+)$', VlDetailView.as_view()),
- )
+urlpatterns = [
+ url(r'^api/nslcm/v1/ns/vls$', VlView.as_view()),
+ url(r'^api/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
index 94ae5e21..33b6bb20 100644
--- a/lcm/ns/vls/views.py
+++ b/lcm/ns/vls/views.py
@@ -15,10 +15,14 @@
from rest_framework import status
from rest_framework.response import Response
from rest_framework.views import APIView
+from drf_yasg.utils import swagger_auto_schema
from lcm.ns.vls.create_vls import CreateVls
from lcm.ns.vls.delete_vls import DeleteVls
from lcm.ns.vls.get_vls import GetVls
+from lcm.ns.vls.serializers import CreateVlReqSerializer, CreateVlRespSerializer
+from lcm.ns.vls.serializers import GetVlRespSerializer
+from lcm.ns.vls.serializers import DeleteVlRespSerializer
import logging
@@ -26,23 +30,72 @@ logger = logging.getLogger(__name__)
class VlView(APIView):
+ @swagger_auto_schema(
+ request_body=CreateVlReqSerializer(),
+ responses={
+ status.HTTP_201_CREATED: CreateVlRespSerializer()
+ }
+ )
def post(self, request):
logger.debug("VlsCreateView--post::> %s" % request.data)
+
+ req_serializer = CreateVlReqSerializer(data=request.data)
+ if not req_serializer.is_valid():
+ logger.error(req_serializer.errors)
+ resp = {"result": 1, "detail": req_serializer.errors, "vlId": ""}
+ return Response(data=resp, status=status.HTTP_201_CREATED)
+
resp = CreateVls(request.data).do()
+
+ resp_serializer = CreateVlRespSerializer(data=resp)
+ if not resp_serializer.is_valid():
+ logger.error(resp_serializer.errors)
+ resp = {"result": 1, "detail": resp_serializer.errors, "vlId": ""}
+ return Response(data=resp, status=status.HTTP_201_CREATED)
+
return Response(data=resp, status=status.HTTP_201_CREATED)
class VlDetailView(APIView):
+ @swagger_auto_schema(
+ request_body=None,
+ responses={
+ status.HTTP_200_OK: GetVlRespSerializer(),
+ status.HTTP_404_NOT_FOUND: "VL instance is not found",
+ status.HTTP_500_INTERNAL_SERVER_ERROR: "Inner error"
+ }
+ )
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"})
+ resp_serializer = GetVlRespSerializer(data={
+ 'vlId': vl_inst_id,
+ 'vlName': vl_inst_info[0].vlinstancename,
+ 'vlStatus': "active"})
+ if not resp_serializer.is_valid():
+ logger.error(resp_serializer.errors)
+ return Response(data={'error': resp_serializer.errors},
+ status=status.HTTP_500_INTERNAL_SERVER_ERROR)
+
+ return Response(status=status.HTTP_200_OK, data=resp_serializer.data)
+
+ @swagger_auto_schema(
+ request_body=None,
+ responses={
+ status.HTTP_202_ACCEPTED: DeleteVlRespSerializer()
+ }
+ )
def delete(self, request_paras, vl_inst_id):
logger.debug("VlDetailView--delete::> %s" % vl_inst_id)
resp = DeleteVls(vl_inst_id).do()
+
+ resp_serializer = DeleteVlRespSerializer(data=resp)
+ if not resp_serializer.is_valid():
+ logger.error(resp_serializer.errors)
+ resp = {"result": 0, "detail": resp_serializer.errors}
+ return Response(data=resp, status=status.HTTP_202_ACCEPTED)
+
return Response(data=resp, status=status.HTTP_202_ACCEPTED)
diff --git a/lcm/ns/vnfs/notify_lcm.py b/lcm/ns/vnfs/notify_lcm.py
index 4ec80526..362e347c 100644
--- a/lcm/ns/vnfs/notify_lcm.py
+++ b/lcm/ns/vnfs/notify_lcm.py
@@ -62,11 +62,12 @@ class NotifyLcm(object):
self.exception('unexpected exception')
def get_vnfinstid(self, mnfinstid, vnfm_inst_id):
+ logger.debug("vnfinstid in vnfm is:%s,vnfmid is:%s", mnfinstid, vnfm_inst_id)
+ logger.debug("mnfinstid=%s, vnfm_inst_id=%s", 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')
+ raise NSLCMException("vnfinstid not exist")
def exception(self, error_msg):
logger.error('Notify Lcm failed, detail message: %s' % error_msg)
diff --git a/lcm/ns/vnfs/scale_vnfs.py b/lcm/ns/vnfs/scale_vnfs.py
index fe6c1017..5b4e978a 100644
--- a/lcm/ns/vnfs/scale_vnfs.py
+++ b/lcm/ns/vnfs/scale_vnfs.py
@@ -34,7 +34,8 @@ class NFManualScaleService(threading.Thread):
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.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 = []
@@ -63,44 +64,67 @@ class NFManualScaleService(threading.Thread):
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))
+ 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}
- })
+ logger.error(
+ 'scaleVnfData parameter does not exist or value incorrect')
+ raise NSLCMException(
+ 'scaleVnfData parameter does not exist or value incorrect')
+
+ scale_type = ignore_case_get(self.scale_vnf_data, 'type')
+ aspect_id = ignore_case_get(self.scale_vnf_data, 'aspectId')
+ number_of_steps = ignore_case_get(self.scale_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)
+ 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)
+ 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')
+ 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)
+ 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)
diff --git a/lcm/ns/vnfs/serializers.py b/lcm/ns/vnfs/serializers.py
new file mode 100644
index 00000000..7a74b167
--- /dev/null
+++ b/lcm/ns/vnfs/serializers.py
@@ -0,0 +1,223 @@
+# Copyright 2018 ZTE Corporation.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+from rest_framework import serializers
+
+
+class InstVnfReqSerializer(serializers.Serializer):
+ vnfIndex = serializers.CharField(help_text="Index of VNF", required=True)
+ nsInstanceId = serializers.CharField(help_text="ID of NS instance", required=True)
+ additionalParamForVnf = serializers.CharField(help_text="Additional param for VNF", required=False, allow_null=True)
+
+
+class InstVnfRespSerializer(serializers.Serializer):
+ vnfInstId = serializers.CharField(help_text="ID of VNF instance", required=True)
+ jobId = serializers.CharField(help_text="ID of Job", required=True)
+
+
+class GetVnfRespSerializer(serializers.Serializer):
+ vnfInstId = serializers.CharField(help_text="ID of VNF instance", required=True)
+ vnfName = serializers.CharField(help_text="Name of VNF instance", required=True)
+ vnfStatus = serializers.CharField(help_text="Status of VNF instance", required=True)
+
+
+class TerminateVnfReqSerializer(serializers.Serializer):
+ terminationType = serializers.CharField(help_text="Termination Type", required=False, allow_null=True)
+ gracefulTerminationTimeout = serializers.CharField(help_text="Graceful Termination Timeout", required=False, allow_null=True)
+
+
+class TerminateVnfRespSerializer(serializers.Serializer):
+ jobId = serializers.CharField(help_text="ID of Job", required=True)
+
+
+class ResourceChangeSerializer(serializers.Serializer):
+ type = serializers.ChoiceField(help_text="Change Type", choices=["VDU"], required=True)
+ resourceDefinitionId = serializers.CharField(help_text="Identifier of resource", required=False, allow_null=True)
+ vdu = serializers.CharField(help_text="Identifier identifier of VDU", required=False, allow_null=True)
+
+
+class GrantVnfReqSerializer(serializers.Serializer):
+ vnfInstanceId = serializers.CharField(help_text="ID of VNF instance", required=True)
+ vnfDescriptorId = serializers.CharField(help_text="ID of VNF Descriptor", required=False, allow_null=True)
+ lifecycleOperation = serializers.ChoiceField(
+ help_text="Lifecycle Operation",
+ choices=["Terminal", "Instantiate", "Scalein", "Scaleout", "Scaledown", "Scaleup", "Heal"],
+ required=True
+ )
+ jobId = serializers.CharField(help_text="ID of Job", required=False, allow_null=True)
+ addResource = ResourceChangeSerializer(help_text="Add resources", many=True)
+ removeResource = ResourceChangeSerializer(help_text="Remove resources", many=True)
+ additionalParam = serializers.DictField(
+ help_text="Additional parameters passed to the NFVO, specific to the VNF and the LCM operation. The currently interpreted keys are the following: vimId",
+ child=serializers.CharField(help_text="Additional parameters", allow_blank=True),
+ required=False,
+ allow_null=True
+ )
+
+
+class AccessinfoSerializer(serializers.Serializer):
+ tenant = serializers.CharField(help_text="Name of tenant", required=True)
+
+
+class VimSerializer(serializers.Serializer):
+ vimid = serializers.CharField(help_text="ID of VIM", required=True)
+ accessinfo = AccessinfoSerializer(help_text="Access Info", required=True)
+
+
+class GrantVnfRespSerializer(serializers.Serializer):
+ vnfInstanceId = serializers.CharField(help_text="ID of VNF instance", required=False, allow_null=True)
+ vim = VimSerializer(help_text="VIM Info", required=True)
+
+
+class AffectedVnfcSerializer(serializers.Serializer):
+ vnfcInstanceId = serializers.CharField(help_text="ID of VNFC instance", required=False, allow_null=True)
+ vduId = serializers.CharField(help_text="ID of VDU in VNFD", required=False, allow_null=True)
+ changeType = serializers.ChoiceField(
+ help_text="Type of Change",
+ choices=["added", "removed", "modified"],
+ required=True
+ )
+ vimId = serializers.CharField(help_text="ID of VIM", required=False, allow_null=True)
+ vmId = serializers.CharField(help_text="ID of virtual machine", required=False, allow_null=True)
+ vmName = serializers.CharField(help_text="Name of virtual machine", required=False, allow_null=True)
+
+
+class NetworkResourceSerializer(serializers.Serializer):
+ resourceType = serializers.ChoiceField(
+ help_text="Type of Resource",
+ choices=["network", "port"],
+ required=True
+ )
+ resourceId = serializers.CharField(help_text="ID of network resource", required=False, allow_null=True)
+ resourceName = serializers.CharField(help_text="Name of network resource", required=False, allow_null=True)
+
+
+class AffectedVirtualLinkSerializer(serializers.Serializer):
+ vlInstanceId = serializers.CharField(help_text="ID of VL instance", required=False, allow_null=True)
+ vldId = serializers.CharField(help_text="ID of VLD in VNFD", required=False, allow_null=True)
+ changeType = serializers.ChoiceField(
+ help_text="Type of Change",
+ choices=["added", "removed", "modified"],
+ required=True
+ )
+ networkResource = NetworkResourceSerializer(help_text="Network Resource", required=False, allow_null=True)
+
+
+class PortResourceSerializer(serializers.Serializer):
+ vimId = serializers.CharField(help_text="ID of VIM", required=False, allow_null=True)
+ resourceId = serializers.CharField(help_text="ID of Resource", required=False, allow_null=True)
+ resourceName = serializers.CharField(help_text="Name of Resource", required=False, allow_null=True)
+ tenant = serializers.CharField(help_text="ID of Tenant", required=False, allow_null=True)
+ ipAddress = serializers.CharField(help_text="IP address of port", required=False, allow_null=True)
+ macAddress = serializers.CharField(help_text="MAC address of port", required=False, allow_null=True)
+ instId = serializers.CharField(help_text="Instance id of server to which the port is attached to", required=False, allow_null=True)
+
+
+class AffectedCpSerializer(serializers.Serializer):
+ changeType = serializers.ChoiceField(
+ help_text="Type of Change",
+ choices=["added", "removed", "modified"],
+ required=True
+ )
+ virtualLinkInstanceId = serializers.CharField(help_text="ID of VL instance", required=False, allow_null=True)
+ cpInstanceId = serializers.CharField(help_text="ID of CP instance", required=False, allow_null=True)
+ cpdId = serializers.CharField(help_text="ID of CPD in VNFD", required=False, allow_null=True)
+ ownerType = serializers.CharField(help_text="Type of Owner", required=False, allow_null=True)
+ ownerId = serializers.CharField(help_text="ID of Owner", required=False, allow_null=True)
+ portResource = PortResourceSerializer(help_text="Port Resource", required=False, allow_null=True)
+
+
+class AffectedVirtualStorage(serializers.Serializer):
+ pass
+
+
+class NotifyLcmReqSerializer(serializers.Serializer):
+ status = serializers.ChoiceField(
+ help_text="Status of operation",
+ choices=["result", "start"],
+ required=True
+ )
+ operation = serializers.ChoiceField(
+ help_text="Lifecycle Operation",
+ choices=["Terminal", "Instantiate", "Scalein", "Scaleout", "Scaledown", "Scaleup", "Heal"],
+ required=True
+ )
+ jobId = serializers.CharField(help_text="ID of Job", required=False, allow_null=True)
+ vnfdmodule = serializers.CharField(help_text="VNFD Module", required=False, allow_null=True)
+ affectedVnfc = AffectedVnfcSerializer(help_text="Affected VNFC", many=True)
+ affectedVl = AffectedVirtualLinkSerializer(help_text="Affected VL", many=True)
+ affectedCp = AffectedCpSerializer(help_text="Affected CP", many=True)
+ affectedVirtualStorage = AffectedVirtualStorage(help_text="Affected Virtual Storage(Not supported)", many=True)
+
+
+class ScaleVnfReqSerializer(serializers.Serializer):
+ type = serializers.ChoiceField(
+ help_text="Direction of the scaling",
+ choices=["SCALE_IN", "SCALE_OUT"],
+ required=True
+ )
+ aspectId = serializers.CharField(help_text="Aspect ID of the VNF that is requested to be scaled", required=False, allow_null=True)
+ numberOfSteps = serializers.CharField(help_text="Number of scaling steps to be executed as part of this ScaleVnf operation", required=False, allow_null=True)
+ additionalParam = serializers.DictField(
+ help_text="Additional parameters passed by the NFVO as input to the scaling process, specific to the VNF being scaled",
+ child=serializers.CharField(help_text="Additional parameters", allow_blank=True),
+ required=False,
+ allow_null=True
+ )
+
+
+class ScaleVnfRespSerializer(serializers.Serializer):
+ jobId = serializers.CharField(help_text="ID of Job", required=True)
+
+
+class VerifyVnfReqSerializer(serializers.Serializer):
+ PackageID = serializers.CharField(help_text="ID of Package", required=True)
+
+
+class VerifyVnfRespSerializer(serializers.Serializer):
+ jobId = serializers.CharField(help_text="ID of Job", required=True)
+
+
+class VnfmInfoRespSerializer(serializers.Serializer):
+ vnfmId = serializers.CharField(help_text="ID of VNFM", required=True)
+ name = serializers.CharField(help_text="Name of VNFM", required=True)
+ type = serializers.CharField(help_text="Type of VNFM", required=True)
+ vimId = serializers.CharField(help_text="ID of VIM", required=True)
+ vendor = serializers.CharField(help_text="Vendor of VNFM", required=False, allow_null=True, allow_blank=True)
+ version = serializers.CharField(help_text="Version of VNFM", required=False, allow_null=True, allow_blank=True)
+ description = serializers.CharField(help_text="Description of VNFM", required=False, allow_null=True, allow_blank=True)
+ certificateUrl = serializers.CharField(help_text="Certificate Url of VNFM", required=True)
+ url = serializers.CharField(help_text="url of VNFM", required=True)
+ userName = serializers.CharField(help_text="User Name of VNFM", required=True)
+ password = serializers.CharField(help_text="Password of VNFM", required=True)
+ createTime = serializers.CharField(help_text="Create Time of VNFM", required=False, allow_null=True, allow_blank=True)
+
+
+class VimInfoRespSerializer(serializers.Serializer):
+ vimId = serializers.CharField(help_text="ID of VIM", required=True)
+ name = serializers.CharField(help_text="Name of VIM", required=True)
+ url = serializers.CharField(help_text="Url of VIM", required=True)
+ userName = serializers.CharField(help_text="User Name of VIM", required=True)
+ password = serializers.CharField(help_text="Password of VIM", required=True)
+ tenantId = serializers.CharField(help_text="Tenant ID of VIM", required=False, allow_null=True, allow_blank=True)
+ tenant = serializers.CharField(help_text="Default Tenant of VIM", required=False, allow_null=True, allow_blank=True)
+ vendor = serializers.CharField(help_text="Vendor of VIM", required=False, allow_null=True, allow_blank=True)
+ version = serializers.CharField(help_text="Version of VIM", required=False, allow_null=True, allow_blank=True)
+ description = serializers.CharField(help_text="Description of VIM", required=False, allow_null=True, allow_blank=True)
+ domain = serializers.CharField(help_text="Domain of VIM", required=False, allow_null=True, allow_blank=True)
+ type = serializers.CharField(help_text="Type of VIM", required=True)
+ createTime = serializers.CharField(help_text="Create Time of VIM", required=False, allow_null=True, allow_blank=True)
+ sslCacert = serializers.CharField(help_text="SSL Cacert of VIM", required=False, allow_null=True, allow_blank=True)
+ sslInsecure = serializers.CharField(help_text="SSL Insecure of VIM", required=False, allow_null=True, allow_blank=True)
+ status = serializers.CharField(help_text="Status of VIM", required=False, allow_null=True, allow_blank=True)
diff --git a/lcm/ns/vnfs/terminate_nfs.py b/lcm/ns/vnfs/terminate_nfs.py
index 3afb5c67..7db2d7c3 100644
--- a/lcm/ns/vnfs/terminate_nfs.py
+++ b/lcm/ns/vnfs/terminate_nfs.py
@@ -159,7 +159,7 @@ class TerminateVnfs(threading.Thread):
cloud_owner, cloud_region_id = split_vim_to_owner_region(vim_id)
# query vim_info from aai, get tenant
vim_info = get_vim_by_id(vim_id)
- tenant_id = vim_info["tenant"]
+ tenant_id = vim_info["tenantId"]
# query vserver instance in aai, get resource_version
vserver_info = query_vserver_aai(cloud_owner, cloud_region_id, tenant_id, vserver_id)
diff --git a/lcm/ns/vnfs/urls.py b/lcm/ns/vnfs/urls.py
index 6e79c4d9..5da83678 100644
--- a/lcm/ns/vnfs/urls.py
+++ b/lcm/ns/vnfs/urls.py
@@ -11,23 +11,22 @@
# 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 django.conf.urls import url
from rest_framework.urlpatterns import format_suffix_patterns
-from lcm.ns.vnfs.views import NfView, NfDetailView, NfGrant, LcmNotify, NfScaleView, NfVerifyView, NfVnfmInfoView, \
- NfVimInfoView
+from lcm.ns.vnfs.views import NfView, NfDetailView, NfGrant
+from lcm.ns.vnfs.views import LcmNotify, NfScaleView, NfVerifyView
+from lcm.ns.vnfs.views import NfVnfmInfoView, NfVimInfoView
-urlpatterns = patterns('',
- url(r'^api/nslcm/v1/ns/vnfs$', NfView.as_view()),
- url(r'^api/nslcm/v1/ns/vnfs/(?P<vnfinstid>[0-9a-zA-Z_-]+)$', NfDetailView.as_view()),
- url(r'^api/nslcm/v1/ns/grantvnf$', NfGrant.as_view()),
- url(r'^api/nslcm/v1/ns/(?P<vnfmid>[0-9a-zA-Z_-]+)'
- r'/vnfs/(?P<vnfInstanceId>[0-9a-zA-Z_-]+)/Notify$',
- LcmNotify.as_view()),
- url(r'^api/nslcm/v1/ns/vnfs/(?P<vnfinstid>[0-9a-zA-Z_-]+)/scaling$', NfScaleView.as_view()),
- url(r'^api/nslcm/v1/vnfonboarding$', NfVerifyView.as_view()),
- url(r'^api/nslcm/v1/vnfms/(?P<vnfmid>[0-9a-zA-Z_-]+)', NfVnfmInfoView.as_view()),
- url(r'^api/nslcm/v1/vims/(?P<vimid>[0-9a-zA-Z_-]+)', NfVimInfoView.as_view()),
- )
+urlpatterns = [
+ url(r'^api/nslcm/v1/ns/vnfs$', NfView.as_view()),
+ url(r'^api/nslcm/v1/ns/vnfs/(?P<vnfinstid>[0-9a-zA-Z_-]+)$', NfDetailView.as_view()),
+ url(r'^api/nslcm/v1/ns/grantvnf$', NfGrant.as_view()),
+ url(r'^api/nslcm/v1/ns/(?P<vnfmid>[0-9a-zA-Z_-]+)/vnfs/(?P<vnfInstanceId>[0-9a-zA-Z_-]+)/Notify$', LcmNotify.as_view()),
+ url(r'^api/nslcm/v1/ns/vnfs/(?P<vnfinstid>[0-9a-zA-Z_-]+)/scaling$', NfScaleView.as_view()),
+ url(r'^api/nslcm/v1/vnfonboarding$', NfVerifyView.as_view()),
+ url(r'^api/nslcm/v1/vnfms/(?P<vnfmid>[0-9a-zA-Z_-]+)', NfVnfmInfoView.as_view()),
+ url(r'^api/nslcm/v1/vims/(?P<vimid>[0-9a-zA-Z_-]+)', NfVimInfoView.as_view()),
+]
urlpatterns = format_suffix_patterns(urlpatterns)
diff --git a/lcm/ns/vnfs/views.py b/lcm/ns/vnfs/views.py
index 411ecf05..75d2b500 100644
--- a/lcm/ns/vnfs/views.py
+++ b/lcm/ns/vnfs/views.py
@@ -18,6 +18,7 @@ import uuid
from rest_framework import status
from rest_framework.response import Response
from rest_framework.views import APIView
+from drf_yasg.utils import swagger_auto_schema
from lcm.ns.vnfs import create_vnfs
from lcm.ns.vnfs.create_vnfs import CreateVnfs
@@ -31,13 +32,38 @@ from lcm.pub.exceptions import NSLCMException
from lcm.pub.msapi.extsys import get_vnfm_by_id, get_vim_by_id
from lcm.pub.utils.jobutil import JobUtil, JOB_TYPE
from lcm.pub.utils.values import ignore_case_get
+from lcm.ns.vnfs.serializers import InstVnfReqSerializer
+from lcm.ns.vnfs.serializers import InstVnfRespSerializer
+from lcm.ns.vnfs.serializers import GetVnfRespSerializer
+from lcm.ns.vnfs.serializers import TerminateVnfReqSerializer
+from lcm.ns.vnfs.serializers import TerminateVnfRespSerializer
+from lcm.ns.vnfs.serializers import GrantVnfReqSerializer
+from lcm.ns.vnfs.serializers import GrantVnfRespSerializer
+from lcm.ns.vnfs.serializers import NotifyLcmReqSerializer
+from lcm.ns.vnfs.serializers import ScaleVnfReqSerializer
+from lcm.ns.vnfs.serializers import ScaleVnfRespSerializer
+from lcm.ns.vnfs.serializers import VerifyVnfReqSerializer
+from lcm.ns.vnfs.serializers import VerifyVnfRespSerializer
+from lcm.ns.vnfs.serializers import VnfmInfoRespSerializer
+from lcm.ns.vnfs.serializers import VimInfoRespSerializer
logger = logging.getLogger(__name__)
class NfView(APIView):
+ @swagger_auto_schema(
+ request_body=InstVnfReqSerializer(),
+ responses={
+ status.HTTP_202_ACCEPTED: InstVnfRespSerializer()
+ }
+ )
def post(self, request):
logger.debug("VnfCreateView--post::> %s" % request.data)
+
+ req_serializer = InstVnfReqSerializer(data=request.data)
+ if not req_serializer.is_valid():
+ logger.error(req_serializer.errors)
+
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'),
@@ -47,21 +73,53 @@ class NfView(APIView):
rsp = {
"vnfInstId": nf_inst_id,
"jobId": job_id}
+
+ resp_serializer = InstVnfRespSerializer(data=rsp)
+ if not resp_serializer.is_valid():
+ logger.error(resp_serializer.errors)
+
return Response(data=rsp, status=status.HTTP_202_ACCEPTED)
class NfDetailView(APIView):
+ @swagger_auto_schema(
+ request_body=None,
+ responses={
+ status.HTTP_200_OK: GetVnfRespSerializer(),
+ status.HTTP_404_NOT_FOUND: "VNF not found"
+ }
+ )
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})
+ rsp = {
+ 'vnfInstId': nf_inst_info[0].nfinstid,
+ 'vnfName': nf_inst_info[0].nf_name,
+ 'vnfStatus': nf_inst_info[0].status
+ }
+ resp_serializer = GetVnfRespSerializer(data=rsp)
+ if not resp_serializer.is_valid():
+ logger.error(resp_serializer.errors)
+
+ return Response(status=status.HTTP_200_OK, data=rsp)
+
+ @swagger_auto_schema(
+ request_body=TerminateVnfReqSerializer(),
+ responses={
+ status.HTTP_200_OK: TerminateVnfRespSerializer(),
+ status.HTTP_409_CONFLICT: "Inner error"
+ }
+ )
def post(self, request_paras, vnfinstid):
logger.debug("VnfTerminateView--post::> %s, %s", vnfinstid, request_paras.data)
+
+ req_serializer = TerminateVnfReqSerializer(data=request_paras.data)
+ if not req_serializer.is_valid():
+ logger.error(req_serializer.errors)
+
vnf_inst_id = vnfinstid
terminationType = ignore_case_get(request_paras.data, 'terminationType')
gracefulTerminationTimeout = ignore_case_get(request_paras.data, 'gracefulTerminationTimeout')
@@ -74,13 +132,29 @@ class NfDetailView(APIView):
logger.error(e.message)
return Response(data={'error': '%s' % e.message}, status=status.HTTP_409_CONFLICT)
rsp = {'jobId': job_id}
+
+ resp_serializer = TerminateVnfRespSerializer(data=rsp)
+ if not resp_serializer.is_valid():
+ logger.error(resp_serializer.errors)
+
return Response(data=rsp, status=status.HTTP_201_CREATED)
class NfGrant(APIView):
+ @swagger_auto_schema(
+ request_body=GrantVnfReqSerializer(),
+ responses={
+ status.HTTP_201_CREATED: GrantVnfRespSerializer(),
+ status.HTTP_409_CONFLICT: "Inner error"
+ }
+ )
def post(self, request):
logger.debug("NfGrant--post::> %s" % request.data)
try:
+ req_serializer = GrantVnfReqSerializer(data=request.data)
+ if not req_serializer.is_valid():
+ raise Exception(req_serializer.errors)
+
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()
@@ -94,6 +168,10 @@ class NfGrant(APIView):
}
}
"""
+ resp_serializer = GrantVnfRespSerializer(data=rsp)
+ if not resp_serializer.is_valid():
+ raise Exception(resp_serializer.errors)
+
return Response(data=rsp, status=status.HTTP_201_CREATED)
except Exception as e:
logger.error(e.message)
@@ -102,10 +180,20 @@ class NfGrant(APIView):
class LcmNotify(APIView):
- def post(self, request_paras, vnfmid, vnfInstanceId):
- logger.debug("LcmNotify--post::> %s" % request_paras.data)
+ @swagger_auto_schema(
+ request_body=NotifyLcmReqSerializer(),
+ responses={
+ status.HTTP_201_CREATED: 'successful',
+ status.HTTP_409_CONFLICT: "Inner error"
+ }
+ )
+ def post(self, request, vnfmid, vnfInstanceId):
+ logger.debug("LcmNotify--post::> %s" % request.data)
try:
- NotifyLcm(vnfmid, vnfInstanceId, request_paras.data).do_biz()
+ req_serializer = NotifyLcmReqSerializer(data=request.data)
+ if not req_serializer.is_valid():
+ raise Exception(req_serializer.errors)
+ NotifyLcm(vnfmid, vnfInstanceId, request.data).do_biz()
return Response(data={}, status=status.HTTP_201_CREATED)
except Exception as e:
logger.error(e.message)
@@ -113,10 +201,20 @@ class LcmNotify(APIView):
class NfScaleView(APIView):
- def post(self, request_paras, vnfinstid):
- logger.debug("NfScaleView--post::> %s" % request_paras.data)
+ @swagger_auto_schema(
+ request_body=ScaleVnfReqSerializer(),
+ responses={
+ status.HTTP_202_ACCEPTED: ScaleVnfRespSerializer(),
+ status.HTTP_409_CONFLICT: "Inner error"
+ }
+ )
+ def post(self, request, vnfinstid):
+ logger.debug("NfScaleView--post::> %s" % request.data)
try:
- NFManualScaleService(vnfinstid, request_paras.data).start()
+ req_serializer = ScaleVnfReqSerializer(data=request.data)
+ if not req_serializer.is_valid():
+ raise Exception(req_serializer.errors)
+ NFManualScaleService(vnfinstid, request.data).start()
return Response(data={}, status=status.HTTP_202_ACCEPTED)
except Exception as e:
logger.error(e.message)
@@ -124,18 +222,51 @@ class NfScaleView(APIView):
class NfVerifyView(APIView):
+ @swagger_auto_schema(
+ request_body=VerifyVnfReqSerializer(),
+ responses={
+ status.HTTP_202_ACCEPTED: VerifyVnfRespSerializer(),
+ status.HTTP_409_CONFLICT: "Inner error"
+ }
+ )
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)
+ try:
+ req_serializer = VerifyVnfReqSerializer(data=request.data)
+ if not req_serializer.is_valid():
+ raise Exception(req_serializer.errors)
+
+ VerifyVnfs(request.data, job_id).start()
+
+ rsp = {"jobId": job_id}
+ resp_serializer = VerifyVnfRespSerializer(data=rsp)
+ if not resp_serializer.is_valid():
+ raise Exception(resp_serializer.errors)
+
+ return Response(data=rsp, status=status.HTTP_202_ACCEPTED)
+ except Exception as e:
+ logger.error(e.message)
+ return Response(data={'error': '%s' % e.message}, status=status.HTTP_409_CONFLICT)
class NfVnfmInfoView(APIView):
+ @swagger_auto_schema(
+ request_body=None,
+ responses={
+ status.HTTP_200_OK: VnfmInfoRespSerializer(),
+ status.HTTP_500_INTERNAL_SERVER_ERROR: "Inner error"
+ }
+ )
def get(self, request, vnfmid):
logger.debug("NfVnfmInfoView--get::> %s" % vnfmid)
try:
vnfm_info = get_vnfm_by_id(vnfmid)
+
+ resp_serializer = VnfmInfoRespSerializer(data=vnfm_info)
+ if not resp_serializer.is_valid():
+ raise Exception(resp_serializer.errors)
+
except NSLCMException as e:
logger.error(e.message)
return Response(data={'error': '%s' % e.message}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
@@ -148,10 +279,22 @@ class NfVnfmInfoView(APIView):
class NfVimInfoView(APIView):
+ @swagger_auto_schema(
+ request_body=None,
+ responses={
+ status.HTTP_200_OK: VimInfoRespSerializer(),
+ status.HTTP_500_INTERNAL_SERVER_ERROR: "Inner error"
+ }
+ )
def get(self, request, vimid):
logger.debug("NfVimInfoView--get::> %s" % vimid)
try:
vim_info = get_vim_by_id(vimid)
+
+ resp_serializer = VimInfoRespSerializer(data=vim_info)
+ if not resp_serializer.is_valid():
+ raise Exception(resp_serializer.errors)
+
except NSLCMException as e:
logger.error(e.message)
return Response(data={'error': '%s' % e.message}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
diff --git a/lcm/pub/config/config.py b/lcm/pub/config/config.py
index a7213400..b9afbe64 100644
--- a/lcm/pub/config/config.py
+++ b/lcm/pub/config/config.py
@@ -33,6 +33,11 @@ DB_NAME = "vfcnfvolcm"
DB_USER = "vfcnfvolcm"
DB_PASSWD = "vfcnfvolcm"
+# [MDC]
+SERVICE_NAME = "nslcm"
+FORWARDED_FOR_FIELDS = ["HTTP_X_FORWARDED_FOR", "HTTP_X_FORWARDED_HOST",
+ "HTTP_X_FORWARDED_SERVER"]
+
# [register]
REG_TO_MSB_WHEN_START = True
REG_TO_MSB_REG_URL = "/api/microservices/v1/services"
diff --git a/lcm/pub/database/models.py b/lcm/pub/database/models.py
index 306cc510..22a7a6b3 100644
--- a/lcm/pub/database/models.py
+++ b/lcm/pub/database/models.py
@@ -302,7 +302,7 @@ class ServiceBaseInfoModel(models.Model):
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)
+ create_time = models.BigIntegerField(db_column='createTime')
class WFPlanModel(models.Model):
diff --git a/lcm/pub/msapi/catalog.py b/lcm/pub/msapi/catalog.py
index ebefcab1..30828ee7 100644
--- a/lcm/pub/msapi/catalog.py
+++ b/lcm/pub/msapi/catalog.py
@@ -18,6 +18,7 @@ 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
+from lcm.pub.database.models import NSInstModel
logger = logging.getLogger(__name__)
@@ -104,3 +105,13 @@ def get_servicetemplate(nsd_id):
if stpl.get("id", "") == nsd_id:
return stpl
return NSLCMException('servicetemplate(%s) does not exist.' % nsd_id)
+
+
+# Gets scaling map json from ns package according to nsd id.
+def get_scalingmap_json_package(ns_InstanceId):
+ csar_id = NSInstModel.objects.filter(id=ns_InstanceId)[0].nspackage_id
+ downloadUrl = query_csar_from_catalog(csar_id, "packageInfo")["downloadUrl"]
+ ret = req_by_msb(downloadUrl, 'GET')
+ scalingmap_json = json.JSONDecoder().decode(ret[1])
+
+ return scalingmap_json
diff --git a/lcm/pub/msapi/extsys.py b/lcm/pub/msapi/extsys.py
index e7f83d65..65b7d032 100644
--- a/lcm/pub/msapi/extsys.py
+++ b/lcm/pub/msapi/extsys.py
@@ -86,7 +86,7 @@ def convert_vim_info(vim_info_aai):
"type": ignore_case_get(esr_system_info[0], "type"),
"createTime": "",
"sslCacert": ignore_case_get(esr_system_info[0], "ssl-cacert"),
- "sslInsecure": ignore_case_get(esr_system_info[0], "ssl-insecure"),
+ "sslInsecure": str(ignore_case_get(esr_system_info[0], "ssl-insecure")),
"status": ignore_case_get(esr_system_info[0], "system-status")
}
return vim_info
diff --git a/lcm/pub/tests/__init__.py b/lcm/pub/tests/__init__.py
new file mode 100644
index 00000000..4f0b05c3
--- /dev/null
+++ b/lcm/pub/tests/__init__.py
@@ -0,0 +1,13 @@
+# Copyright 2016-2018 ZTE Corporation.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
diff --git a/lcm/pub/tests/test_scaleaspect.py b/lcm/pub/tests/test_scaleaspect.py
new file mode 100644
index 00000000..38d4ad29
--- /dev/null
+++ b/lcm/pub/tests/test_scaleaspect.py
@@ -0,0 +1,398 @@
+# Copyright 2016-2018 ZTE Corporation.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+from django.test import TestCase
+from lcm.pub.utils.scaleaspect import get_json_data
+from lcm.pub.utils.scaleaspect import get_nsdId
+from lcm.pub.utils.scaleaspect import get_scale_vnf_data_from_json
+from lcm.pub.utils.scaleaspect import get_scale_vnf_data_info_list
+from lcm.pub.utils.scaleaspect import set_scacle_vnf_instance_id
+from lcm.pub.utils.scaleaspect import check_and_set_params
+from lcm.pub.utils.scaleaspect import set_scaleVnfData_type
+from lcm.pub.database.models import NfInstModel
+from lcm.pub.database.models import NSInstModel
+from lcm.pub.msapi import catalog
+from lcm.pub.utils.timeutil import now_time
+import os
+import mock
+
+
+class TestScaleAspect(TestCase):
+
+ def setUp(self):
+ self.init_scaling_map_json()
+ self.initInstModel()
+
+ self.init_scale_ns_data()
+
+ self.vnf_scale_info_list = [
+ {
+ "vnfd_id": "nf_zte_cscf",
+ "vnf_scaleAspectId": "mpu",
+ "numberOfSteps": "1"
+ },
+ {
+ "vnfd_id": "nf_zte_hss",
+ "vnf_scaleAspectId": "gsu",
+ "numberOfSteps": "2"
+ }
+ ]
+
+ def init_scale_ns_data(self):
+ self.ns_scale_aspect = "TIC_EDGE_IMS"
+ self.ns_scale_steps = "1"
+ self.ns_scale_direction = "SCALE_IN"
+ self.scaleNsData = [{
+ "scaleNsByStepsData": [
+ {
+ "aspectId": self.ns_scale_aspect,
+ "numberOfSteps": self.ns_scale_steps,
+ "scalingDirection": self.ns_scale_direction
+ }
+ ]
+ }]
+
+ self.ns_scale_aspect2 = "TIC_EDGE_HW"
+ self.ns_scale_steps2 = "4"
+ self.scaleNsData2 = [{
+ "scaleNsByStepsData": [
+ {
+ "aspectId": self.ns_scale_aspect2,
+ "numberOfSteps": self.ns_scale_steps2,
+ "scalingDirection": self.ns_scale_direction
+ }
+ ]
+ }]
+
+ def init_scaling_map_json(self):
+ curdir_path = os.path.dirname(
+ os.path.dirname(
+ os.path.dirname(
+ os.path.abspath(__file__))))
+ filename = curdir_path + "/ns/data/scalemapping.json"
+ self.scaling_map_json = get_json_data(filename)
+
+ def initInstModel(self):
+ self.nsd_id = "23"
+ self.ns_inst_id = "1"
+ self.ns_name = "ns_1"
+ self.ns_package_id = "ns_zte"
+ self.description = "ns_zte"
+ self.global_customer_id = "global_customer_id"
+ self.service_type = "service_role"
+
+ 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(),
+ global_customer_id=self.global_customer_id,
+ service_type=self.service_type).save()
+
+ self.nf_inst_id = "231"
+ self.ns_inst_id = "1"
+ self.nf_name = "name_1"
+ self.vnf_id = "1"
+ self.vnfm_inst_id = "1"
+ self.package_id = "nf_zte_cscf"
+ self.nf_uuid = "abc34-345a-de13-ab85-ijs9"
+
+ NfInstModel.objects.create(
+ nfinstid=self.nf_inst_id,
+ nf_name=self.nf_name,
+ vnf_id=self.vnf_id,
+ vnfm_inst_id=self.vnfm_inst_id,
+ ns_inst_id=self.ns_inst_id,
+ max_cpu='14',
+ max_ram='12296',
+ max_hd='101',
+ max_shd="20",
+ max_net=10,
+ status='active',
+ mnfinstid=self.nf_uuid,
+ package_id=self.package_id,
+ 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"}}')
+
+ # Create a second vnf instance
+ self.nf_inst_id = "232"
+ self.package_id = "nf_zte_hss"
+ self.nf_uuid = "abc34-3g5a-de13-ab85-ijs3"
+
+ NfInstModel.objects.create(
+ nfinstid=self.nf_inst_id,
+ nf_name=self.nf_name,
+ vnf_id=self.vnf_id,
+ vnfm_inst_id=self.vnfm_inst_id,
+ ns_inst_id=self.ns_inst_id,
+ max_cpu='14',
+ max_ram='12296',
+ max_hd='101',
+ max_shd="20",
+ max_net=10,
+ status='active',
+ mnfinstid=self.nf_uuid,
+ package_id=self.package_id,
+ 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 add_another_nf_instance(self):
+ # Create a third vnf instance
+ nf_inst_id = "233"
+ package_id = "nf_zte_hss"
+ nf_uuid = "ab34-3g5j-de13-ab85-ij93"
+
+ NfInstModel.objects.create(
+ nfinstid=nf_inst_id,
+ nf_name=self.nf_name,
+ vnf_id=self.vnf_id,
+ vnfm_inst_id=self.vnfm_inst_id,
+ ns_inst_id=self.ns_inst_id,
+ max_cpu='14',
+ max_ram='12296',
+ max_hd='101',
+ max_shd="20",
+ max_net=10,
+ status='active',
+ mnfinstid=nf_uuid,
+ package_id=package_id,
+ 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 add_new_vnf_instance(self):
+ # Create a third vnf instance
+ nf_inst_id = "241"
+ package_id = "nf_hw_cscf"
+ nf_uuid = "ab34-3g5j-de13-aa85-ij93"
+
+ NfInstModel.objects.create(
+ nfinstid=nf_inst_id,
+ nf_name=self.nf_name,
+ vnf_id=self.vnf_id,
+ vnfm_inst_id=self.vnfm_inst_id,
+ ns_inst_id=self.ns_inst_id,
+ max_cpu='14',
+ max_ram='12296',
+ max_hd='101',
+ max_shd="20",
+ max_net=10,
+ status='active',
+ mnfinstid=nf_uuid,
+ package_id=package_id,
+ 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"}}')
+
+ # Create a third vnf instance
+ nf_inst_id = "242"
+ package_id = "nf_hw_hss"
+ nf_uuid = "ab34-3g5j-de13-aa85-id93"
+
+ NfInstModel.objects.create(
+ nfinstid=nf_inst_id,
+ nf_name=self.nf_name,
+ vnf_id=self.vnf_id,
+ vnfm_inst_id=self.vnfm_inst_id,
+ ns_inst_id=self.ns_inst_id,
+ max_cpu='14',
+ max_ram='12296',
+ max_hd='101',
+ max_shd="20",
+ max_net=10,
+ status='active',
+ mnfinstid=nf_uuid,
+ package_id=package_id,
+ 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().clean()
+ NfInstModel().clean()
+
+ def test_get_and_check_params(self):
+ aspect, numberOfSteps, scale_type = check_and_set_params(
+ self.scaleNsData, "1")
+ self.assertEqual(aspect, self.ns_scale_aspect)
+ self.assertEqual(numberOfSteps, self.ns_scale_steps)
+ self.assertEqual(scale_type, self.ns_scale_direction)
+
+ def test_get_scale_vnf_data_from_json(self):
+ vnf_data_package = get_scale_vnf_data_from_json(
+ self.scaling_map_json, "23", "TIC_EDGE_IMS", "1")
+ self.assertIsNotNone(vnf_data_package)
+ self.assertEqual(2, vnf_data_package.__len__())
+ self.assertIsNotNone(vnf_data_package)
+ self.assertEqual(2, vnf_data_package.__len__())
+ self.assertEqual("nf_zte_cscf", vnf_data_package[0]["vnfd_id"])
+ self.assertEqual("1", vnf_data_package[0]["numberOfSteps"])
+ self.assertEqual("gsu", vnf_data_package[0]["vnf_scaleAspectId"])
+ self.assertEqual("nf_zte_hss", vnf_data_package[1]["vnfd_id"])
+ self.assertEqual("3", vnf_data_package[1]["numberOfSteps"])
+ self.assertEqual("gpu", vnf_data_package[1]["vnf_scaleAspectId"])
+
+ def test_get_scale_vnf_data_from_json_2(self):
+ vnf_data_package = get_scale_vnf_data_from_json(
+ self.scaling_map_json, "23", "TIC_EDGE_IMS", "2")
+ self.assertIsNotNone(vnf_data_package)
+ self.assertEqual(2, vnf_data_package.__len__())
+ self.assertEqual("nf_zte_cscf", vnf_data_package[0]["vnfd_id"])
+ self.assertEqual("2", vnf_data_package[0]["numberOfSteps"])
+ self.assertEqual("mpu", vnf_data_package[0]["vnf_scaleAspectId"])
+ self.assertEqual("nf_zte_hss", vnf_data_package[1]["vnfd_id"])
+ self.assertEqual("4", vnf_data_package[1]["numberOfSteps"])
+ self.assertEqual("mpu", vnf_data_package[1]["vnf_scaleAspectId"])
+
+ def test_set_scacle_vnf_instance_id(self):
+ result = set_scacle_vnf_instance_id(self.vnf_scale_info_list)
+ self.assertEqual(2, result.__len__())
+ self.assertEqual(result[0]["numberOfSteps"],
+ self.vnf_scale_info_list[0]["numberOfSteps"])
+ self.assertEqual(
+ result[0]["vnf_scaleAspectId"],
+ self.vnf_scale_info_list[0]["vnf_scaleAspectId"])
+ self.assertEqual(result[1]["numberOfSteps"],
+ self.vnf_scale_info_list[1]["numberOfSteps"])
+ self.assertEqual(
+ result[1]["vnf_scaleAspectId"],
+ self.vnf_scale_info_list[1]["vnf_scaleAspectId"])
+ self.assertEqual("231", result[0]["vnfInstanceId"])
+ self.assertEqual("232", result[1]["vnfInstanceId"])
+ self.assertNotIn("vnfd_id", result[0])
+ self.assertNotIn("vnfd_id", result[1])
+
+ def test_set_scacle_vnf_instance_id_2(self):
+ vnf_scale_info_list = [
+ {
+ "vnfd_id": "error1",
+ "vnf_scaleAspectId": "mpu",
+ "numberOfSteps": "1"
+ },
+ {
+ "vnfd_id": "nf_zte_hss",
+ "vnf_scaleAspectId": "mpu",
+ "numberOfSteps": "1"
+ }
+ ]
+ result = set_scacle_vnf_instance_id(vnf_scale_info_list)
+ self.assertEqual(1, result.__len__())
+ self.assertEqual(
+ result[0]["numberOfSteps"],
+ vnf_scale_info_list[0]["numberOfSteps"])
+ self.assertEqual(
+ result[0]["vnf_scaleAspectId"],
+ vnf_scale_info_list[0]["vnf_scaleAspectId"])
+ self.assertEqual("232", result[0]["vnfInstanceId"])
+ self.assertNotIn("vnfd_id", result[0])
+
+ def test_set_scacle_vnf_instance_id_3(self):
+ vnf_scale_info_list = [
+ {
+ "vnfd_id": "error1",
+ "vnf_scaleAspectId": "mpu",
+ "numberOfSteps": "1"
+ },
+ {
+ "vnfd_id": "error2",
+ "vnf_scaleAspectId": "gsu",
+ "numberOfSteps": "1"
+ }
+ ]
+ result = set_scacle_vnf_instance_id(vnf_scale_info_list)
+ self.assertEqual(0, result.__len__())
+
+ def test_set_scacle_vnf_instance_id_4(self):
+ self.add_another_nf_instance()
+ result = set_scacle_vnf_instance_id(self.vnf_scale_info_list)
+ self.assertEqual(3, result.__len__())
+ self.assertEqual("231", result[0]["vnfInstanceId"])
+ self.assertEqual("232", result[1]["vnfInstanceId"])
+ self.assertEqual("233", result[2]["vnfInstanceId"])
+
+ def test_set_scaleVnfData_type(self):
+ vnf_scale_list = set_scacle_vnf_instance_id(self.vnf_scale_info_list)
+ result = set_scaleVnfData_type(vnf_scale_list, self.ns_scale_direction)
+ self.assertEqual(2, result.__len__())
+ self.assertNotIn("scaleByStepData", result)
+ self.assertEqual(
+ self.ns_scale_direction,
+ result[0]["scaleByStepData"]["type"])
+ self.assertEqual("mpu", result[0]["scaleByStepData"]["aspectId"])
+ self.assertNotIn("vnf_scaleAspectId", result[0]["scaleByStepData"])
+ self.assertEqual("1", result[0]["scaleByStepData"]["numberOfSteps"])
+ self.assertEqual(
+ self.ns_scale_direction,
+ result[1]["scaleByStepData"]["type"])
+ self.assertEqual("gsu", result[1]["scaleByStepData"]["aspectId"])
+ self.assertNotIn("vnf_scaleAspectId", result[1]["scaleByStepData"])
+ self.assertEqual("2", result[1]["scaleByStepData"]["numberOfSteps"])
+
+ def test_get_nsdId(self):
+ nsd_id = get_nsdId("1")
+ self.assertEqual("23", nsd_id)
+
+ @mock.patch.object(catalog, 'get_scalingmap_json_package')
+ def test_get_scale_vnf_data_info_list(
+ self, mock_get_scalingmap_json_package):
+ mock_get_scalingmap_json_package.return_value = self.scaling_map_json
+
+ scale_vnf_data = get_scale_vnf_data_info_list(self.scaleNsData, "1")
+ self.assertIsNotNone(scale_vnf_data)
+ self.assertEqual(2, scale_vnf_data.__len__())
+
+ @mock.patch.object(catalog, 'get_scalingmap_json_package')
+ def test_get_scale_vnf_data_info_list_2(
+ self, mock_get_scalingmap_json_package):
+ mock_get_scalingmap_json_package.return_value = self.scaling_map_json
+
+ scale_vnf_data = None
+ is_exception_caught = False
+ try:
+ scale_vnf_data = get_scale_vnf_data_info_list(
+ self.scaleNsData2, "1")
+ except Exception:
+ is_exception_caught = True
+ self.assertTrue(is_exception_caught)
+ self.assertIsNone(scale_vnf_data)
+
+ @mock.patch.object(catalog, 'get_scalingmap_json_package')
+ def test_get_scale_vnf_data_info_list_3(
+ self, mock_get_scalingmap_json_package):
+ mock_get_scalingmap_json_package.return_value = self.scaling_map_json
+ self.add_new_vnf_instance()
+
+ scale_vnf_data = None
+ is_exception_caught = False
+ try:
+ scale_vnf_data = get_scale_vnf_data_info_list(
+ self.scaleNsData2, "1")
+ except Exception:
+ is_exception_caught = True
+ self.assertFalse(is_exception_caught)
+ self.assertEqual(2, scale_vnf_data.__len__())
diff --git a/lcm/pub/utils/jobutil.py b/lcm/pub/utils/jobutil.py
index 7a8c5edc..69fa2866 100644
--- a/lcm/pub/utils/jobutil.py
+++ b/lcm/pub/utils/jobutil.py
@@ -113,7 +113,7 @@ class JobUtil(object):
job_status.status = "error"
job_status.descp = status_decs
- job_status.errcode = error_code
+ job_status.errcode = error_code if error_code else "0"
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,"
diff --git a/lcm/pub/utils/scaleaspect.py b/lcm/pub/utils/scaleaspect.py
index 0cd92168..cf78092f 100644
--- a/lcm/pub/utils/scaleaspect.py
+++ b/lcm/pub/utils/scaleaspect.py
@@ -15,19 +15,23 @@
import json
import logging
import os
+import copy
+from lcm.pub.database.models import NfInstModel
+from lcm.pub.database.models import NSInstModel
+from lcm.ns.vnfs.const import VNF_STATUS
+from lcm.pub.msapi import catalog
+
logger = logging.getLogger(__name__)
SCALE_TYPE = ("SCALE_NS", "SCALE_VNF")
scale_vnf_data_mapping = {
"vnfInstanceId": "",
- "scaleByStepData": [
- {
- "type": "",
- "aspectId": "",
- "numberOfSteps": ""
- }
- ]
+ "scaleByStepData": {
+ "type": "",
+ "aspectId": "",
+ "numberOfSteps": ""
+ }
}
@@ -49,7 +53,9 @@ def mapping_conv(keyword_map, rest_return):
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))
+ 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
@@ -62,15 +68,33 @@ def get_vnf_scale_info(filename, ns_instanceId, aspect, step):
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")
+ 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 ns_scale_info["vnf_scale_info"]
return None
+def get_vnf_instance_id_list(vnfd_id):
+ kwargs = {}
+ kwargs['package_id'] = vnfd_id
+ kwargs['status'] = VNF_STATUS.ACTIVE
+
+ nf_model_list = NfInstModel.objects.filter(**kwargs)
+ vnf_instance_id_list = list()
+ nf_model_len = nf_model_list.__len__()
+ if nf_model_len == 0:
+ logger.error("No VNF instances found(vnfd_id=%s)" % vnfd_id)
+ else:
+ for i in range(nf_model_len):
+ vnf_instance_id_list.append(nf_model_list[i].nfinstid)
+
+ return vnf_instance_id_list
+
+
def get_json_data(filename):
f = open(filename)
json_str = f.read()
@@ -80,35 +104,18 @@ def get_json_data(filename):
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))
+ if vnf_scale_list is None or vnf_scale_list.__len__() == 0:
+ 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):
+def get_scale_vnf_data_list(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)
@@ -116,31 +123,126 @@ def get_vnf_data(filename, ns_instanceId, aspect, step, 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)
+# Get the nsd id according to the ns instance id.
+def get_nsdId(ns_instanceId):
+ if NSInstModel.objects.filter(id=ns_instanceId):
+ nsd_id = NSInstModel.objects.filter(id=ns_instanceId)[0].nsd_id
+ return nsd_id
+
+ return None
-def get_and_check_params(scaleNsData, ns_InstanceId):
+def check_and_set_params(scaleNsData, ns_InstanceId):
if scaleNsData is None:
- pass
- # raise NSLCMException("Error! scaleNsData in the request is Empty!")
+ raise Exception("Error! scaleNsData in the request is Empty!")
- scaleNsByStepsData = scaleNsData[0]["scaleNsByStepsData"]
+ scaleNsByStepsData = scaleNsData[0]["scaleNsByStepsData"][0]
if scaleNsByStepsData is None:
- pass
- # raise NSLCMException("Error! scaleNsByStepsData in the request is Empty!")
+ raise Exception("Error! scaleNsByStepsData in the request is Empty!")
- aspect = scaleNsByStepsData[0]["aspectId"]
- numberOfSteps = scaleNsByStepsData[0]["numberOfSteps"]
- scale_type = scaleNsByStepsData[0]["scalingDirection"]
+ aspect = scaleNsByStepsData["aspectId"]
+ numberOfSteps = scaleNsByStepsData["numberOfSteps"]
+ scale_type = scaleNsByStepsData["scalingDirection"]
- return ns_InstanceId, aspect, numberOfSteps, scale_type
+ return 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__))))
+ 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)
+ aspect, numberOfSteps, scale_type = check_and_set_params(
+ scaleNsData, ns_InstanceId)
+ return get_scale_vnf_data_list(
+ filename,
+ ns_InstanceId,
+ aspect,
+ numberOfSteps,
+ scale_type)
+
+
+# Get scaling vnf data info list according to the ns instance id and request ScaleNsData.
+def get_scale_vnf_data_info_list(scaleNsData, ns_InstanceId):
+ # Gets the nsd id accordign to the ns instance id.
+ nsd_id = get_nsdId(ns_InstanceId)
+
+ # Gets the scalingmap json data from the package according to the ns instance id.
+ scalingmap_json = catalog.get_scalingmap_json_package(ns_InstanceId)
+
+ # Gets and checks the values of parameters.
+ aspect, numberOfSteps, scale_type = check_and_set_params(
+ scaleNsData, ns_InstanceId)
+
+ # Firstly, gets the scaling vnf data info list from the scaling map json data.
+ scale_vnf_data_info_list_from_json = get_scale_vnf_data_from_json(scalingmap_json, nsd_id, aspect, numberOfSteps)
+ check_scale_list(scale_vnf_data_info_list_from_json, ns_InstanceId, aspect, numberOfSteps)
+
+ # Secondly, adds the property of vnfInstanceId to the list according to the vnfd id.
+ scale_vnf_data_info_list = set_scacle_vnf_instance_id(scale_vnf_data_info_list_from_json)
+ check_scale_list(scale_vnf_data_info_list, ns_InstanceId, aspect, numberOfSteps)
+
+ # Lastly, adds the property of type to the list acoording to the request ScaleNsData.
+ scale_vnf_data_info_list = set_scaleVnfData_type(scale_vnf_data_info_list, scale_type)
+ check_scale_list(scale_vnf_data_info_list, ns_InstanceId, aspect, numberOfSteps)
+
+ return scale_vnf_data_info_list
+
+
+# Get the vnf scaling info from the scaling_map.json according to the ns package id.
+def get_scale_vnf_data_from_json(scalingmap_json, nsd_id, aspect, step):
+ scale_options = ignorcase_get(scalingmap_json, "scale_options")
+ for i in range(scale_options.__len__()):
+ ns_scale_option = scale_options[i]
+ if (ignorcase_get(ns_scale_option, "nsd_id") == nsd_id) and (
+ ignorcase_get(ns_scale_option, "ns_scale_aspect") == aspect):
+ ns_scale_info_list = ignorcase_get(
+ ns_scale_option, "ns_scale_info")
+ for j in range(ns_scale_info_list.__len__()):
+ ns_scale_info = ns_scale_info_list[j]
+ if ns_scale_info["step"] == step:
+ vnf_scale_info_list = ns_scale_info["vnf_scale_info"]
+
+ return vnf_scale_info_list
+
+ logger.error("get_scale_vnf_data_from_json method retuan null")
+ return None
+
+
+# Gets the vnf instance id according to the vnfd_id and modify the list of scaling vnf info accrodingly.
+def set_scacle_vnf_instance_id(vnf_scale_info_list):
+ scale_vnf_data_info_list = []
+ for i in range(vnf_scale_info_list.__len__()):
+ vnf_scale_info = vnf_scale_info_list[i]
+ vnfd_id = vnf_scale_info["vnfd_id"]
+ vnf_instance_id_list = get_vnf_instance_id_list(vnfd_id)
+ index = 0
+ while index < vnf_instance_id_list.__len__():
+ copy_vnf_scale_info = copy.deepcopy(vnf_scale_info)
+ copy_vnf_scale_info.pop("vnfd_id")
+ copy_vnf_scale_info["vnfInstanceId"] = vnf_instance_id_list[index]
+ index += 1
+ scale_vnf_data_info_list.append(copy_vnf_scale_info)
+
+ return scale_vnf_data_info_list
+
+
+# Sets the scaling type of vnf data info 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 = copy.deepcopy(scale_vnf_data_mapping)
+ scaleVnfData["vnfInstanceId"] = vnf_scale_list[i]["vnfInstanceId"]
+ scaleVnfData["scaleByStepData"]["type"] = scale_type
+ scaleVnfData["scaleByStepData"]["aspectId"] = vnf_scale_list[i]["vnf_scaleAspectId"]
+ scaleVnfData["scaleByStepData"]["numberOfSteps"] = vnf_scale_list[i]["numberOfSteps"]
+ scaleVnfDataList.append(scaleVnfData)
+ logger.debug("scaleVnfDataList = %s" % scaleVnfDataList)
+ return scaleVnfDataList
diff --git a/lcm/samples/serializers.py b/lcm/samples/serializers.py
new file mode 100644
index 00000000..c70561fa
--- /dev/null
+++ b/lcm/samples/serializers.py
@@ -0,0 +1,19 @@
+# Copyright 2018 ZTE Corporation.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+from rest_framework import serializers
+
+
+class RecordCountSerializer(serializers.Serializer):
+ count = serializers.CharField(help_text="Count of record", required=True)
diff --git a/lcm/samples/views.py b/lcm/samples/views.py
index cec3209e..5889aaca 100644
--- a/lcm/samples/views.py
+++ b/lcm/samples/views.py
@@ -18,8 +18,12 @@ import traceback
from rest_framework import status
from rest_framework.response import Response
from rest_framework.views import APIView
+from drf_yasg.utils import swagger_auto_schema
+
from lcm.pub.database import models
+from lcm.samples.serializers import RecordCountSerializer
+
logger = logging.getLogger(__name__)
@@ -27,6 +31,12 @@ class SampleList(APIView):
"""
List all samples.
"""
+ @swagger_auto_schema(
+ request_body=None,
+ responses={
+ status.HTTP_200_OK: "Status is active"
+ }
+ )
def get(self, request, format=None):
count = len(models.NSDModel.objects.filter())
logger.debug("get, count of NSDModel is %s", count)
@@ -34,6 +44,13 @@ class SampleList(APIView):
class TablesList(APIView):
+ @swagger_auto_schema(
+ request_body=None,
+ responses={
+ status.HTTP_204_NO_CONTENT: 'successful',
+ status.HTTP_500_INTERNAL_SERVER_ERROR: "Inner error"
+ }
+ )
def delete(self, request, modelName):
logger.debug("Start delete model %s", modelName)
try:
@@ -47,13 +64,24 @@ class TablesList(APIView):
return Response(data={"error": "failed"}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
return Response(data={}, status=status.HTTP_204_NO_CONTENT)
+ @swagger_auto_schema(
+ request_body=None,
+ responses={
+ status.HTTP_200_OK: RecordCountSerializer(),
+ status.HTTP_500_INTERNAL_SERVER_ERROR: "Inner error"
+ }
+ )
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:
+ resp_serializer = RecordCountSerializer(data={"count": count})
+ if not resp_serializer.is_valid():
+ raise Exception(resp_serializer.errors)
+ return Response(data=resp_serializer.data, status=status.HTTP_200_OK)
+ except Exception as e:
+ logger.error(e.message)
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)
+ return Response(data={"error": e.message}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
diff --git a/lcm/settings.py b/lcm/settings.py
index 9a095b3f..e5f680bb 100644
--- a/lcm/settings.py
+++ b/lcm/settings.py
@@ -19,7 +19,10 @@ 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
-from lcm.pub.config import config
+from lcm.pub.config import config as pub_config
+from logging import config as log_config
+from onaplogging import monkey
+monkey.patch_all()
# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
@@ -33,7 +36,7 @@ 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 = []
+ALLOWED_HOSTS = ['*']
# Application definition
@@ -45,10 +48,31 @@ INSTALLED_APPS = [
'django.contrib.staticfiles',
'rest_framework',
'lcm.pub.database',
- 'lcm.samples',
- 'lcm.swagger'
+ 'drf_yasg'
]
+TEMPLATES = [
+ {
+ 'BACKEND': 'django.template.backends.django.DjangoTemplates',
+ 'DIRS': [],
+ 'APP_DIRS': True,
+ 'OPTIONS': {
+ 'context_processors': [
+ 'django.template.context_processors.debug',
+ 'django.template.context_processors.request',
+ 'django.contrib.auth.context_processors.auth',
+ 'django.contrib.messages.context_processors.messages',
+ ],
+ },
+ },
+]
+
+SWAGGER_SETTINGS = {
+ 'LOGIN_URL': '/admin/login',
+ 'LOGOUT_URL': '/admin/logout',
+ 'DEFAULT_INFO': 'lcm.urls.swagger_info'
+}
+
MIDDLEWARE_CLASSES = [
'django.middleware.security.SecurityMiddleware',
'django.contrib.sessions.middleware.SessionMiddleware',
@@ -58,6 +82,7 @@ MIDDLEWARE_CLASSES = [
'django.contrib.auth.middleware.SessionAuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
+ 'lcm.middleware.LogContextMiddleware',
]
ROOT_URLCONF = 'lcm.urls'
@@ -102,42 +127,46 @@ STATICFILES_DIRS = [
os.path.join(BASE_DIR, "static")
]
-config.CATALOG_ROOT_PATH = os.path.join(STATICFILES_DIRS[0], "catalog")
-config.CATALOG_URL_PATH = "static/catalog"
-
-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
- },
- }
-}
+pub_config.CATALOG_ROOT_PATH = os.path.join(STATICFILES_DIRS[0], "catalog")
+pub_config.CATALOG_URL_PATH = "static/catalog"
+#
+# 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
+# },
+# }
+# }
+LOGGING_CONFIG = None
+# yaml configuration of logging
+LOGGING_FILE = os.path.join(BASE_DIR, 'lcm/log.yml')
+log_config.yamlConfig(filepath=LOGGING_FILE, watchDog=True)
if 'test' in sys.argv:
- config.REG_TO_MSB_WHEN_START = False
- config.DEPLOY_WORKFLOW_WHEN_START = False
+ pub_config.REG_TO_MSB_WHEN_START = False
+ pub_config.DEPLOY_WORKFLOW_WHEN_START = False
DATABASES = {}
DATABASES['default'] = {
'ENGINE': 'django.db.backends.sqlite3',
diff --git a/lcm/swagger/urls.py b/lcm/swagger/urls.py
index c3b8ad62..cb10cad6 100644
--- a/lcm/swagger/urls.py
+++ b/lcm/swagger/urls.py
@@ -11,13 +11,17 @@
# 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 django.conf.urls import url
+from lcm.swagger.views import SchemaView
from lcm.swagger.views import SwaggerJsonView
-urlpatterns = patterns('',
- url(r'^api/nslcm/v1/swagger.json$', SwaggerJsonView.as_view())
- )
-
-urlpatterns = format_suffix_patterns(urlpatterns)
+urlpatterns = [
+ url(r'^api/nslcm/v1/swagger.json$', SwaggerJsonView.as_view()),
+ url(r'^swagger(?P<format>.json|.yaml)$', SchemaView.without_ui(cache_timeout=0), name='schema-json'),
+ url(r'^swagger/$', SchemaView.with_ui('swagger', cache_timeout=0), name='schema-swagger-ui'),
+ url(r'^redoc/$', SchemaView.with_ui('redoc', cache_timeout=0), name='schema-redoc'),
+ url(r'^cached/swagger(?P<format>.json|.yaml)$', SchemaView.without_ui(cache_timeout=None), name='cschema-json'),
+ url(r'^cached/swagger/$', SchemaView.with_ui('swagger', cache_timeout=None), name='cschema-swagger-ui'),
+ url(r'^cached/redoc/$', SchemaView.with_ui('redoc', cache_timeout=None), name='cschema-redoc'),
+]
diff --git a/lcm/swagger/vfc.nslcm.swagger.json b/lcm/swagger/vfc.nslcm.swagger.json
index e8a83905..891e1789 100644
--- a/lcm/swagger/vfc.nslcm.swagger.json
+++ b/lcm/swagger/vfc.nslcm.swagger.json
@@ -166,7 +166,7 @@
}
}
},
- "/ns/{ns_instance_id}/heal": {
+ "/ns/{nsInstanceId}/heal": {
"post": {
"tags": [
"ns"
@@ -179,7 +179,7 @@
"required": true,
"type": "string",
"description": "Identifier of the NS instance.",
- "name": "ns_instance_id",
+ "name": "nsInstanceId",
"in": "path"
},
{
@@ -208,7 +208,7 @@
}
}
},
- "/ns/{ns_instance_id}/terminate": {
+ "/ns/{nsInstanceId}/terminate": {
"post": {
"tags": [
"ns"
@@ -221,7 +221,7 @@
"required": true,
"type": "string",
"description": "Identifier of the NS instance.",
- "name": "ns_instance_id",
+ "name": "nsInstanceId",
"in": "path"
},
{
@@ -247,7 +247,7 @@
}
}
},
- "/ns/{ns_instance_id}": {
+ "/ns/{nsInstanceId}": {
"get": {
"tags": [
"ns"
@@ -255,7 +255,15 @@
"summary": "ns get",
"description": "ns get",
"operationId": "ns_instance_get",
- "parameters": [],
+ "parameters": [
+ {
+ "required": true,
+ "type": "string",
+ "description": "Identifier of the NS instance.",
+ "name": "nsInstanceId",
+ "in": "path"
+ }
+ ],
"responses": {
"200": {
"description": "successful operation",
@@ -277,7 +285,7 @@
"required": true,
"type": "string",
"description": "Identifier of the NS instance.",
- "name": "ns_instance_id",
+ "name": "nsInstanceId",
"in": "path"
}
],
diff --git a/lcm/swagger/vfc.vnfdriver.swagger.json b/lcm/swagger/vfc.vnfdriver.swagger.json
index 52f94c5e..fc35adbd 100644
--- a/lcm/swagger/vfc.vnfdriver.swagger.json
+++ b/lcm/swagger/vfc.vnfdriver.swagger.json
@@ -951,17 +951,30 @@
"extVirtualLinkInfo":{
"type": "object",
"properties": {
+ "resourceSubnetId": {
+ "type": "string",
+ "description": "The provider id of the subnet"
+ },
"vlInstanceId": {
- "type": "string"
+ "type": "string",
+ "description" : "The identifier of the virtual link"
},
- "networkId": {
- "type": "string"
+ "resourceId": {
+ "type": "string",
+ "description": "The provider id of the network"
},
"cpdId": {
- "type": "string"
+ "type": "string",
+ "description": "The identifier of the connection point descriptor"
},
"vim": {
- "$ref": "#/definitions/vimInfo"
+ "type": "object",
+ "properties": {
+ "vimid": {
+ "type": "string",
+ "description": "The identifier of the VIM"
+ }
+ }
}
}
},
diff --git a/lcm/swagger/views.py b/lcm/swagger/views.py
index e78ecead..5f087f8c 100644
--- a/lcm/swagger/views.py
+++ b/lcm/swagger/views.py
@@ -17,10 +17,19 @@ import os
from rest_framework.response import Response
from rest_framework.views import APIView
+from rest_framework import permissions
+from drf_yasg.views import get_schema_view
logger = logging.getLogger(__name__)
+SchemaView = get_schema_view(
+ validators=['ssv', 'flex'],
+ public=True,
+ permission_classes=(permissions.AllowAny,),
+)
+
+
class SwaggerJsonView(APIView):
def get(self, request):
diff --git a/lcm/urls.py b/lcm/urls.py
index 5e647260..eb82f083 100644
--- a/lcm/urls.py
+++ b/lcm/urls.py
@@ -13,9 +13,21 @@
# limitations under the License.
from django.conf.urls import include, url
+from drf_yasg import openapi
+
from lcm.pub.config.config import REG_TO_MSB_WHEN_START, REG_TO_MSB_REG_URL, REG_TO_MSB_REG_PARAM
from lcm.pub.config.config import DEPLOY_WORKFLOW_WHEN_START
+swagger_info = openapi.Info(
+ title="vfc-nfvo-lcm API",
+ default_version='v1',
+ description="""
+
+The `swagger-ui` view can be found [here](/cached/swagger).
+The `ReDoc` view can be found [here](/cached/redoc).
+The swagger YAML document can be found [here](/cached/swagger.yaml)."""
+)
+
urlpatterns = [
url(r'^', include('lcm.samples.urls')),
url(r'^', include('lcm.packages.urls')),
@@ -26,6 +38,7 @@ urlpatterns = [
url(r'^', include('lcm.jobs.urls')),
url(r'^', include('lcm.workflows.urls')),
url(r'^', include('lcm.swagger.urls')),
+ url(r'^', include('lcm.v2.urls')),
]
# regist to MSB when startup
diff --git a/lcm/v2/__init__.py b/lcm/v2/__init__.py
new file mode 100644
index 00000000..342c2a8c
--- /dev/null
+++ b/lcm/v2/__init__.py
@@ -0,0 +1,13 @@
+# Copyright 2018 ZTE Corporation.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
diff --git a/lcm/v2/grant_vnf.py b/lcm/v2/grant_vnf.py
new file mode 100644
index 00000000..a3ba37f9
--- /dev/null
+++ b/lcm/v2/grant_vnf.py
@@ -0,0 +1,35 @@
+# Copyright 2018 ZTE Corporation.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import json
+import logging
+import uuid
+
+logger = logging.getLogger(__name__)
+
+
+class GrantVnf(object):
+ def __init__(self, grant_data):
+ self.data = grant_data
+
+ def exec_grant(self):
+ if isinstance(self.data, (unicode, str)):
+ self.data = json.JSONDecoder().decode(self.data)
+ grant_resp = {
+ "id": str(uuid.uuid4()),
+ "vnfInstanceId": self.data.get("vnfInstanceId"),
+ "vnfLcmOpOccId": self.data.get("vnfLcmOpOccId")
+ }
+ logger.debug("grant_resp=%s", grant_resp)
+ return grant_resp
diff --git a/lcm/v2/serializers.py b/lcm/v2/serializers.py
new file mode 100644
index 00000000..557c603c
--- /dev/null
+++ b/lcm/v2/serializers.py
@@ -0,0 +1,1001 @@
+# Copyright 2018 ZTE Corporation.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+from rest_framework import serializers
+
+
+class ResourceHandleSerializer(serializers.Serializer):
+ vimConnectionId = serializers.CharField(
+ help_text="Identifier of the VIM connection to manage the resource.",
+ required=False,
+ allow_null=True,
+ allow_blank=True
+ )
+ resourceProviderId = serializers.CharField(
+ help_text="Identifier of the entity responsible for the management of the resource.",
+ required=False,
+ allow_null=True,
+ allow_blank=True
+ )
+ resourceId = serializers.CharField(
+ help_text="Identifier of the resource in the scope of the VIM or the resource provider.",
+ required=True
+ )
+ vimLevelResourceType = serializers.CharField(
+ help_text="Type of the resource in the scope of the VIM or the resource provider.",
+ required=False,
+ allow_null=True,
+ allow_blank=True
+ )
+
+
+class ResourceDefinitionSerializer(serializers.Serializer):
+ id = serializers.CharField(
+ help_text="Identifier of this ResourceDefinition, unique at least within the scope of the GrantRequest.",
+ required=True
+ )
+ type = serializers.ChoiceField(
+ help_text="Type of the resource definition referenced.",
+ choices=["COMPUTE", "VL", "STORAGE", "LINKPORT"],
+ required=True
+ )
+ vduId = serializers.CharField(
+ help_text="Reference to the related VDU in the VNFD applicable to this resource.",
+ required=False,
+ allow_null=True,
+ allow_blank=True
+ )
+ resourceTemplateId = serializers.CharField(
+ help_text="Reference to a resource template(such as VnfVirtualLinkDesc) in the VNFD.",
+ required=False,
+ allow_null=True,
+ allow_blank=True
+ )
+ resource = ResourceHandleSerializer(
+ help_text="Resource information for an existing resource.",
+ required=False,
+ allow_null=True
+ )
+
+
+class ConstraintResourceRefSerializer(serializers.Serializer):
+ idType = serializers.ChoiceField(
+ help_text="The type of the identifier.",
+ choices=["RES_MGMT", "GRANT"],
+ required=True
+ )
+ resourceId = serializers.CharField(
+ help_text="An actual resource-management-level identifier(idType=RES_MGMT), or an identifier that references a ResourceDefinition(idType=GRANT).",
+ required=True
+ )
+ vimConnectionId = serializers.CharField(
+ help_text="",
+ required=False,
+ allow_null=True,
+ allow_blank=True
+ )
+ resourceProviderId = serializers.CharField(
+ help_text="Identifier of the resource provider. It shall only be present when idType = RES_MGMT.",
+ required=False,
+ allow_null=True,
+ allow_blank=True
+ )
+
+
+class PlacementConstraintSerializer(serializers.Serializer):
+ affinityOrAntiAffinity = serializers.ChoiceField(
+ help_text="The type of the constraint.",
+ choices=["AFFINITY", "ANTI_AFFINITY"],
+ required=True
+ )
+ scope = serializers.ChoiceField(
+ help_text="The scope of the placement constraint indicating the category of the place where the constraint applies.",
+ choices=["NFVI_POP", "ZONE", "ZONE_GROUP", "NFVI_NODE"],
+ required=True
+ )
+ resource = ConstraintResourceRefSerializer(
+ help_text="References to resources in the constraint rule.",
+ many=True,
+ required=False
+ )
+
+
+class VimConstraintSerializer(serializers.Serializer):
+ sameResourceGroup = serializers.BooleanField(
+ help_text="Set to true when the constraint applies not only to the same VIM connection, but also to the same infrastructure resource group.",
+ required=False
+ )
+ resource = ConstraintResourceRefSerializer(
+ help_text="References to resources in the constraint rule.",
+ many=True,
+ required=False
+ )
+
+
+class LinkSerializer(serializers.Serializer):
+ href = serializers.CharField(
+ help_text="URI of the referenced resource.",
+ required=True
+ )
+
+
+class GrantRequestLinksSerializer(serializers.Serializer):
+ vnfLcmOpOcc = LinkSerializer(
+ help_text="Related VNF lifecycle management operation occurrence.",
+ required=True
+ )
+ vnfInstance = LinkSerializer(
+ help_text="Related VNF instance.",
+ required=True
+ )
+
+
+class GrantRequestSerializer(serializers.Serializer):
+ vnfInstanceId = serializers.CharField(
+ help_text="Identifier of the VNF instance which this grant request is related to.",
+ required=True
+ )
+ vnfLcmOpOccId = serializers.CharField(
+ help_text="The identifier of the VNF lifecycle management operation occurrence associated to the GrantRequest.",
+ required=False,
+ allow_null=True,
+ allow_blank=True
+ )
+ vnfdId = serializers.CharField(
+ help_text="Identifier of the VNFD that defines the VNF for which the LCM operation is to be granted.",
+ required=False,
+ allow_null=True,
+ allow_blank=True
+ )
+ flavourId = serializers.CharField(
+ help_text="Identifier of the VNF deployment flavour of the VNFD that defines the VNF for which the LCM operation is to be granted.",
+ required=False,
+ allow_null=True,
+ allow_blank=True
+ )
+ operation = serializers.ChoiceField(
+ help_text="The lifecycle management operation for which granting is requested.",
+ choices=["INSTANTIATE", "SCALE", "SCALE_TO_LEVEL", "CHANGE_FLAVOUR", "TERMINATE", "HEAL", "OPERATE", "OPERATE", "CHANGE_EXT_CONN", "MODIFY_INFO"],
+ required=True
+ )
+ isAutomaticInvocation = serializers.BooleanField(
+ help_text="Set to true if this VNF LCM operation occurrence has been triggered by an automated procedure inside the VNFM, set to false otherwise.",
+ required=True
+ )
+ instantiationLevelId = serializers.CharField(
+ help_text="If operation=INSTANTIATE, the identifier of the instantiation level may be provided as an alternative way to define the resources to be added.",
+ required=False,
+ allow_null=True,
+ allow_blank=True
+ )
+ addResources = ResourceDefinitionSerializer(
+ help_text="List of resource definitions in the VNFD for resources to be added by the LCM operation.",
+ many=True,
+ required=False
+ )
+ tempResources = ResourceDefinitionSerializer(
+ help_text="List of resource definitions in the VNFD for resources to be temporarily instantiated during the runtime of the LCM operation.",
+ many=True,
+ required=False
+ )
+ removeResources = ResourceDefinitionSerializer(
+ help_text="Provides the definitions of resources to be removed by the LCM operation.",
+ many=True,
+ required=False
+ )
+ updateResources = ResourceDefinitionSerializer(
+ help_text="Provides the definitions of resources to be modified by the LCM operation.",
+ many=True,
+ required=False
+ )
+ placementConstraints = PlacementConstraintSerializer(
+ help_text="Placement constraints that the VNFM may send to the NFVO in order to influence the resource placement decision.",
+ many=True,
+ required=False
+ )
+ vimConstraints = VimConstraintSerializer(
+ help_text="Used by the VNFM to require that multiple resources are managed through the same VIM connection.",
+ many=True,
+ required=False
+ )
+ additionalParams = serializers.DictField(
+ help_text="Additional parameters passed by the VNFM.",
+ child=serializers.CharField(help_text="KeyValue Pairs", allow_blank=True),
+ required=False,
+ allow_null=True
+ )
+ _links = GrantRequestLinksSerializer(
+ help_text="Links to resources related to this request.",
+ required=False
+ )
+
+
+class VimConnectionInfoSerializer(serializers.Serializer):
+ id = serializers.CharField(
+ help_text="The identifier of the VIM Connection. This identifier is managed by the NFVO.",
+ required=True
+ )
+ vimId = serializers.CharField(
+ help_text="The identifier of the VIM instance. This identifier is managed by the NFVO.",
+ required=False,
+ allow_null=True,
+ allow_blank=True
+ )
+ vimType = serializers.CharField(
+ help_text="Discriminator for the different types of the VIM information.",
+ required=False,
+ allow_null=True,
+ allow_blank=True
+ )
+ interfaceInfo = serializers.DictField(
+ help_text="Information about the interface or interfaces to the VIM.",
+ child=serializers.CharField(help_text="Interface Info", allow_blank=True),
+ required=False,
+ allow_null=True
+ )
+ accessInfo = serializers.DictField(
+ help_text="Authentication credentials for accessing the VIM.",
+ child=serializers.CharField(help_text="Access Info", allow_blank=True),
+ required=False,
+ allow_null=True
+ )
+ extra = serializers.DictField(
+ help_text="VIM type specific additional information.",
+ child=serializers.CharField(help_text="Extra", allow_blank=True),
+ required=False,
+ allow_null=True
+ )
+
+
+class ZoneInfoSerializer(serializers.Serializer):
+ id = serializers.CharField(
+ help_text="The identifier of this ZoneInfo instance, for the purpose of referencing it from other structures in the Grant structure.",
+ required=True
+ )
+ zoneId = serializers.CharField(
+ help_text="The identifier of the resource zone, as managed by the resource management layer(typically, the VIM).",
+ required=False,
+ allow_null=True,
+ allow_blank=True
+ )
+ vimConnectionId = serializers.CharField(
+ help_text="Identifier of the connection to the VIM that manages the resource zone.",
+ required=False,
+ allow_null=True,
+ allow_blank=True
+ )
+ resourceProviderId = serializers.CharField(
+ help_text="Identifies the entity responsible for the management the resource zone.",
+ required=False,
+ allow_null=True,
+ allow_blank=True
+ )
+
+
+class ZoneGroupInfoSerializer(serializers.Serializer):
+ zoneId = serializers.ListSerializer(
+ help_text="References of identifiers of ZoneInfo structures.",
+ child=serializers.CharField(help_text="IdentifierLocal", allow_blank=True),
+ required=False,
+ allow_null=True
+ )
+
+
+class GrantInfoSerializer(serializers.Serializer):
+ resourceDefinitionId = serializers.CharField(
+ help_text="Identifier of the related ResourceDefinition from the related GrantRequest.",
+ required=True
+ )
+ reservationId = serializers.CharField(
+ help_text="The reservation identifier applicable to the VNFC/VirtualLink/VirtualStorage.",
+ required=False,
+ allow_null=True,
+ allow_blank=True
+ )
+ vimConnectionId = serializers.CharField(
+ help_text="Identifier of the VIM connection to be used to manage this resource.",
+ required=False,
+ allow_null=True,
+ allow_blank=True
+ )
+ resourceProviderId = serializers.CharField(
+ help_text="Identifies the entity responsible for the management of the virtualised resource.",
+ required=False,
+ allow_null=True,
+ allow_blank=True
+ )
+ zoneId = serializers.CharField(
+ help_text="Reference to the identifier of the ZoneInfo in the Grant.",
+ required=False,
+ allow_null=True,
+ allow_blank=True
+ )
+ resourceGroupId = serializers.CharField(
+ help_text="Identifier of the infrastructure resource group.",
+ required=False,
+ allow_null=True,
+ allow_blank=True
+ )
+
+
+class VimComputeResourceFlavourSerializer(serializers.Serializer):
+ vimConnectionId = serializers.CharField(
+ help_text="Identifier of the VIM connection to access the flavour referenced in this structure.",
+ required=False,
+ allow_null=True,
+ allow_blank=True
+ )
+ resourceProviderId = serializers.CharField(
+ help_text="Identifies the entity responsible for the management of the virtualised resource.",
+ required=False,
+ allow_null=True,
+ allow_blank=True
+ )
+ vnfdVirtualComputeDescId = serializers.CharField(
+ help_text="Identifier which references the virtual compute descriptor in the VNFD that maps to this flavour.",
+ required=False,
+ allow_null=True,
+ allow_blank=True
+ )
+ vimFlavourId = serializers.CharField(
+ help_text="Identifier of the compute resource flavour in the resource management layer (i.e. VIM).",
+ required=False,
+ allow_null=True,
+ allow_blank=True
+ )
+
+
+class VimSoftwareImageSerializer(serializers.Serializer):
+ vimConnectionId = serializers.CharField(
+ help_text="Identifier of the VIM connection to access the flavour referenced in this structure.",
+ required=False,
+ allow_null=True,
+ allow_blank=True
+ )
+ resourceProviderId = serializers.CharField(
+ help_text="Identifies the entity responsible for the management of the virtualised resource.",
+ required=False,
+ allow_null=True,
+ allow_blank=True
+ )
+ vnfdSoftwareImageId = serializers.CharField(
+ help_text="Identifier which references the software image descriptor in the VNFD.",
+ required=False,
+ allow_null=True,
+ allow_blank=True
+ )
+ vimSoftwareImageId = serializers.CharField(
+ help_text="Identifier of the software image in the resource management layer (i.e. VIM).",
+ required=False,
+ allow_null=True,
+ allow_blank=True
+ )
+
+
+class VimAssetsSerializer(serializers.Serializer):
+ computeResourceFlavours = VimComputeResourceFlavourSerializer(
+ help_text="Mappings between virtual compute descriptors defined in the VNFD and compute resource flavours managed in the VIM.",
+ many=True,
+ required=False
+ )
+ softwareImages = VimSoftwareImageSerializer(
+ help_text="Mappings between software images defined in the VNFD and software images managed in the VIM.",
+ many=True,
+ required=False
+ )
+
+
+class AddressRangeSerializer(serializers.Serializer):
+ minAddress = serializers.CharField(
+ help_text="Lowest IP address belonging to the range.",
+ required=True
+ )
+ maxAddress = serializers.CharField(
+ help_text="Highest IP address belonging to the range.",
+ required=True
+ )
+
+
+class IpAddresseSerializer(serializers.Serializer):
+ type = serializers.ChoiceField(
+ help_text="The type of the IP addresses.",
+ choices=["IPV4", "IPV6"],
+ required=True
+ )
+ fixedAddresses = serializers.ListSerializer(
+ help_text="Fixed addresses to assign.",
+ child=serializers.CharField(help_text="IpAddress"),
+ required=False,
+ allow_null=True
+ )
+ numDynamicAddresses = serializers.IntegerField(
+ help_text="Number of dynamic addresses to assign.",
+ required=True
+ )
+ addressRange = AddressRangeSerializer(
+ help_text="An IP address range to be used, e.g. in case of egress connections.",
+ required=False,
+ allow_null=True
+ )
+ subnetId = serializers.CharField(
+ help_text="Subnet defined by the identifier of the subnet resource in the VIM.",
+ required=False,
+ allow_null=True,
+ allow_blank=True
+ )
+
+
+class IpOverEthernetAddressDataSerializer(serializers.Serializer):
+ macAddress = serializers.CharField(
+ help_text="MAC address.",
+ required=False,
+ allow_null=True,
+ allow_blank=True
+ )
+ ipAddresses = IpAddresseSerializer(
+ help_text="List of IP addresses to assign to the CP instance.",
+ many=True,
+ required=False
+ )
+
+
+class CpProtocolDataSerializer(serializers.Serializer):
+ layerProtocol = serializers.ChoiceField(
+ help_text="Identifier of layer(s) and protocol(s).",
+ choices=["IP_OVER_ETHERNET"],
+ required=True
+ )
+ ipOverEthernet = IpOverEthernetAddressDataSerializer(
+ help_text="Network address data for IP over Ethernet to assign to the extCP instance.",
+ required=False,
+ allow_null=True,
+ )
+
+
+class VnfExtCpConfigSerializer(serializers.Serializer):
+ cpInstanceId = serializers.CharField(
+ help_text="Identifier of the external CP instance to which this set of configuration parameters is requested to be applied.",
+ required=False,
+ allow_null=True,
+ allow_blank=True
+ )
+ linkPortId = serializers.CharField(
+ help_text="Identifier of a pre-configured link port to which the external CP will be associated.",
+ required=False,
+ allow_null=True,
+ allow_blank=True
+ )
+ cpProtocolData = CpProtocolDataSerializer(
+ help_text="Parameters for configuring the network protocols on the link port that connects the CP to a VL.",
+ many=True,
+ required=False
+ )
+
+
+class VnfExtCpDataSerializer(serializers.Serializer):
+ cpdId = serializers.CharField(
+ help_text="The identifier of the CPD in the VNFD.",
+ required=True
+ )
+ cpConfig = VnfExtCpConfigSerializer(
+ help_text="List of instance data that need to be configured on the CP instances created from the respective CPD.",
+ many=True,
+ required=False
+ )
+
+
+class ExtLinkPortDataSerializer(serializers.Serializer):
+ id = serializers.CharField(
+ help_text="Identifier of this link port as provided by the entity that has created the link port.",
+ required=True
+ )
+ resourceHandle = serializers.CharField(
+ help_text="Reference to the virtualised resource realizing this link port.",
+ required=True
+ )
+
+
+class ExtVirtualLinkDataSerializer(serializers.Serializer):
+ id = serializers.CharField(
+ help_text="The identifier of the external VL instance.",
+ required=True
+ )
+ vimConnectionId = serializers.CharField(
+ help_text="Identifier of the VIM connection to manage this resource.",
+ required=False,
+ allow_null=True,
+ allow_blank=True
+ )
+ resourceProviderId = serializers.CharField(
+ help_text="Identifies the entity responsible for the management of this resource.",
+ required=False,
+ allow_null=True,
+ allow_blank=True
+ )
+ resourceId = serializers.CharField(
+ help_text="The identifier of the resource in the scope of the VIM or the resource provider.",
+ required=True
+ )
+ extCps = VnfExtCpDataSerializer(
+ help_text="External CPs of the VNF to be connected to this external VL.",
+ many=True,
+ required=False
+ )
+ extLinkPorts = ExtLinkPortDataSerializer(
+ help_text="Externally provided link ports to be used to connect external connection points to this external VL.",
+ many=True,
+ required=False
+ )
+
+
+class ExtManagedVirtualLinkDataSerializer(serializers.Serializer):
+ id = serializers.CharField(
+ help_text="The identifier of the externally-managed internal VL instance.",
+ required=True
+ )
+ virtualLinkDescId = serializers.CharField(
+ help_text="The identifier of the VLD in the VNFD for this VL.",
+ required=True
+ )
+ vimConnectionId = serializers.CharField(
+ help_text="Identifier of the VIM connection to manage this resource.",
+ required=False,
+ allow_null=True,
+ allow_blank=True
+ )
+ resourceProviderId = serializers.CharField(
+ help_text="Identifies the entity responsible for the management of this resource.",
+ required=False,
+ allow_null=True,
+ allow_blank=True
+ )
+ resourceId = serializers.CharField(
+ help_text="The identifier of the resource in the scope of the VIM or the resource provider.",
+ required=True
+ )
+
+
+class GrantLinksSerializer(serializers.Serializer):
+ self = LinkSerializer(
+ help_text="URI of this resource.",
+ required=True
+ )
+ vnfLcmOpOcc = LinkSerializer(
+ help_text="Related VNF lifecycle management operation occurrence.",
+ required=True
+ )
+ vnfInstance = LinkSerializer(
+ help_text="Related VNF instance.",
+ required=True
+ )
+
+
+class GrantSerializer(serializers.Serializer):
+ id = serializers.CharField(
+ help_text="Identifier of the grant.",
+ required=True
+ )
+ vnfInstanceId = serializers.CharField(
+ help_text="Identifier of the related VNF instance.",
+ required=True
+ )
+ vnfLcmOpOccId = serializers.CharField(
+ help_text="Identifier of the related VNF lifecycle management operation occurrence.",
+ required=False,
+ allow_null=True,
+ allow_blank=True
+ )
+ vimConnections = VimConnectionInfoSerializer(
+ help_text="Provides information regarding VIM connections that are approved to be used by the VNFM to allocate resources.",
+ many=True,
+ required=False
+ )
+ zones = ZoneInfoSerializer(
+ help_text="Identifies resource zones where the resources are approved to be allocated by the VNFM.",
+ many=True,
+ required=False
+ )
+ zoneGroups = ZoneGroupInfoSerializer(
+ help_text="Information about groups of resource zones.",
+ many=True,
+ required=False
+ )
+ computeReservationId = serializers.CharField(
+ help_text="Information that identifies a reservation applicable to the compute resource requirements.",
+ required=False,
+ allow_null=True,
+ allow_blank=True
+ )
+ networkReservationId = serializers.CharField(
+ help_text="Information that identifies a reservation applicable to the network resource requirements.",
+ required=False,
+ allow_null=True,
+ allow_blank=True
+ )
+ storageReservationId = serializers.CharField(
+ help_text="Information that identifies a reservation applicable to the storage resource requirements.",
+ required=False,
+ allow_null=True,
+ allow_blank=True
+ )
+ addResources = GrantInfoSerializer(
+ help_text="List of resources that are approved to be added.",
+ many=True,
+ required=False
+ )
+ tempResources = GrantInfoSerializer(
+ help_text="List of resources that are approved to be temporarily instantiated during the runtime of the lifecycle operation.",
+ many=True,
+ required=False
+ )
+ removeResources = GrantInfoSerializer(
+ help_text="List of resources that are approved to be removed.",
+ many=True,
+ required=False
+ )
+ updateResources = GrantInfoSerializer(
+ help_text="List of resources that are approved to be modified.",
+ many=True,
+ required=False
+ )
+ vimAssets = VimAssetsSerializer(
+ help_text="Information about assets for the VNF that are managed by the NFVO in the VIM.",
+ required=False,
+ allow_null=True
+ )
+ extVirtualLinks = ExtVirtualLinkDataSerializer(
+ help_text="Information about external VLs to connect the VNF to.",
+ many=True,
+ required=False
+ )
+ extManagedVirtualLinks = ExtManagedVirtualLinkDataSerializer(
+ help_text="Information about internal VLs that are managed by other entities than the VNFM.",
+ many=True,
+ required=False
+ )
+ _links = GrantLinksSerializer(
+ help_text="Links to resources related to this resource.",
+ required=False
+ )
+
+
+class AffectedVnfcSerializer(serializers.Serializer):
+ id = serializers.CharField(
+ help_text="Identifier of the Vnfc instance.",
+ required=True
+ )
+ vduId = serializers.CharField(
+ help_text="Identifier of the related VDU in the VNFD.",
+ required=True
+ )
+ changeType = serializers.ChoiceField(
+ help_text="Signals the type of change.",
+ choices=["ADDED", "REMOVED", "MODIFIED", "TEMPORARY"],
+ required=True
+ )
+ computeResource = ResourceHandleSerializer(
+ help_text="Reference to the VirtualCompute resource.",
+ required=True
+ )
+ metadata = serializers.DictField(
+ help_text="Metadata about this resource.",
+ child=serializers.CharField(help_text="KeyValue Pairs", allow_blank=True),
+ required=False,
+ allow_null=True
+ )
+ affectedVnfcCpIds = serializers.ListSerializer(
+ help_text="Identifiers of CP(s) of the VNFC instance that were affected by the change.",
+ child=serializers.CharField(help_text="Identifier In Vnf", allow_blank=True),
+ required=False,
+ allow_null=True
+ )
+ addedStorageResourceIds = serializers.ListSerializer(
+ help_text="References to VirtualStorage resources that have been added.",
+ child=serializers.CharField(help_text="Identifier In Vnf", allow_blank=True),
+ required=False,
+ allow_null=True
+ )
+ removedStorageResourceIds = serializers.ListSerializer(
+ help_text="References to VirtualStorage resources that have been removed.",
+ child=serializers.CharField(help_text="Identifier In Vnf", allow_blank=True),
+ required=False,
+ allow_null=True
+ )
+
+
+class AffectedVirtualLinkSerializer(serializers.Serializer):
+ id = serializers.CharField(
+ help_text="Identifier of the virtual link instance.",
+ required=True
+ )
+ virtualLinkDescId = serializers.CharField(
+ help_text="Identifier of the related VLD in the VNFD.",
+ required=True
+ )
+ changeType = serializers.ChoiceField(
+ help_text="Signals the type of change.",
+ choices=["ADDED", "REMOVED", "MODIFIED", "TEMPORARY", "LINK_PORT_ADDED", "LINK_PORT_REMOVED"],
+ required=True
+ )
+ networkResource = ResourceHandleSerializer(
+ help_text="Reference to the VirtualNetwork resource.",
+ required=False,
+ allow_null=True
+ )
+ metadata = serializers.DictField(
+ help_text="Metadata about this resource.",
+ child=serializers.CharField(help_text="KeyValue Pairs", allow_blank=True),
+ required=False,
+ allow_null=True
+ )
+
+
+class AffectedVirtualStorageSerializer(serializers.Serializer):
+ id = serializers.CharField(
+ help_text="Identifier of the storage instance.",
+ required=True
+ )
+ virtualStorageDescId = serializers.CharField(
+ help_text="Identifier of the related VirtualStorage descriptor in the VNFD.",
+ required=True
+ )
+ changeType = serializers.ChoiceField(
+ help_text="Signals the type of change.",
+ choices=["ADDED", "REMOVED", "MODIFIED", "TEMPORARY"],
+ required=True
+ )
+ storageResource = ResourceHandleSerializer(
+ help_text="Reference to the VirtualStorage resource.",
+ required=False,
+ allow_null=True
+ )
+ metadata = serializers.DictField(
+ help_text="Metadata about this resource.",
+ child=serializers.CharField(help_text="KeyValue Pairs", allow_blank=True),
+ required=False,
+ allow_null=True
+ )
+
+
+class VnfInfoModificationsSerializer(serializers.Serializer):
+ vnfInstanceName = serializers.CharField(
+ help_text="If present, this attribute signals modifications of the vnfInstanceName attribute in VnfInstance.",
+ required=False,
+ allow_null=True,
+ allow_blank=True
+ )
+ vnfInstanceDescription = serializers.CharField(
+ help_text="If present, this attribute signals modifications of the vnfInstanceDescription attribute in VnfInstance.",
+ required=False,
+ allow_null=True,
+ allow_blank=True
+ )
+ vnfConfigurableProperties = serializers.DictField(
+ help_text="If present, this attribute signals modifications of the vnfConfigurableProperties attribute in VnfInstance.",
+ child=serializers.CharField(help_text="KeyValue Pairs", allow_blank=True),
+ required=False,
+ allow_null=True
+ )
+ metadata = serializers.DictField(
+ help_text="If present, this attribute signals modifications of the metadata attribute in VnfInstance.",
+ child=serializers.CharField(help_text="KeyValue Pairs", allow_blank=True),
+ required=False,
+ allow_null=True
+ )
+ extensions = serializers.DictField(
+ help_text="If present, this attribute signals modifications of the extensions attribute in VnfInstance.",
+ child=serializers.CharField(help_text="KeyValue Pairs", allow_blank=True),
+ required=False,
+ allow_null=True
+ )
+ vimConnectionInfo = VimConnectionInfoSerializer(
+ help_text="If present, this attribute signals modifications of the vimConnectionInfo attribute in VnfInstance.",
+ many=True,
+ required=False
+ )
+ vnfPkgId = serializers.CharField(
+ help_text="If present, this attribute signals modifications of the vnfPkgId attribute in VnfInstance.",
+ required=False,
+ allow_null=True,
+ allow_blank=True
+ )
+ vnfdId = serializers.CharField(
+ help_text="If present, this attribute signals modifications of the vnfdId attribute in VnfInstance.",
+ required=False,
+ allow_null=True,
+ allow_blank=True
+ )
+ vnfProvider = serializers.CharField(
+ help_text="If present, this attribute signals modifications of the vnfProvider attribute in VnfInstance.",
+ required=False,
+ allow_null=True,
+ allow_blank=True
+ )
+ vnfProductName = serializers.CharField(
+ help_text="If present, this attribute signals modifications of the vnfProductName attribute in VnfInstance.",
+ required=False,
+ allow_null=True,
+ allow_blank=True
+ )
+ vnfSoftwareVersion = serializers.CharField(
+ help_text="If present, this attribute signals modifications of the vnfSoftwareVersion attribute in VnfInstance.",
+ required=False,
+ allow_null=True,
+ allow_blank=True
+ )
+ vnfdVersion = serializers.CharField(
+ help_text="If present, this attribute signals modifications of the vnfdVersion attribute in VnfInstance.",
+ required=False,
+ allow_null=True,
+ allow_blank=True
+ )
+
+
+class ExtLinkPortInfoSerializer(serializers.Serializer):
+ id = serializers.CharField(
+ help_text="Identifier of this link port as provided by the entity that has created the link port.",
+ required=True
+ )
+ resourceHandle = ResourceHandleSerializer(
+ help_text="Reference to the virtualised resource realizing this link port.",
+ required=True
+ )
+ cpInstanceId = serializers.CharField(
+ help_text="Identifier of the external CP of the VNF connected to this link port.",
+ required=False,
+ allow_null=True,
+ allow_blank=True
+ )
+
+
+class ExtVirtualLinkInfoSerializer(serializers.Serializer):
+ id = serializers.CharField(
+ help_text="Identifier of the external VL and the related external VL information instance.",
+ required=True
+ )
+ resourceHandle = ResourceHandleSerializer(
+ help_text="Reference to the resource realizing this VL.",
+ required=True
+ )
+ extLinkPorts = ExtLinkPortInfoSerializer(
+ help_text="Link ports of this VL.",
+ many=True,
+ required=False
+ )
+
+
+class ProblemDetailsSerializer(serializers.Serializer):
+ type = serializers.CharField(
+ help_text="A URI reference according to IETF RFC 3986 [5] that identifies the problem type.",
+ required=False,
+ allow_null=True,
+ allow_blank=True
+ )
+ title = serializers.CharField(
+ help_text="A short, human-readable summary of the problem type.",
+ required=False,
+ allow_null=True,
+ allow_blank=True
+ )
+ status = serializers.IntegerField(
+ help_text="The HTTP status code for this occurrence of the problem.",
+ required=True
+ )
+ detail = serializers.CharField(
+ help_text="A human-readable explanation specific to this occurrence of the problem.",
+ required=True
+ )
+ instance = serializers.CharField(
+ help_text="A URI reference that identifies the specific occurrence of the problem.",
+ required=False,
+ allow_null=True,
+ allow_blank=True
+ )
+
+
+class LccnLinksSerializer(serializers.Serializer):
+ vnfInstance = LinkSerializer(
+ help_text="Link to the resource representing the VNF instance to which the notified change applies.",
+ required=True
+ )
+ subscription = LinkSerializer(
+ help_text="Link to the related subscription.",
+ required=True
+ )
+ vnfLcmOpOcc = LinkSerializer(
+ help_text="Link to the VNF lifecycle management operation occurrence that this notification is related to.",
+ required=False,
+ allow_null=True
+ )
+
+
+class VnfLcmOperationOccurrenceNotificationSerializer(serializers.Serializer):
+ id = serializers.CharField(
+ help_text="Identifier of this notification.",
+ required=True
+ )
+ notificationType = serializers.CharField(
+ help_text="Discriminator for the different notification types.",
+ required=True
+ )
+ subscriptionId = serializers.CharField(
+ help_text="Identifier of the subscription that this notification relates to.",
+ required=True
+ )
+ timeStamp = serializers.CharField(
+ help_text="Date-time of the generation of the notification.",
+ required=True
+ )
+ notificationStatus = serializers.ChoiceField(
+ help_text="Indicates whether this notification reports about the start of a lifecycle operation or the result of a lifecycle operation.",
+ choices=["START", "RESULT"],
+ required=True
+ )
+ operationState = serializers.ChoiceField(
+ help_text="The state of the VNF LCM operation occurrence.",
+ choices=["STARTING", "PROCESSING", "COMPLETED", "FAILED_TEMP", "FAILED", "ROLLING_BACK", "ROLLED_BACK"],
+ required=True
+ )
+ vnfInstanceId = serializers.CharField(
+ help_text="The identifier of the VNF instance affected.",
+ required=True
+ )
+ operation = serializers.ChoiceField(
+ help_text="The lifecycle management operation.",
+ choices=["INSTANTIATE", "SCALE", "SCALE_TO_LEVEL", "CHANGE_FLAVOUR", "TERMINATE", "HEAL", "OPERATE", "CHANGE_EXT_CONN", "MODIFY_INFO"],
+ required=True
+ )
+ isAutomaticInvocation = serializers.BooleanField(
+ help_text="Set to true if this VNF LCM operation occurrence has been triggered by an automated procedure inside the VNFM.",
+ required=True
+ )
+ vnfLcmOpOccId = serializers.CharField(
+ help_text="The identifier of the VNF lifecycle management operation occurrence associated to the notification.",
+ required=True
+ )
+ affectedVnfcs = AffectedVnfcSerializer(
+ help_text="Information about VNFC instances that were affected during the lifecycle operation.",
+ many=True,
+ required=False
+ )
+ affectedVirtualLinks = AffectedVirtualLinkSerializer(
+ help_text="Information about VL instances that were affected during the lifecycle operation.",
+ many=True,
+ required=False
+ )
+ affectedVirtualStorages = AffectedVirtualStorageSerializer(
+ help_text="Information about virtualised storage instances that were affected during the lifecycle operation.",
+ many=True,
+ required=False
+ )
+ changedInfo = VnfInfoModificationsSerializer(
+ help_text="Information about the changed VNF instance information, including changed VNF configurable properties.",
+ required=False,
+ allow_null=True
+ )
+ changedExtConnectivity = ExtVirtualLinkInfoSerializer(
+ help_text="Information about changed external connectivity.",
+ many=True,
+ required=False
+ )
+ error = ProblemDetailsSerializer(
+ help_text="Details of the latest error, if one has occurred during executing the LCM operation",
+ required=False,
+ allow_null=True
+ )
+ _links = LccnLinksSerializer(
+ help_text="Links to resources related to this notification.",
+ required=False,
+ allow_null=True
+ )
diff --git a/lcm/v2/tests.py b/lcm/v2/tests.py
new file mode 100644
index 00000000..406edadd
--- /dev/null
+++ b/lcm/v2/tests.py
@@ -0,0 +1,217 @@
+# Copyright 2018 ZTE Corporation.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import unittest
+import json
+from django.test import Client
+from rest_framework import status
+
+
+class VnfGrantViewTest(unittest.TestCase):
+ def setUp(self):
+ self.client = Client()
+
+ def tearDown(self):
+ pass
+
+ def test_grant_vnf_normal(self):
+ data = {
+ "vnfInstanceId": "1",
+ "vnfLcmOpOccId": "2",
+ "vnfdId": "3",
+ "flavourId": "4",
+ "operation": "INSTANTIATE",
+ "isAutomaticInvocation": True,
+ "instantiationLevelId": "5",
+ "addResources": [
+ {
+ "id": "1",
+ "type": "COMPUTE",
+ "vduId": "2",
+ "resourceTemplateId": "3",
+ "resource": {
+ "vimConnectionId": "4",
+ "resourceProviderId": "5",
+ "resourceId": "6",
+ "vimLevelResourceType": "7"
+ }
+ }
+ ],
+ "placementConstraints": [
+ {
+ "affinityOrAntiAffinity": "AFFINITY",
+ "scope": "NFVI_POP",
+ "resource": [
+ {
+ "idType": "RES_MGMT",
+ "resourceId": "1",
+ "vimConnectionId": "2",
+ "resourceProviderId": "3"
+ }
+ ]
+ }
+ ],
+ "vimConstraints": [
+ {
+ "sameResourceGroup": True,
+ "resource": [
+ {
+ "idType": "RES_MGMT",
+ "resourceId": "1",
+ "vimConnectionId": "2",
+ "resourceProviderId": "3"
+ }
+ ]
+ }
+ ],
+ "additionalParams": {},
+ "_links": {
+ "vnfLcmOpOcc": {
+ "href": "1"
+ },
+ "vnfInstance": {
+ "href": "2"
+ }
+ }
+ }
+ response = self.client.post("/api/nslcm/v2/grants", data=data, format='json')
+ self.assertEqual(status.HTTP_201_CREATED, response.status_code, response.content)
+ resp_data = json.loads(response.content)
+ expect_resp_data = {
+ "id": resp_data.get("id"),
+ "vnfInstanceId": "1",
+ "vnfLcmOpOccId": "2"
+ }
+ self.assertEqual(expect_resp_data, resp_data)
+
+ def test_get_notify_vnf_normal(self):
+ response = self.client.get("/api/nslcm/v2/ns/1/vnfs/1/Notify")
+ self.assertEqual(status.HTTP_204_NO_CONTENT, response.status_code, response.content)
+
+ def test_notify_vnf_normal(self):
+ data = {
+ "id": "string",
+ "notificationType": "string",
+ "subscriptionId": "string",
+ "timeStamp": "string",
+ "notificationStatus": "START",
+ "operationState": "STARTING",
+ "vnfInstanceId": "string",
+ "operation": "INSTANTIATE",
+ "isAutomaticInvocation": True,
+ "vnfLcmOpOccId": "string",
+ "affectedVnfcs": [{
+ "vnfcInstanceId": "string",
+ "vduId": "string",
+ "changeType": "added",
+ "vimId": "string",
+ "vmId": "string",
+ "vmName": "string"
+ }],
+ "affectedVirtualLinks": [{
+ "vlInstanceId": "string",
+ "vldId": "string",
+ "changeType": "added",
+ "networkResource": {
+ "resourceType": "network",
+ "resourceId": "string",
+ "resourceName": "string"
+ }
+ }],
+ "affectedVirtualStorages": [{}],
+ "changedInfo": {
+ "vnfInstanceName": "string",
+ "vnfInstanceDescription": "string",
+ "vnfConfigurableProperties": {
+ "additionalProp1": "string",
+ "additionalProp2": "string",
+ "additionalProp3": "string"
+ },
+ "metadata": {
+ "additionalProp1": "string",
+ "additionalProp2": "string",
+ "additionalProp3": "string"
+ },
+ "extensions": {
+ "additionalProp1": "string",
+ "additionalProp2": "string",
+ "additionalProp3": "string"
+ },
+ "vimConnectionInfo": [{
+ "id": "string",
+ "vimId": "string",
+ "vimType": "string",
+ "interfaceInfo": {
+ "additionalProp1": "string",
+ "additionalProp2": "string",
+ "additionalProp3": "string"
+ },
+ "accessInfo": {
+ "additionalProp1": "string",
+ "additionalProp2": "string",
+ "additionalProp3": "string"
+ },
+ "extra": {
+ "additionalProp1": "string",
+ "additionalProp2": "string",
+ "additionalProp3": "string"
+ }
+ }],
+ "vnfPkgId": "string",
+ "vnfdId": "string",
+ "vnfProvider": "string",
+ "vnfProductName": "string",
+ "vnfSoftwareVersion": "string",
+ "vnfdVersion": "string"
+ },
+ "changedExtConnectivity": [{
+ "id": "string",
+ "resourceHandle": {
+ "vimConnectionId": "string",
+ "resourceProviderId": "string",
+ "resourceId": "string",
+ "vimLevelResourceType": "string"
+ },
+ "extLinkPorts": [{
+ "id": "string",
+ "resourceHandle": {
+ "vimConnectionId": "string",
+ "resourceProviderId": "string",
+ "resourceId": "string",
+ "vimLevelResourceType": "string"
+ },
+ "cpInstanceId": "string"
+ }]
+ }],
+ "error": {
+ "type": "string",
+ "title": "string",
+ "status": 0,
+ "detail": "string",
+ "instance": "string"
+ },
+ "_links": {
+ "vnfInstance": {
+ "href": "string"
+ },
+ "subscription": {
+ "href": "string"
+ },
+ "vnfLcmOpOcc": {
+ "href": "string"
+ }
+ }
+ }
+ response = self.client.post("/api/nslcm/v2/ns/1/vnfs/2/Notify", data=data, format='json')
+ self.assertEqual(status.HTTP_204_NO_CONTENT, response.status_code, response.content)
diff --git a/lcm/v2/urls.py b/lcm/v2/urls.py
new file mode 100644
index 00000000..243cdcd8
--- /dev/null
+++ b/lcm/v2/urls.py
@@ -0,0 +1,24 @@
+# Copyright 2018 ZTE Corporation.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+from django.conf.urls import url
+from rest_framework.urlpatterns import format_suffix_patterns
+
+from lcm.v2.views import VnfGrantView, VnfNotifyView
+
+urlpatterns = [
+ url(r'^api/nslcm/v2/grants$', VnfGrantView.as_view()),
+ url(r'^api/nslcm/v2/ns/(?P<vnfmId>[0-9a-zA-Z_-]+)/vnfs/(?P<vnfInstanceId>[0-9a-zA-Z_-]+)/Notify$', VnfNotifyView.as_view()),
+]
+
+urlpatterns = format_suffix_patterns(urlpatterns)
diff --git a/lcm/v2/views.py b/lcm/v2/views.py
new file mode 100644
index 00000000..e216022d
--- /dev/null
+++ b/lcm/v2/views.py
@@ -0,0 +1,84 @@
+# Copyright 2018 ZTE Corporation.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+import logging
+import traceback
+
+from rest_framework.response import Response
+from rest_framework.views import APIView
+from rest_framework import status
+from drf_yasg.utils import swagger_auto_schema
+
+from lcm.v2.serializers import GrantRequestSerializer
+from lcm.v2.serializers import GrantSerializer
+from lcm.v2.serializers import VnfLcmOperationOccurrenceNotificationSerializer
+from lcm.v2.grant_vnf import GrantVnf
+
+logger = logging.getLogger(__name__)
+
+
+class VnfGrantView(APIView):
+ @swagger_auto_schema(
+ request_body=GrantRequestSerializer(),
+ responses={
+ status.HTTP_201_CREATED: GrantSerializer(
+ help_text="The grant was created successfully (synchronous mode)."
+ ),
+ status.HTTP_500_INTERNAL_SERVER_ERROR: "Inner error"
+ }
+ )
+ def post(self, request):
+ logger.debug("VnfGrantView Post: %s" % request.data)
+ try:
+ req_serializer = GrantRequestSerializer(data=request.data)
+ if not req_serializer.is_valid():
+ raise Exception(req_serializer.errors)
+
+ grant_resp = GrantVnf(request.data).exec_grant()
+
+ resp_serializer = GrantSerializer(data=grant_resp)
+ if not resp_serializer.is_valid():
+ raise Exception(resp_serializer.errors)
+
+ return Response(data=resp_serializer.data, status=status.HTTP_201_CREATED)
+ except Exception as e:
+ logger.error(traceback.format_exc())
+ logger.error("Exception in VnfGrant: %s", e.message)
+ return Response(data={'error': e.message}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
+
+
+class VnfNotifyView(APIView):
+ @swagger_auto_schema(
+ request_body=VnfLcmOperationOccurrenceNotificationSerializer(
+ help_text="A notification about lifecycle changes triggered by a VNF LCM operation occurrence."
+ ),
+ responses={
+ status.HTTP_204_NO_CONTENT: "The notification was delivered successfully.",
+ status.HTTP_500_INTERNAL_SERVER_ERROR: "Inner error"
+ }
+ )
+ def post(self, request, vnfmId, vnfInstanceId):
+ logger.debug("VnfNotifyView post: %s" % request.data)
+ logger.debug("vnfmId: %s vnfInstanceId: %s", vnfmId, vnfInstanceId)
+ return Response(data={}, status=status.HTTP_204_NO_CONTENT)
+
+ @swagger_auto_schema(
+ responses={
+ status.HTTP_204_NO_CONTENT: "The notification endpoint was tested successfully.",
+ status.HTTP_500_INTERNAL_SERVER_ERROR: "Inner error"
+ }
+ )
+ def get(self, request, vnfmId, vnfInstanceId):
+ logger.debug("VnfNotifyView get")
+ logger.debug("vnfmId: %s vnfInstanceId: %s", vnfmId, vnfInstanceId)
+ return Response(data={}, status=status.HTTP_204_NO_CONTENT)
diff --git a/mvn-phase-script.sh b/mvn-phase-script.sh
new file mode 100755
index 00000000..6b41abf1
--- /dev/null
+++ b/mvn-phase-script.sh
@@ -0,0 +1,86 @@
+#!/bin/bash
+# Copyright 2018 ZTE Corporation.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+
+set -e
+
+echo "running script: [$0] for module [$1] at stage [$2]"
+
+export SETTINGS_FILE=${SETTINGS_FILE:-$HOME/.m2/settings.xml}
+MVN_PROJECT_MODULEID="$1"
+MVN_PHASE="$2"
+
+
+FQDN="${MVN_PROJECT_GROUPID}.${MVN_PROJECT_ARTIFACTID}"
+if [ "$MVN_PROJECT_MODULEID" == "__" ]; then
+ MVN_PROJECT_MODULEID=""
+fi
+
+if [ -z "$WORKSPACE" ]; then
+ WORKSPACE=$(pwd)
+fi
+
+
+# mvn phase in life cycle
+MVN_PHASE="$2"
+
+
+echo "MVN_PROJECT_MODULEID is [$MVN_PROJECT_MODULEID]"
+echo "MVN_PHASE is [$MVN_PHASE]"
+echo "MVN_PROJECT_GROUPID is [$MVN_PROJECT_GROUPID]"
+echo "MVN_PROJECT_ARTIFACTID is [$MVN_PROJECT_ARTIFACTID]"
+echo "MVN_PROJECT_VERSION is [$MVN_PROJECT_VERSION]"
+
+run_tox_test()
+{
+ set -x
+ CURDIR=$(pwd)
+ if [[ ${CURDIR} =~ "-sonar" ]]
+ then
+ echo "====Sonar job, need execute tox."
+ TOXINIS=$(find . -name "tox.ini")
+ for TOXINI in "${TOXINIS[@]}"; do
+ DIR=$(echo "$TOXINI" | rev | cut -f2- -d'/' | rev)
+ cd "${CURDIR}/${DIR}"
+ rm -rf ./venv-tox ./.tox
+ virtualenv ./venv-tox
+ source ./venv-tox/bin/activate
+ pip install --upgrade pip
+ pip install --upgrade tox argparse
+ pip freeze
+ tox
+ deactivate
+ rm -rf ./venv-tox ./.tox
+ done
+ else
+ echo "====Not a sonar job, need not execute tox."
+ fi
+}
+
+
+case $MVN_PHASE in
+clean)
+ echo "==> clean phase script"
+ rm -rf ./venv-*
+ ;;
+test)
+ echo "==> test phase script"
+ run_tox_test
+ ;;
+*)
+ echo "==> unprocessed phase"
+ ;;
+esac
+
diff --git a/pom.xml b/pom.xml
index ca07fdee..3ffce910 100644
--- a/pom.xml
+++ b/pom.xml
@@ -1,6 +1,6 @@
<?xml version="1.0"?>
<!--
- Copyright 2016 ZTE Corporation.
+ Copyright 2016-2018 ZTE Corporation.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
@@ -18,7 +18,7 @@
<parent>
<groupId>org.onap.oparent</groupId>
<artifactId>oparent</artifactId>
- <version>0.1.1</version>
+ <version>1.1.0</version>
</parent>
<modelVersion>4.0.0</modelVersion>
<groupId>org.onap.vfc.nfvo.lcm</groupId>
@@ -27,9 +27,70 @@
<packaging>pom</packaging>
<name>vfc-nfvo-lcm</name>
<description>vfc nfvo lcm</description>
+ <properties>
+ <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+ <sonar.sources>.</sonar.sources>
+ <sonar.junit.reportsPath>xunit-results.xml</sonar.junit.reportsPath>
+ <sonar.python.coverage.reportPath>coverage.xml</sonar.python.coverage.reportPath>
+ <sonar.language>py</sonar.language>
+ <sonar.pluginname>python</sonar.pluginname>
+ <sonar.inclusions>**/**.py</sonar.inclusions>
+ <sonar.exclusions>**/tests/**.py,**/test*.py</sonar.exclusions>
+ </properties>
<build>
+ <pluginManagement>
+ <plugins>
+ <plugin>
+ <groupId>org.codehaus.mojo</groupId>
+ <artifactId>exec-maven-plugin</artifactId>
+ <version>1.2.1</version>
+ <configuration>
+ <executable>${project.basedir}/mvn-phase-script.sh</executable>
+ <environmentVariables>
+ <!-- make mvn properties as env for our script -->
+ <MVN_PROJECT_GROUPID>${project.groupId}</MVN_PROJECT_GROUPID>
+ <MVN_PROJECT_ARTIFACTID>${project.artifactId}</MVN_PROJECT_ARTIFACTID>
+ <MVN_PROJECT_VERSION>${project.version}</MVN_PROJECT_VERSION>
+ </environmentVariables>
+ </configuration>
+ </plugin>
+ </plugins>
+ </pluginManagement>
<plugins>
<plugin>
+ <groupId>org.codehaus.mojo</groupId>
+ <artifactId>exec-maven-plugin</artifactId>
+ <version>1.2.1</version>
+ <executions>
+ <execution>
+ <id>clean phase script</id>
+ <phase>clean</phase>
+ <goals>
+ <goal>exec</goal>
+ </goals>
+ <configuration>
+ <arguments>
+ <argument>__</argument>
+ <argument>clean</argument>
+ </arguments>
+ </configuration>
+ </execution>
+ <execution>
+ <id>test script</id>
+ <phase>test</phase>
+ <goals>
+ <goal>exec</goal>
+ </goals>
+ <configuration>
+ <arguments>
+ <argument>__</argument>
+ <argument>test</argument>
+ </arguments>
+ </configuration>
+ </execution>
+ </executions>
+ </plugin>
+ <plugin>
<artifactId>maven-assembly-plugin</artifactId>
<configuration>
<appendAssemblyId>false</appendAssemblyId>
diff --git a/requirements.txt b/requirements.txt
index 8c34a073..c1dd615e 100644
--- a/requirements.txt
+++ b/requirements.txt
@@ -1,9 +1,9 @@
# rest framework
-Django==1.9.6
-djangorestframework==3.3.3
+Django==1.11.9
+djangorestframework==3.7.7
# for access MySQL
-MySQL-python==1.2.5
+PyMySQL==0.7.11
# redis cache
redis==2.10.5
@@ -29,3 +29,13 @@ unittest_xml_reporting==1.12.0
cryptography==2.0.3
paramiko==2.0.2
nfv-toscaparser>=0.5.0
+
+# for swagger
+drf-yasg>=1.2.2
+
+# for the validation feature
+flex>=6.11.1
+swagger-spec-validator>=2.1.0
+
+# for onap logging
+onappylog>=1.0.6 \ No newline at end of file
diff --git a/run.sh b/run.sh
index aebe4055..2eea401f 100755
--- a/run.sh
+++ b/run.sh
@@ -12,4 +12,16 @@
# 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.
+
+logDir="/var/log/onap/vfc/nslcm/"
+if [ ! -x $logDir ]; then
+ mkdir -p $logDir
+fi
+
nohup python manage.py runserver 0.0.0.0:8403 > /dev/null &
+
+while [ ! -f $logDir/runtime_nslcm.log ]; do
+ sleep 1
+done
+
+tail -F $logDir/runtime_nslcm.log \ No newline at end of file
diff --git a/tox.ini b/tox.ini
index 5d7adac0..f0b29e88 100644
--- a/tox.ini
+++ b/tox.ini
@@ -23,4 +23,4 @@ commands =
{[testenv]commands}
[testenv:cov]
-commands = coverage html --omit="*test_*,*__init__.py,*site-packages*" -d htmlcov
+commands = coverage xml --omit="*test_*,*__init__.py,*site-packages*"