aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--LICENSE15
-rw-r--r--assembly.xml1
-rw-r--r--catalog/__init__.py3
-rw-r--r--catalog/jobs/tests/tests.py2
-rw-r--r--catalog/jobs/urls.py11
-rw-r--r--catalog/jobs/views.py112
-rw-r--r--catalog/log.yml50
-rw-r--r--catalog/middleware.py60
-rw-r--r--catalog/packages/tests/test_ns.py710
-rw-r--r--catalog/packages/views.py280
-rw-r--r--catalog/pub/config/config.py5
-rw-r--r--catalog/pub/utils/toscaparser/basemodel.py3
-rw-r--r--catalog/pub/utils/toscaparser/testdata/resource-ZteMmeFixVl-csar.csarbin0 -> 34326 bytes
-rw-r--r--catalog/pub/utils/toscaparser/tests.py34
-rw-r--r--catalog/serializers.py206
-rw-r--r--catalog/settings.py107
-rw-r--r--catalog/swagger/urls.py11
-rw-r--r--catalog/swagger/vfc.catalog.swagger.json64
-rw-r--r--catalog/urls.py39
-rwxr-xr-xmvn-phase-script.sh86
-rw-r--r--pom.xml63
-rw-r--r--requirements.txt16
-rwxr-xr-xrun.sh11
-rw-r--r--tox.ini2
24 files changed, 1366 insertions, 525 deletions
diff --git a/LICENSE b/LICENSE
new file mode 100644
index 00000000..15867162
--- /dev/null
+++ b/LICENSE
@@ -0,0 +1,15 @@
+# Copyright 2017 ZTE Corporation.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+# Micro service of nfvo catalog.
diff --git a/assembly.xml b/assembly.xml
index a062bc06..23dc6363 100644
--- a/assembly.xml
+++ b/assembly.xml
@@ -28,6 +28,7 @@
<include>**/*.py</include>
<include>**/*.json</include>
<include>**/*.xml</include>
+ <include>**/*.yml</include>
</includes>
</fileSet>
<fileSet>
diff --git a/catalog/__init__.py b/catalog/__init__.py
index c7b6818e..68cf9541 100644
--- a/catalog/__init__.py
+++ b/catalog/__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/catalog/jobs/tests/tests.py b/catalog/jobs/tests/tests.py
index 37996a05..0411c186 100644
--- a/catalog/jobs/tests/tests.py
+++ b/catalog/jobs/tests/tests.py
@@ -27,7 +27,7 @@ class JobsViewTest(TestCase):
def test_job_normal(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', errcode='0', progress=20, descp='inst').save()
response = self.client.get("/api/catalog/v1/jobs/%s" % self.job_id)
self.failUnlessEqual(status.HTTP_200_OK, response.status_code)
diff --git a/catalog/jobs/urls.py b/catalog/jobs/urls.py
index d2e000fd..ea1fcd64 100644
--- a/catalog/jobs/urls.py
+++ b/catalog/jobs/urls.py
@@ -11,13 +11,10 @@
# 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 catalog.jobs.views import JobView
-urlpatterns = patterns('',
- url(r'^api/catalog/v1/jobs/(?P<job_id>[0-9a-zA-Z_-]+)$', JobView.as_view()),
- )
-
-urlpatterns = format_suffix_patterns(urlpatterns)
+urlpatterns = [
+ url(r'^api/catalog/v1/jobs/(?P<job_id>[0-9a-zA-Z_-]+)$', JobView.as_view()),
+]
diff --git a/catalog/jobs/views.py b/catalog/jobs/views.py
index febcfcec..8db6cb64 100644
--- a/catalog/jobs/views.py
+++ b/catalog/jobs/views.py
@@ -12,37 +12,111 @@
# See the License for the specific language governing permissions and
# limitations under the License.
import logging
-import traceback
-
+from drf_yasg import openapi
+from drf_yasg.utils import swagger_auto_schema
from rest_framework.response import Response
from rest_framework.views import APIView
-
+from rest_framework import status
from catalog.jobs.job_get import GetJobInfoService
from catalog.pub.utils.jobutil import JobUtil
from catalog.pub.utils.values import ignore_case_get
+from catalog.serializers import GetJobResponseSerializer
+from catalog.serializers import PostJobResponseResultSerializer
+from catalog.serializers import PostJobRequestSerializer
logger = logging.getLogger(__name__)
class JobView(APIView):
+
+ input_job_id = openapi.Parameter(
+ 'job_id',
+ openapi.IN_QUERY,
+ description="job id",
+ type=openapi.TYPE_STRING)
+ input_response_id = openapi.Parameter(
+ 'responseId',
+ openapi.IN_QUERY,
+ description="response id",
+ type=openapi.TYPE_STRING)
+
+ @swagger_auto_schema(
+ operation_description="Get job status",
+ manual_parameters=[input_job_id, input_response_id],
+ responses={
+ status.HTTP_200_OK: GetJobResponseSerializer(),
+ status.HTTP_500_INTERNAL_SERVER_ERROR: PostJobResponseResultSerializer()
+ })
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)
+ response_serializer = GetJobResponseSerializer(data=ret)
+ validataion_error = self.handleValidatonError(
+ response_serializer, False)
+ if validataion_error:
+ return validataion_error
+ return Response(
+ data=response_serializer.data,
+ status=status.HTTP_200_OK)
+
+ @swagger_auto_schema(
+ request_body=PostJobRequestSerializer(),
+ operation_description="Update job status",
+ manual_parameters=[input_job_id],
+ responses={
+ status.HTTP_202_ACCEPTED: PostJobResponseResultSerializer(),
+ status.HTTP_500_INTERNAL_SERVER_ERROR: PostJobResponseResultSerializer()
+ }
+ )
def post(self, request, job_id):
- try:
- logger.debug("Enter JobView:post, %s, %s ", job_id, request.data)
- jobs = JobUtil.query_job_status(job_id)
- if len(jobs) > 0 and jobs[-1].errcode == '255':
- return Response(data={'result': 'ok'})
- progress = request.data.get('progress')
- desc = request.data.get('desc', '%s' % progress)
- errcode = '0' if request.data.get('errcode') in ('true', 'active') else '255'
- logger.debug("errcode=%s", errcode)
- JobUtil.add_job_status(job_id, progress, desc, error_code=errcode)
- return Response(data={'result': 'ok'})
- except Exception as e:
- logger.error(e.message)
- logger.error(traceback.format_exc())
- return Response(data={'result': 'error', 'msg': e.message})
+ job_result_ok = {'result': 'ok'}
+
+ logger.debug("Enter JobView:post, %s, %s ", job_id, request.data)
+ jobs = JobUtil.query_job_status(job_id)
+ if len(jobs) > 0 and jobs[-1].errcode == '255':
+ return Response(data=job_result_ok)
+
+ request_serializer = PostJobRequestSerializer(data=request.data)
+ validataion_error = self.handleValidatonError(
+ request_serializer, True)
+ if not validataion_error:
+ return validataion_error
+
+ requestData = request_serializer.data
+ progress = ignore_case_get(requestData, "progress")
+ desc = ignore_case_get(requestData, "desc", '%s' % progress)
+ errcode = '0' if ignore_case_get(
+ requestData, 'errcode') in (
+ 'true', 'active') else '255'
+ logger.debug("errcode=%s", errcode)
+ JobUtil.add_job_status(job_id, progress, desc, error_code=errcode)
+
+ response_serializer = PostJobResponseResultSerializer(
+ data=job_result_ok)
+ validataion_error = self.handleValidatonError(
+ response_serializer, False)
+ if validataion_error:
+ return validataion_error
+
+ return Response(
+ data=response_serializer.data,
+ status=status.HTTP_202_ACCEPTED)
+
+ def handleValidatonError(self, base_serializer, is_request):
+ response = None
+
+ if not base_serializer.is_valid():
+ errormessage = base_serializer.errors
+ logger.error(errormessage)
+
+ if is_request:
+ message = 'Invalid request'
+ else:
+ message = 'Invalid response'
+ logger.error(message)
+
+ Response(
+ data={'result': message, 'msg': errormessage},
+ status=status.HTTP_500_INTERNAL_SERVER_ERROR)
+ return response
diff --git a/catalog/log.yml b/catalog/log.yml
new file mode 100644
index 00000000..2daea32c
--- /dev/null
+++ b/catalog/log.yml
@@ -0,0 +1,50 @@
+version: 1
+disable_existing_loggers: False
+
+loggers:
+ catalog:
+ handlers: [cataloglocal_handler, catalog_handler]
+ level: "DEBUG"
+ propagate: False
+ django:
+ handlers: [django_handler]
+ level: "DEBUG"
+ propagate: False
+handlers:
+ cataloglocal_handler:
+ level: "DEBUG"
+ class:
+ "logging.handlers.RotatingFileHandler"
+ filename: "logs/runtime_catalog.log"
+ formatter:
+ "standard"
+ maxBytes: 52428800
+ backupCount: 10
+ catalog_handler:
+ level: "DEBUG"
+ class:
+ "logging.handlers.RotatingFileHandler"
+ filename: "/var/log/onap/vfc/catalog/runtime_catalog.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/catalog/middleware.py b/catalog/middleware.py
new file mode 100644
index 00000000..0617fead
--- /dev/null
+++ b/catalog/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 catalog.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/catalog/packages/tests/test_ns.py b/catalog/packages/tests/test_ns.py
index 9f0f2acc..020216a1 100644
--- a/catalog/packages/tests/test_ns.py
+++ b/catalog/packages/tests/test_ns.py
@@ -28,384 +28,248 @@ class TestNsPackage(TestCase):
self.client = Client()
NSPackageModel.objects.filter().delete()
VnfPackageModel.objects.filter().delete()
- self.nsd_data = {
- "vnffgs": [
- {
- "vnffg_id": "vnffg1",
- "description": "",
- "members": [
- "path1",
- "path2"
- ],
- "properties": {
- "vendor": "zte",
- "connection_point": [
- "m6000_data_in",
- "m600_tunnel_cp",
- "m6000_data_out"
- ],
- "version": "1.0",
- "constituent_vnfs": [
- "VFW",
- "VNAT"
- ],
- "number_of_endpoints": 3,
- "dependent_virtual_link": [
- "sfc_data_network",
- "ext_datanet_net",
- "ext_mnet_net"
- ]
- }
- }
- ],
- "inputs": {
- "sfc_data_network": {
- "type": "string",
- "value": "sfc_data_network"
- },
- "externalDataNetworkName": {
- "type": "string",
- "value": "vlan_4004_tunnel_net"
- },
- "externalManageNetworkName": {
- "type": "string",
- "value": "vlan_4008_mng_net"
- },
- "NatIpRange": {
- "type": "string",
- "value": "192.167.0.10-192.168.0.20"
- },
- "externalPluginManageNetworkName": {
- "type": "string",
- "value": "vlan_4007_plugin_net"
- }
- },
- "pnfs": [
- {
- "pnf_id": "m6000_s",
- "cps": [],
- "description": "",
- "properties": {
- "vendor": "zte",
- "request_reclassification": False,
- "pnf_type": "m6000s",
- "version": "1.0",
- "management_address": "111111",
- "id": "m6000_s",
- "nsh_aware": False
- }
- }
- ],
- "fps": [
- {
- "properties": {
- "symmetric": False,
- "policy": {
- "type": "ACL",
- "criteria": {
- "dest_port_range": "1-100",
- "ip_protocol": "tcp",
- "source_ip_range": [
- "119.1.1.1-119.1.1.10"
- ],
- "dest_ip_range": [
- {
- "get_input": "NatIpRange"
- }
- ],
- "dscp": 0,
- "source_port_range": "1-100"
- }
- }
- },
- "forwarder_list": [
- {
- "capability": "",
- "type": "cp",
- "node_name": "m6000_data_out"
- },
- {
- "capability": "",
- "type": "cp",
- "node_name": "m600_tunnel_cp"
- },
- {
- "capability": "vnat_fw_inout",
- "type": "vnf",
- "node_name": "VNAT"
- }
- ],
- "description": "",
- "fp_id": "path2"
- },
- {
- "properties": {
- "symmetric": True,
- "policy": {
- "type": "ACL",
- "criteria": {
- "dest_port_range": "1-100",
- "ip_protocol": "tcp",
- "source_ip_range": [
- "1-100"
- ],
- "dest_ip_range": [
- "1-100"
- ],
- "dscp": 4,
- "source_port_range": "1-100"
- }
- }
- },
- "forwarder_list": [
- {
- "capability": "",
- "type": "cp",
- "node_name": "m6000_data_in"
- },
- {
- "capability": "",
- "type": "cp",
- "node_name": "m600_tunnel_cp"
- },
- {
- "capability": "vfw_fw_inout",
- "type": "vnf",
- "node_name": "VFW"
- },
- {
- "capability": "vnat_fw_inout",
- "type": "vnf",
- "node_name": "VNAT"
- },
- {
- "capability": "",
- "type": "cp",
- "node_name": "m600_tunnel_cp"
- },
- {
- "capability": "",
- "type": "cp",
- "node_name": "m6000_data_out"
- }
- ],
- "description": "",
- "fp_id": "path1"
- }
- ],
- "routers": [],
- "vnfs": [
- {
- "vnf_id": "VFW",
- "description": "",
- "properties": {
- "plugin_info": "vbrasplugin_1.0",
- "vendor": "zte",
- "is_shared": False,
- "adjust_vnf_capacity": True,
- "name": "VFW",
- "vnf_extend_type": "driver",
- "csarVersion": "v1.0",
- "csarType": "NFAR",
- "csarProvider": "ZTE",
- "version": "1.0",
- "nsh_aware": True,
- "cross_dc": False,
- "vnf_type": "VFW",
- "vmnumber_overquota_alarm": True,
- "vnfd_version": "1.0.0",
- "externalPluginManageNetworkName": "vlan_4007_plugin_net",
- "id": "vcpe_vfw_zte_1_0",
- "request_reclassification": False
- },
- "dependencies": [
- {
- "key_name": "vfw_ctrl_by_manager_cp",
- "vl_id": "ext_mnet_net"
- },
- {
- "key_name": "vfw_data_cp",
- "vl_id": "sfc_data_network"
- }
- ],
- "type": "tosca.nodes.nfv.ext.zte.VNF.VFW",
- "networks": []
- }
- ],
- "ns_exposed": {
- "external_cps": [],
- "forward_cps": []
- },
- "policies": [
- {
- "file_url": "policies/abc.drl",
- "name": "aaa"
- }
- ],
- "vls": [
- {
- "route_id": "",
- "vl_id": "ext_mnet_net",
- "route_external": False,
- "description": "",
- "properties": {
- "name": "vlan_4008_mng_net",
- "mtu": 1500,
- "location_info": {
- "tenant": "admin",
- "vimid": 2,
- "availability_zone": "nova"
- },
- "ip_version": 4,
- "dhcp_enabled": True,
- "network_name": "vlan_4008_mng_net",
- "network_type": "vlan"
- }
- },
- {
- "route_id": "",
- "vl_id": "ext_datanet_net",
- "route_external": False,
- "description": "",
- "properties": {
- "name": "vlan_4004_tunnel_net",
- "mtu": 1500,
- "location_info": {
- "tenant": "admin",
- "vimid": 2,
- "availability_zone": "nova"
- },
- "ip_version": 4,
- "dhcp_enabled": True,
- "network_name": "vlan_4004_tunnel_net",
- "network_type": "vlan"
- }
- },
- {
- "route_id": "",
- "vl_id": "sfc_data_network",
- "route_external": False,
- "description": "",
- "properties": {
- "name": "sfc_data_network",
- "dhcp_enabled": True,
- "is_predefined": False,
- "location_info": {
- "tenant": "admin",
- "vimid": 2,
- "availability_zone": "nova"
- },
- "ip_version": 4,
- "mtu": 1500,
- "network_name": "sfc_data_network",
- "network_type": "vlan"
- }
- }
- ],
- "cps": [
- {
- "pnf_id": "m6000_s",
- "vl_id": "path2",
- "description": "",
- "cp_id": "m6000_data_out",
- "properties": {
- "direction": "bidirectional",
- "vnic_type": "normal",
- "bandwidth": 0,
- "mac_address": "11-22-33-22-11-44",
- "interface_name": "xgei-0/4/1/5",
- "ip_address": "176.1.1.2",
- "order": 0,
- "sfc_encapsulation": "mac"
- }
- },
- {
- "pnf_id": "m6000_s",
- "vl_id": "ext_datanet_net",
- "description": "",
- "cp_id": "m600_tunnel_cp",
- "properties": {
- "direction": "bidirectional",
- "vnic_type": "normal",
- "bandwidth": 0,
- "mac_address": "00-11-00-22-33-00",
- "interface_name": "gei-0/4/0/13",
- "ip_address": "191.167.100.5",
- "order": 0,
- "sfc_encapsulation": "mac"
- }
- },
- {
- "pnf_id": "m6000_s",
- "vl_id": "path2",
- "description": "",
- "cp_id": "m6000_data_in",
- "properties": {
- "direction": "bidirectional",
- "vnic_type": "normal",
- "bandwidth": 0,
- "mac_address": "11-22-33-22-11-41",
- "interface_name": "gei-0/4/0/7",
- "ip_address": "1.1.1.1",
- "order": 0,
- "sfc_encapsulation": "mac",
- "bond": "none"
- }
- },
- {
- "pnf_id": "m6000_s",
- "vl_id": "ext_mnet_net",
- "description": "",
- "cp_id": "m600_mnt_cp",
- "properties": {
- "direction": "bidirectional",
- "vnic_type": "normal",
- "bandwidth": 0,
- "mac_address": "00-11-00-22-33-11",
- "interface_name": "gei-0/4/0/1",
- "ip_address": "10.46.244.51",
- "order": 0,
- "sfc_encapsulation": "mac",
- "bond": "none"
- }
- }
- ],
- "metadata": {
- "invariant_id": "vcpe_ns_sff_1",
- "name": "VCPE_NS",
- "csarVersion": "v1.0",
- "csarType": "NSAR",
- "csarProvider": "ZTE",
- "version": 1,
- "vendor": "ZTE",
- "id": "VCPE_NS",
- "description": "vcpe_ns"
- }
- }
+ self.nsd_data = {"vnffgs": [{"vnffg_id": "vnffg1",
+ "description": "",
+ "members": ["path1",
+ "path2"],
+ "properties": {"vendor": "zte",
+ "connection_point": ["m6000_data_in",
+ "m600_tunnel_cp",
+ "m6000_data_out"],
+ "version": "1.0",
+ "constituent_vnfs": ["VFW",
+ "VNAT"],
+ "number_of_endpoints": 3,
+ "dependent_virtual_link": ["sfc_data_network",
+ "ext_datanet_net",
+ "ext_mnet_net"]}}],
+ "inputs": {"sfc_data_network": {"type": "string",
+ "value": "sfc_data_network"},
+ "externalDataNetworkName": {"type": "string",
+ "value": "vlan_4004_tunnel_net"},
+ "externalManageNetworkName": {"type": "string",
+ "value": "vlan_4008_mng_net"},
+ "NatIpRange": {"type": "string",
+ "value": "192.167.0.10-192.168.0.20"},
+ "externalPluginManageNetworkName": {"type": "string",
+ "value": "vlan_4007_plugin_net"}},
+ "pnfs": [{"pnf_id": "m6000_s",
+ "cps": [],
+ "description": "",
+ "properties": {"vendor": "zte",
+ "request_reclassification": False,
+ "pnf_type": "m6000s",
+ "version": "1.0",
+ "management_address": "111111",
+ "id": "m6000_s",
+ "nsh_aware": False}}],
+ "fps": [{"properties": {"symmetric": False,
+ "policy": {"type": "ACL",
+ "criteria": {"dest_port_range": "1-100",
+ "ip_protocol": "tcp",
+ "source_ip_range": ["119.1.1.1-119.1.1.10"],
+ "dest_ip_range": [{"get_input": "NatIpRange"}],
+ "dscp": 0,
+ "source_port_range": "1-100"}}},
+ "forwarder_list": [{"capability": "",
+ "type": "cp",
+ "node_name": "m6000_data_out"},
+ {"capability": "",
+ "type": "cp",
+ "node_name": "m600_tunnel_cp"},
+ {"capability": "vnat_fw_inout",
+ "type": "vnf",
+ "node_name": "VNAT"}],
+ "description": "",
+ "fp_id": "path2"},
+ {"properties": {"symmetric": True,
+ "policy": {"type": "ACL",
+ "criteria": {"dest_port_range": "1-100",
+ "ip_protocol": "tcp",
+ "source_ip_range": ["1-100"],
+ "dest_ip_range": ["1-100"],
+ "dscp": 4,
+ "source_port_range": "1-100"}}},
+ "forwarder_list": [{"capability": "",
+ "type": "cp",
+ "node_name": "m6000_data_in"},
+ {"capability": "",
+ "type": "cp",
+ "node_name": "m600_tunnel_cp"},
+ {"capability": "vfw_fw_inout",
+ "type": "vnf",
+ "node_name": "VFW"},
+ {"capability": "vnat_fw_inout",
+ "type": "vnf",
+ "node_name": "VNAT"},
+ {"capability": "",
+ "type": "cp",
+ "node_name": "m600_tunnel_cp"},
+ {"capability": "",
+ "type": "cp",
+ "node_name": "m6000_data_out"}],
+ "description": "",
+ "fp_id": "path1"}],
+ "routers": [],
+ "vnfs": [{"vnf_id": "VFW",
+ "description": "",
+ "properties": {"plugin_info": "vbrasplugin_1.0",
+ "vendor": "zte",
+ "is_shared": False,
+ "adjust_vnf_capacity": True,
+ "name": "VFW",
+ "vnf_extend_type": "driver",
+ "csarVersion": "v1.0",
+ "csarType": "NFAR",
+ "csarProvider": "ZTE",
+ "version": "1.0",
+ "nsh_aware": True,
+ "cross_dc": False,
+ "vnf_type": "VFW",
+ "vmnumber_overquota_alarm": True,
+ "vnfd_version": "1.0.0",
+ "externalPluginManageNetworkName": "vlan_4007_plugin_net",
+ "id": "vcpe_vfw_zte_1_0",
+ "request_reclassification": False},
+ "dependencies": [{"key_name": "vfw_ctrl_by_manager_cp",
+ "vl_id": "ext_mnet_net"},
+ {"key_name": "vfw_data_cp",
+ "vl_id": "sfc_data_network"}],
+ "type": "tosca.nodes.nfv.ext.zte.VNF.VFW",
+ "networks": []}],
+ "ns_exposed": {"external_cps": [],
+ "forward_cps": []},
+ "policies": [{"file_url": "policies/abc.drl",
+ "name": "aaa"}],
+ "vls": [{"route_id": "",
+ "vl_id": "ext_mnet_net",
+ "route_external": False,
+ "description": "",
+ "properties": {"name": "vlan_4008_mng_net",
+ "mtu": 1500,
+ "location_info": {"tenant": "admin",
+ "vimid": 2,
+ "availability_zone": "nova"},
+ "ip_version": 4,
+ "dhcp_enabled": True,
+ "network_name": "vlan_4008_mng_net",
+ "network_type": "vlan"}},
+ {"route_id": "",
+ "vl_id": "ext_datanet_net",
+ "route_external": False,
+ "description": "",
+ "properties": {"name": "vlan_4004_tunnel_net",
+ "mtu": 1500,
+ "location_info": {"tenant": "admin",
+ "vimid": 2,
+ "availability_zone": "nova"},
+ "ip_version": 4,
+ "dhcp_enabled": True,
+ "network_name": "vlan_4004_tunnel_net",
+ "network_type": "vlan"}},
+ {"route_id": "",
+ "vl_id": "sfc_data_network",
+ "route_external": False,
+ "description": "",
+ "properties": {"name": "sfc_data_network",
+ "dhcp_enabled": True,
+ "is_predefined": False,
+ "location_info": {"tenant": "admin",
+ "vimid": 2,
+ "availability_zone": "nova"},
+ "ip_version": 4,
+ "mtu": 1500,
+ "network_name": "sfc_data_network",
+ "network_type": "vlan"}}],
+ "cps": [{"pnf_id": "m6000_s",
+ "vl_id": "path2",
+ "description": "",
+ "cp_id": "m6000_data_out",
+ "properties": {"direction": "bidirectional",
+ "vnic_type": "normal",
+ "bandwidth": 0,
+ "mac_address": "11-22-33-22-11-44",
+ "interface_name": "xgei-0/4/1/5",
+ "ip_address": "176.1.1.2",
+ "order": 0,
+ "sfc_encapsulation": "mac"}},
+ {"pnf_id": "m6000_s",
+ "vl_id": "ext_datanet_net",
+ "description": "",
+ "cp_id": "m600_tunnel_cp",
+ "properties": {"direction": "bidirectional",
+ "vnic_type": "normal",
+ "bandwidth": 0,
+ "mac_address": "00-11-00-22-33-00",
+ "interface_name": "gei-0/4/0/13",
+ "ip_address": "191.167.100.5",
+ "order": 0,
+ "sfc_encapsulation": "mac"}},
+ {"pnf_id": "m6000_s",
+ "vl_id": "path2",
+ "description": "",
+ "cp_id": "m6000_data_in",
+ "properties": {"direction": "bidirectional",
+ "vnic_type": "normal",
+ "bandwidth": 0,
+ "mac_address": "11-22-33-22-11-41",
+ "interface_name": "gei-0/4/0/7",
+ "ip_address": "1.1.1.1",
+ "order": 0,
+ "sfc_encapsulation": "mac",
+ "bond": "none"}},
+ {"pnf_id": "m6000_s",
+ "vl_id": "ext_mnet_net",
+ "description": "",
+ "cp_id": "m600_mnt_cp",
+ "properties": {"direction": "bidirectional",
+ "vnic_type": "normal",
+ "bandwidth": 0,
+ "mac_address": "00-11-00-22-33-11",
+ "interface_name": "gei-0/4/0/1",
+ "ip_address": "10.46.244.51",
+ "order": 0,
+ "sfc_encapsulation": "mac",
+ "bond": "none"}}],
+ "metadata": {"invariant_id": "vcpe_ns_sff_1",
+ "name": "VCPE_NS",
+ "csarVersion": "v1.0",
+ "csarType": "NSAR",
+ "csarProvider": "ZTE",
+ "version": 1,
+ "vendor": "ZTE",
+ "id": "VCPE_NS",
+ "description": "vcpe_ns"}}
def tearDown(self):
pass
def test_ns_pkg_distribute_when_ns_exists(self):
NSPackageModel(nsPackageId="1", nsdId="2").save()
- resp = self.client.post("/api/catalog/v1/nspackages", {"csarId": "1"}, format='json')
+ resp = self.client.post(
+ "/api/catalog/v1/nspackages", {"csarId": "1"}, format='json')
self.assertEqual(resp.status_code, status.HTTP_202_ACCEPTED)
self.assertEqual("failed", resp.data["status"])
- self.assertEqual("NS CSAR(1) already exists.", resp.data["statusDescription"])
+ self.assertEqual(
+ "NS CSAR(1) already exists.",
+ resp.data["statusDescription"])
@mock.patch.object(restcall, 'call_req')
def test_ns_pkg_distribute_when_csar_not_exist(self, mock_call_req):
mock_call_req.return_value = [0, "[]", '200']
- resp = self.client.post("/api/catalog/v1/nspackages", {"csarId": "1"}, format='json')
+ resp = self.client.post(
+ "/api/catalog/v1/nspackages", {"csarId": "1"}, format='json')
self.assertEqual(resp.status_code, status.HTTP_202_ACCEPTED)
self.assertEqual("failed", resp.data["status"])
- self.assertEqual("Failed to query artifact(services,1) from sdc.", resp.data["statusDescription"])
+ self.assertEqual(
+ "Failed to query artifact(services,1) from sdc.",
+ resp.data["statusDescription"])
@mock.patch.object(restcall, 'call_req')
@mock.patch.object(sdc, 'download_artifacts')
@mock.patch.object(toscaparser, 'parse_nsd')
- def test_ns_pkg_distribute_when_nsd_already_exists(self,
- mock_parse_nsd, mock_download_artifacts, mock_call_req):
+ def test_ns_pkg_distribute_when_nsd_already_exists(
+ self, mock_parse_nsd, mock_download_artifacts, mock_call_req):
mock_parse_nsd.return_value = json.JSONEncoder().encode(self.nsd_data)
mock_download_artifacts.return_value = "/home/vcpe.csar"
mock_call_req.return_value = [0, json.JSONEncoder().encode([{
@@ -413,32 +277,38 @@ class TestNsPackage(TestCase):
"toscaModelURL": "https://127.0.0.1:1234/sdc/v1/vcpe.csar"
}]), '200']
NSPackageModel(nsPackageId="2", nsdId="VCPE_NS").save()
- resp = self.client.post("/api/catalog/v1/nspackages", {"csarId": "1"}, format='json')
+ resp = self.client.post(
+ "/api/catalog/v1/nspackages", {"csarId": "1"}, format='json')
self.assertEqual(resp.status_code, status.HTTP_202_ACCEPTED)
self.assertEqual("failed", resp.data["status"])
- self.assertEqual("NSD(VCPE_NS) already exists.", resp.data["statusDescription"])
+ self.assertEqual(
+ "NSD(VCPE_NS) already exists.",
+ resp.data["statusDescription"])
@mock.patch.object(restcall, 'call_req')
@mock.patch.object(sdc, 'download_artifacts')
@mock.patch.object(toscaparser, 'parse_nsd')
- def test_ns_pkg_distribute_when_nf_not_distributed(self,
- mock_parse_nsd, mock_download_artifacts, mock_call_req):
+ def test_ns_pkg_distribute_when_nf_not_distributed(
+ self, mock_parse_nsd, mock_download_artifacts, mock_call_req):
mock_parse_nsd.return_value = json.JSONEncoder().encode(self.nsd_data)
mock_download_artifacts.return_value = "/home/vcpe.csar"
mock_call_req.return_value = [0, json.JSONEncoder().encode([{
"uuid": "1",
"toscaModelURL": "https://127.0.0.1:1234/sdc/v1/vcpe.csar"
}]), '200']
- resp = self.client.post("/api/catalog/v1/nspackages", {"csarId": "1"}, format='json')
+ resp = self.client.post(
+ "/api/catalog/v1/nspackages", {"csarId": "1"}, format='json')
self.assertEqual(resp.status_code, status.HTTP_202_ACCEPTED)
self.assertEqual("failed", resp.data["status"])
- self.assertEqual("VNF package(vcpe_vfw_zte_1_0) is not distributed.", resp.data["statusDescription"])
+ self.assertEqual(
+ "VNF package(vcpe_vfw_zte_1_0) is not distributed.",
+ resp.data["statusDescription"])
@mock.patch.object(restcall, 'call_req')
@mock.patch.object(sdc, 'download_artifacts')
@mock.patch.object(toscaparser, 'parse_nsd')
- def test_ns_pkg_distribute_when_successfully(self,
- mock_parse_nsd, mock_download_artifacts, mock_call_req):
+ def test_ns_pkg_distribute_when_successfully(
+ self, mock_parse_nsd, mock_download_artifacts, mock_call_req):
mock_parse_nsd.return_value = json.JSONEncoder().encode(self.nsd_data)
mock_download_artifacts.return_value = "/home/vcpe.csar"
mock_call_req.return_value = [0, json.JSONEncoder().encode([{
@@ -446,58 +316,68 @@ class TestNsPackage(TestCase):
"toscaModelURL": "https://127.0.0.1:1234/sdc/v1/vcpe.csar"
}]), '200']
VnfPackageModel(vnfPackageId="1", vnfdId="vcpe_vfw_zte_1_0").save()
- resp = self.client.post("/api/catalog/v1/nspackages", {"csarId": "1"}, format='json')
+ resp = self.client.post(
+ "/api/catalog/v1/nspackages", {"csarId": "1"}, format='json')
self.assertEqual(resp.status_code, status.HTTP_202_ACCEPTED)
self.assertEqual("success", resp.data["status"])
- self.assertEqual("CSAR(1) distributed successfully.", resp.data["statusDescription"])
+ self.assertEqual(
+ "CSAR(1) distributed successfully.",
+ resp.data["statusDescription"])
- ###############################################################################################################
+ ##########################################################################
def test_ns_pkg_normal_delete(self):
NSPackageModel(nsPackageId="8", nsdId="2").save()
resp = self.client.delete("/api/catalog/v1/nspackages/8")
- self.assertEqual(resp.status_code, status.HTTP_202_ACCEPTED)
+ self.assertEqual(resp.status_code, status.HTTP_200_OK)
self.assertEqual("success", resp.data["status"])
- self.assertEqual("Delete CSAR(8) successfully.", resp.data["statusDescription"])
+ self.assertEqual(
+ "Delete CSAR(8) successfully.",
+ resp.data["statusDescription"])
def test_ns_pkg_get_all(self):
- NSPackageModel(nsPackageId="13", nsdId="2", nsdDesginer="2", nsdVersion="2",
- nsPackageUri="13.csar", nsdModel="").save()
- NSPackageModel(nsPackageId="14", nsdId="3", nsdDesginer="3", nsdVersion="3",
- nsPackageUri="14.csar", nsdModel="").save()
+ NSPackageModel(
+ nsPackageId="13",
+ nsdId="2",
+ nsdDesginer="2",
+ nsdVersion="2",
+ nsPackageUri="13.csar",
+ nsdModel="").save()
+ NSPackageModel(
+ nsPackageId="14",
+ nsdId="3",
+ nsdDesginer="3",
+ nsdVersion="3",
+ nsPackageUri="14.csar",
+ nsdModel="").save()
resp = self.client.get("/api/catalog/v1/nspackages")
self.assertEqual(resp.status_code, status.HTTP_200_OK)
- expect_data = [
- {
- "csarId": "13",
- "packageInfo": {
- "csarName": "13.csar",
- "nsdProvider": "2",
- "nsdId": "2",
- "nsPackageId": "13",
- "downloadUrl": "http://127.0.0.1:8806/static/catalog/13/13.csar",
- "nsdModel": "",
- "nsdVersion": "2"
- }
- },
- {
- "csarId": "14",
- "packageInfo": {
- "csarName": "14.csar",
- "nsdProvider": "3",
- "nsdId": "3",
- "nsPackageId": "14",
- "downloadUrl": "http://127.0.0.1:8806/static/catalog/14/14.csar",
- "nsdModel": "",
- "nsdVersion": "3"
- }
- }
- ]
+ expect_data = [{"csarId": "13",
+ "packageInfo": {"csarName": "13.csar",
+ "nsdProvider": "2",
+ "nsdId": "2",
+ "nsPackageId": "13",
+ "downloadUrl": "http://127.0.0.1:8806/static/catalog/13/13.csar",
+ "nsdModel": "",
+ "nsdVersion": "2"}},
+ {"csarId": "14",
+ "packageInfo": {"csarName": "14.csar",
+ "nsdProvider": "3",
+ "nsdId": "3",
+ "nsPackageId": "14",
+ "downloadUrl": "http://127.0.0.1:8806/static/catalog/14/14.csar",
+ "nsdModel": "",
+ "nsdVersion": "3"}}]
self.assertEqual(expect_data, resp.data)
def test_ns_pkg_get_one(self):
- NSPackageModel(nsPackageId="14", nsdId="2", nsdDesginer="3", nsdVersion="4",
- nsPackageUri="14.csar", nsdModel="").save()
+ NSPackageModel(
+ nsPackageId="14",
+ nsdId="2",
+ nsdDesginer="3",
+ nsdVersion="4",
+ nsPackageUri="14.csar",
+ nsdModel="").save()
resp = self.client.get("/api/catalog/v1/nspackages/14")
self.assertEqual(resp.status_code, status.HTTP_200_OK)
expect_data = {
@@ -509,24 +389,30 @@ class TestNsPackage(TestCase):
"nsdVersion": "4",
"csarName": "14.csar",
"nsdModel": "",
- "downloadUrl": "http://127.0.0.1:8806/static/catalog/14/14.csar"
- }
- }
+ "downloadUrl": "http://127.0.0.1:8806/static/catalog/14/14.csar"}}
self.assertEqual(expect_data, resp.data)
- ###############################################################################################################
+ ##########################################################################
@mock.patch.object(toscaparser, 'parse_nsd')
def test_nsd_parse_normal(self, mock_parse_nsd):
NSPackageModel(nsPackageId="18", nsdId="12").save()
mock_parse_nsd.return_value = json.JSONEncoder().encode({"a": "b"})
req_data = {"csarId": "18", "inputs": []}
- resp = self.client.post("/api/catalog/v1/parsernsd", req_data, format='json')
+ resp = self.client.post(
+ "/api/catalog/v1/parsernsd",
+ req_data,
+ format='json')
self.assertEqual(resp.status_code, status.HTTP_202_ACCEPTED)
self.assertEqual({"model": '{"a": "b"}'}, resp.data)
def test_nsd_parse_when_csar_not_exist(self):
req_data = {"csarId": "1", "inputs": []}
- resp = self.client.post("/api/catalog/v1/parsernsd", req_data, format='json')
- self.assertEqual(resp.status_code, status.HTTP_500_INTERNAL_SERVER_ERROR)
+ resp = self.client.post(
+ "/api/catalog/v1/parsernsd",
+ req_data,
+ format='json')
+ self.assertEqual(
+ resp.status_code,
+ status.HTTP_500_INTERNAL_SERVER_ERROR)
self.assertEqual(resp.data, {"error": "NS CSAR(1) does not exist."})
diff --git a/catalog/packages/views.py b/catalog/packages/views.py
index a5922d3d..73cc3dbf 100644
--- a/catalog/packages/views.py
+++ b/catalog/packages/views.py
@@ -21,108 +21,340 @@ from rest_framework.decorators import api_view
from catalog.pub.utils.values import ignore_case_get
from catalog.packages import nf_package
from catalog.packages import ns_package
+from catalog.serializers import NsPackagesSerializer
+from catalog.serializers import NsPackageSerializer
+from catalog.serializers import NfPackagesSerializer
+from catalog.serializers import NsPackageDistributeRequestSerializer
+from catalog.serializers import NsPackageDistributeResponseSerializer
+from catalog.serializers import NfPackageDistributeRequestSerializer
+from catalog.serializers import NfPackageSerializer
+from catalog.serializers import ParseModelRequestSerializer
+from catalog.serializers import ParseModelResponseSerializer
+from catalog.serializers import InternalErrorRequestSerializer
+from catalog.serializers import PostJobResponseSerializer
+from drf_yasg import openapi
+from drf_yasg.utils import no_body, swagger_auto_schema
logger = logging.getLogger(__name__)
+@swagger_auto_schema(
+ method='POST',
+ operation_description="On distribute NS package",
+ request_body=NsPackageDistributeRequestSerializer,
+ responses={
+ status.HTTP_202_ACCEPTED: NsPackageDistributeResponseSerializer,
+ status.HTTP_500_INTERNAL_SERVER_ERROR: InternalErrorRequestSerializer})
+@swagger_auto_schema(
+ method='GET',
+ operation_description="Query NS packages",
+ request_body=no_body,
+ responses={
+ status.HTTP_200_OK: NsPackagesSerializer,
+ status.HTTP_500_INTERNAL_SERVER_ERROR: InternalErrorRequestSerializer})
@api_view(http_method_names=['POST', 'GET'])
def nspackages_rc(request, *args, **kwargs):
logger.debug("Enter %s, method is %s", fun_name(), request.method)
- ret, normal_status = None, None
+ ret, normal_status, response_serializer, validation_error = None, None, None, None
if request.method == 'GET':
# Gets ns package list
ret = ns_package.ns_get_csars()
normal_status = status.HTTP_200_OK
+
+ if ret[0] == 0:
+ response_serializer = NsPackagesSerializer(data=ret[1])
+ validation_error = handleValidatonError(
+ response_serializer, False)
+ if validation_error:
+ return validation_error
elif request.method == 'POST':
# Distributes the package accroding to the given csarId
+ request_serializer = NsPackageDistributeRequestSerializer(data=request.data)
+ validation_error = handleValidatonError(request_serializer, True)
+ if validation_error:
+ return validation_error
+
csar_id = ignore_case_get(request.data, "csarId")
logger.debug("csar_id is %s", csar_id)
ret = ns_package.ns_on_distribute(csar_id)
normal_status = status.HTTP_202_ACCEPTED
+
logger.debug("Leave %s, Return value is %s", fun_name(), ret)
if ret[0] != 0:
- return Response(data={'error': ret[1]}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
+ return Response(
+ data={
+ 'error': ret[1]},
+ status=status.HTTP_500_INTERNAL_SERVER_ERROR)
+
return Response(data=ret[1], status=normal_status)
+@swagger_auto_schema(
+ method='POST',
+ operation_description="On distribute Nf package",
+ request_body=NfPackageDistributeRequestSerializer(),
+ responses={
+ status.HTTP_202_ACCEPTED: PostJobResponseSerializer,
+ status.HTTP_500_INTERNAL_SERVER_ERROR: InternalErrorRequestSerializer})
+@swagger_auto_schema(
+ method='GET',
+ operation_description="Query Nf packages",
+ request_body=no_body,
+ responses={
+ status.HTTP_200_OK: NfPackagesSerializer,
+ status.HTTP_500_INTERNAL_SERVER_ERROR: InternalErrorRequestSerializer})
@api_view(http_method_names=['POST', 'GET'])
def nfpackages_rc(request, *args, **kwargs):
- logger.debug("Enter %s%s, method is %s", fun_name(), request.data, request.method)
- ret, normal_status = None, None
+ logger.debug(
+ "Enter %s%s, method is %s",
+ fun_name(),
+ request.data,
+ request.method)
+ ret, normal_status, response_serializer, validation_error = None, None, None, None
if request.method == 'GET':
ret = nf_package.nf_get_csars()
normal_status = status.HTTP_200_OK
+ response_serializer = NfPackagesSerializer(data=ret[1])
elif request.method == 'POST':
- csar_id = ignore_case_get(request.data, "csarId")
- vim_ids = ignore_case_get(request.data, "vimIds")
- lab_vim_id = ignore_case_get(request.data, "labVimId")
+ request_serivalizer = NfPackageDistributeRequestSerializer(
+ data=request.data)
+ validation_error = handleValidatonError(
+ request_serivalizer, True)
+ if validation_error:
+ return validation_error
+
+ csar_id = ignore_case_get(request_serivalizer.data, "csarId")
+ vim_ids = ignore_case_get(request_serivalizer.data, "vimIds")
+ lab_vim_id = ignore_case_get(request_serivalizer.data, "labVimId")
job_id = str(uuid.uuid4())
- nf_package.NfDistributeThread(csar_id, vim_ids, lab_vim_id, job_id).start()
+ nf_package.NfDistributeThread(
+ csar_id, vim_ids, lab_vim_id, job_id).start()
ret = [0, {"jobId": job_id}]
normal_status = status.HTTP_202_ACCEPTED
+
+ response_serializer = PostJobResponseSerializer(data=ret[1])
logger.debug("Leave %s, Return value is %s", fun_name(), ret)
+
if ret[0] != 0:
- return Response(data={'error': ret[1]}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
- return Response(data=ret[1], status=normal_status)
+ return Response(
+ data={
+ 'error': ret[1]},
+ status=status.HTTP_500_INTERNAL_SERVER_ERROR)
+
+ validation_error = handleValidatonError(
+ response_serializer, False)
+ if validation_error:
+ return validation_error
+
+ return Response(data=response_serializer.data, status=normal_status)
+@swagger_auto_schema(
+ method='DELETE',
+ operation_description="Delete one NS package",
+ request_body=no_body,
+ manual_parameters=[
+ openapi.Parameter(
+ 'csarId',
+ openapi.IN_QUERY,
+ "csarId",
+ type=openapi.TYPE_STRING)],
+ responses={
+ status.HTTP_200_OK: NsPackageDistributeResponseSerializer,
+ status.HTTP_500_INTERNAL_SERVER_ERROR: openapi.Response(
+ 'error message',
+ openapi.Schema(
+ type=openapi.TYPE_STRING))})
+@swagger_auto_schema(
+ method='GET',
+ operation_description="Query one NS package",
+ request_body=no_body,
+ manual_parameters=[
+ openapi.Parameter(
+ 'csarId',
+ openapi.IN_QUERY,
+ "csarId",
+ type=openapi.TYPE_STRING)],
+ responses={
+ status.HTTP_200_OK: NsPackageSerializer,
+ status.HTTP_500_INTERNAL_SERVER_ERROR: openapi.Response(
+ 'error message',
+ openapi.Schema(
+ type=openapi.TYPE_STRING))})
@api_view(http_method_names=['DELETE', 'GET'])
def ns_rd_csar(request, *args, **kwargs):
csar_id = ignore_case_get(kwargs, "csarId")
- logger.info("Enter %s, method is %s, csar_id is %s", fun_name(), request.method, csar_id)
- ret, normal_status = None, None
+ logger.info("Enter %s, method is %s, csar_id is %s",
+ fun_name(), request.method, csar_id)
+ ret, normal_status, response_serializer, validation_error = None, None, None, None
if request.method == 'GET':
ret = ns_package.ns_get_csar(csar_id)
normal_status = status.HTTP_200_OK
+ if ret[0] == 0:
+ response_serializer = NsPackageSerializer(data=ret[1])
+ validation_error = handleValidatonError(response_serializer, False)
+ if validation_error:
+ return validation_error
elif request.method == 'DELETE':
ret = ns_package.ns_delete_csar(csar_id)
- normal_status = status.HTTP_202_ACCEPTED
+ normal_status = status.HTTP_200_OK
logger.info("Leave %s, Return value is %s", fun_name(), ret)
if ret[0] != 0:
- return Response(data={'error': ret[1]}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
+ return Response(
+ data={
+ 'error': ret[1]},
+ status=status.HTTP_500_INTERNAL_SERVER_ERROR)
return Response(data=ret[1], status=normal_status)
+@swagger_auto_schema(
+ method='DELETE',
+ operation_description="Delete one Nf package",
+ request_body=no_body,
+ manual_parameters=[
+ openapi.Parameter(
+ 'csarId',
+ openapi.IN_QUERY,
+ "csarId",
+ type=openapi.TYPE_STRING)],
+ responses={
+ status.HTTP_202_ACCEPTED: PostJobResponseSerializer,
+ status.HTTP_500_INTERNAL_SERVER_ERROR: openapi.Response(
+ 'error message',
+ openapi.Schema(
+ type=openapi.TYPE_STRING))})
+@swagger_auto_schema(
+ method='GET',
+ operation_description="Query one Nf package",
+ request_body=no_body,
+ manual_parameters=[
+ openapi.Parameter(
+ 'csarId',
+ openapi.IN_QUERY,
+ "csarId",
+ type=openapi.TYPE_STRING)],
+ responses={
+ status.HTTP_200_OK: NfPackageSerializer,
+ status.HTTP_500_INTERNAL_SERVER_ERROR: openapi.Response(
+ 'error message',
+ openapi.Schema(
+ type=openapi.TYPE_STRING))})
@api_view(http_method_names=['DELETE', 'GET'])
def nf_rd_csar(request, *args, **kwargs):
csar_id = ignore_case_get(kwargs, "csarId")
- logger.info("Enter %s, method is %s, csar_id is %s", fun_name(), request.method, csar_id)
- ret, normal_status = None, None
+ logger.info("Enter %s, method is %s, csar_id is %s",
+ fun_name(), request.method, csar_id)
+ ret, normal_status, response_serializer, validation_error = None, None, None, None
+
if request.method == 'GET':
ret = nf_package.nf_get_csar(csar_id)
normal_status = status.HTTP_200_OK
+ response_serializer = NfPackageSerializer(data=ret[1])
+
elif request.method == 'DELETE':
job_id = str(uuid.uuid4())
nf_package.NfPkgDeleteThread(csar_id, job_id).start()
ret = [0, {"jobId": job_id}]
normal_status = status.HTTP_202_ACCEPTED
+ response_serializer = PostJobResponseSerializer(data=ret[1])
+
logger.info("Leave %s, Return value is %s", fun_name(), ret)
if ret[0] != 0:
- return Response(data={'error': ret[1]}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
- return Response(data=ret[1], status=normal_status)
+ return Response(
+ data={
+ 'error': ret[1]},
+ status=status.HTTP_500_INTERNAL_SERVER_ERROR)
+
+ validation_error = handleValidatonError(
+ response_serializer, False)
+ if validation_error:
+ return validation_error
+ return Response(data=response_serializer.data, status=normal_status)
+
+@swagger_auto_schema(
+ method='POST',
+ operation_description="Parse NS model",
+ request_body=ParseModelRequestSerializer,
+ responses={
+ status.HTTP_202_ACCEPTED: ParseModelResponseSerializer,
+ status.HTTP_500_INTERNAL_SERVER_ERROR: InternalErrorRequestSerializer})
@api_view(http_method_names=['POST'])
def ns_model_parser(request, *args, **kwargs):
csar_id = ignore_case_get(request.data, "csarId")
inputs = ignore_case_get(request.data, "inputs")
- logger.debug("Enter %s, csar_id=%s, inputs=%s", fun_name(), csar_id, inputs)
+ logger.debug(
+ "Enter %s, csar_id=%s, inputs=%s",
+ fun_name(),
+ csar_id,
+ inputs)
ret = ns_package.parse_nsd(csar_id, inputs)
logger.info("Leave %s, Return value is %s", fun_name(), ret)
if ret[0] != 0:
- return Response(data={'error': ret[1]}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
- return Response(data=ret[1], status=status.HTTP_202_ACCEPTED)
+ return Response(
+ data={
+ 'error': ret[1]},
+ status=status.HTTP_500_INTERNAL_SERVER_ERROR)
+
+ response_serializer = ParseModelResponseSerializer(data=ret[1])
+ validation_error = handleValidatonError(
+ response_serializer, False)
+ if validation_error:
+ return validation_error
+
+ return Response(data=response_serializer.data, status=status.HTTP_202_ACCEPTED)
+@swagger_auto_schema(
+ method='POST',
+ operation_description="Parse NF model",
+ request_body=ParseModelRequestSerializer,
+ responses={
+ status.HTTP_202_ACCEPTED: ParseModelResponseSerializer,
+ status.HTTP_500_INTERNAL_SERVER_ERROR: InternalErrorRequestSerializer})
@api_view(http_method_names=['POST'])
def vnf_model_parser(request, *args, **kwargs):
csar_id = ignore_case_get(request.data, "csarId")
inputs = ignore_case_get(request.data, "inputs")
- logger.debug("Enter %s, csar_id=%s, inputs=%s", fun_name(), csar_id, inputs)
+ logger.debug(
+ "Enter %s, csar_id=%s, inputs=%s",
+ fun_name(),
+ csar_id,
+ inputs)
ret = nf_package.parse_vnfd(csar_id, inputs)
logger.info("Leave %s, Return value is %s", fun_name(), ret)
if ret[0] != 0:
- return Response(data={'error': ret[1]}, status=status.HTTP_500_INTERNAL_SERVER_ERROR)
- return Response(data=ret[1], status=status.HTTP_202_ACCEPTED)
+ return Response(
+ data={
+ 'error': ret[1]},
+ status=status.HTTP_500_INTERNAL_SERVER_ERROR)
+
+ response_serializer = ParseModelResponseSerializer(data=ret[1])
+ validation_error = handleValidatonError(
+ response_serializer, False)
+ if validation_error:
+ return validation_error
+
+ return Response(data=response_serializer.data, status=status.HTTP_202_ACCEPTED)
+
+
+def handleValidatonError(base_serializer, is_request):
+ response = None
+
+ if not base_serializer.is_valid():
+ errormessage = base_serializer.errors
+ logger.error(errormessage)
+
+ if is_request:
+ message = 'Invalid request'
+ else:
+ message = 'Invalid response'
+ logger.error(message)
+ response = Response(
+ data={'error': errormessage},
+ status=status.HTTP_500_INTERNAL_SERVER_ERROR)
+
+ return response
diff --git a/catalog/pub/config/config.py b/catalog/pub/config/config.py
index da0dfade..0086e99a 100644
--- a/catalog/pub/config/config.py
+++ b/catalog/pub/config/config.py
@@ -28,6 +28,11 @@ DB_NAME = "nfvocatalog"
DB_USER = "nfvocatalog"
DB_PASSWD = "nfvocatalog"
+# [MDC]
+SERVICE_NAME = "catalog"
+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/catalog/pub/utils/toscaparser/basemodel.py b/catalog/pub/utils/toscaparser/basemodel.py
index 7d2595ad..205bdb4e 100644
--- a/catalog/pub/utils/toscaparser/basemodel.py
+++ b/catalog/pub/utils/toscaparser/basemodel.py
@@ -161,7 +161,8 @@ class BaseInfoModel(object):
def buidMetadata(self, tosca):
if 'metadata' in tosca.tpl:
self.metadata = copy.deepcopy(tosca.tpl['metadata'])
- self.metadata['id'] = tosca.tpl['metadata']['UUID']
+ if tosca.tpl['metadata'].get('UUID', ''):
+ self.metadata['id'] = tosca.tpl['metadata']['UUID']
def buildProperties(self, nodeTemplate, parsed_params):
properties = {}
diff --git a/catalog/pub/utils/toscaparser/testdata/resource-ZteMmeFixVl-csar.csar b/catalog/pub/utils/toscaparser/testdata/resource-ZteMmeFixVl-csar.csar
new file mode 100644
index 00000000..4d7e3984
--- /dev/null
+++ b/catalog/pub/utils/toscaparser/testdata/resource-ZteMmeFixVl-csar.csar
Binary files differ
diff --git a/catalog/pub/utils/toscaparser/tests.py b/catalog/pub/utils/toscaparser/tests.py
new file mode 100644
index 00000000..bbf7e0da
--- /dev/null
+++ b/catalog/pub/utils/toscaparser/tests.py
@@ -0,0 +1,34 @@
+# Copyright 2018 ZTE Corporation.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+import json
+import os
+
+from django.test import TestCase
+
+from catalog.pub.utils.toscaparser import parse_vnfd
+
+
+class TestToscaparser(TestCase):
+ def setUp(self):
+ pass
+
+ def tearDown(self):
+ pass
+
+ def test_nsd_parse(self):
+ csar_path = os.path.dirname(os.path.abspath(__file__)) + "/testdata/resource-ZteMmeFixVl-csar.csar"
+ input_parameters = [{"value": "111111", "key": "sdncontroller"}]
+ vnfd_json = parse_vnfd(csar_path, input_parameters)
+ metadata = json.loads(vnfd_json).get("metadata")
+ self.assertEqual("ZTE-MME-FIX-VL", metadata.get("name", ""))
diff --git a/catalog/serializers.py b/catalog/serializers.py
new file mode 100644
index 00000000..d05e1aee
--- /dev/null
+++ b/catalog/serializers.py
@@ -0,0 +1,206 @@
+# 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
+
+from catalog.pub.utils.toscaparser.nsdmodel import EtsiNsdInfoModel
+from catalog.pub.utils.toscaparser.vnfdmodel import EtsiVnfdInfoModel
+
+
+class PostJobRequestSerializer(serializers.Serializer):
+ progress = serializers.CharField(help_text="Job Progress", required=False)
+ desc = serializers.CharField(help_text="Description", required=False)
+ errcode = serializers.CharField(help_text="Error Code", required=False)
+
+
+class JobResponseHistoryListSerializer(serializers.Serializer):
+ status = serializers.CharField(help_text="Status", required=False)
+ progress = serializers.CharField(help_text="Job Progress", required=False)
+ statusDescription = serializers.CharField(
+ help_text="Status Description", required=False)
+ errorCode = serializers.CharField(help_text="Error Code", required=False)
+ responseId = serializers.CharField(help_text="Response Id", required=False)
+
+
+class JobResponseDescriptorSerializer(serializers.Serializer):
+ status = serializers.CharField(help_text="Status", required=False)
+ progress = serializers.CharField(help_text="Job Progress", required=False)
+ statusDescription = serializers.CharField(
+ help_text="Status Description", required=False)
+ errorCode = serializers.CharField(help_text="Error Code", required=False)
+ responseId = serializers.CharField(help_text="Response Id", required=False)
+ responseHistoryList = JobResponseHistoryListSerializer(
+ many=True, help_text="Response History List", required=False)
+
+
+class GetJobResponseSerializer(serializers.Serializer):
+ jobId = serializers.CharField(
+ help_text="Job Id",
+ required=False)
+ responseDescriptor = JobResponseDescriptorSerializer(
+ help_text="Job Response Descriptor", required=False)
+
+
+class PostJobResponseResultSerializer(serializers.Serializer):
+ result = serializers.CharField(help_text="Result", required=True)
+ msg = serializers.CharField(help_text="Message", required=False)
+
+
+class InternalErrorRequestSerializer(serializers.Serializer):
+ error = serializers.CharField(help_text="Error", required=True)
+ errorMessage = serializers.CharField(help_text="Error Message", required=False)
+
+
+class NsPackageDistributeRequestSerializer(serializers.Serializer):
+ csarId = serializers.CharField(help_text="csarId", required=True)
+
+
+class NsPackageDistributeResponseSerializer(serializers.Serializer):
+ status = serializers.CharField(help_text="status", required=True)
+ statusDescription = serializers.CharField(help_text="statusDescription", required=True)
+ errorCode = serializers.CharField(help_text="errorCode", required=True)
+
+
+class NsPackageInfoSerializer(serializers.Serializer):
+ nsdId = serializers.CharField(help_text="NSD ID", required=True)
+ nsPackageId = serializers.CharField(
+ help_text="NS Package ID", allow_blank=True, required=True)
+ nsdProvider = serializers.CharField(
+ help_text="NSD Provider", allow_blank=True, required=True)
+ nsdVersion = serializers.CharField(
+ help_text="NSD Version",
+ allow_blank=True,
+ required=True)
+ csarName = serializers.CharField(
+ help_text="CSAR name",
+ allow_blank=True,
+ required=True)
+ nsdModel = serializers.CharField(
+ help_text="NSD Model",
+ allow_blank=True,
+ required=True)
+ downloadUrl = serializers.CharField(
+ help_text="URL to download NSD Model", required=True)
+
+
+class NsPackageSerializer(serializers.Serializer):
+ csarId = serializers.CharField(help_text="CSAR ID", required=True)
+ packageInfo = NsPackageInfoSerializer(
+ help_text="NS Package Info", required=True)
+
+
+class NsPackagesSerializer(serializers.ListSerializer):
+ child = NsPackageSerializer()
+
+
+class NfPackageDistributeRequestSerializer(serializers.Serializer):
+ csarId = serializers.CharField(help_text="CSAR ID", required=True)
+ vimIds = serializers.ListField(
+ help_text="A string for vimIds",
+ child=serializers.CharField(),
+ required=False)
+ labVimId = serializers.CharField(
+ help_text="A list of VIM IDs.",
+ allow_blank=True,
+ required=False)
+
+
+class NfPackageInfoSerializer(serializers.Serializer):
+ vnfdId = serializers.CharField(
+ help_text="VNFD ID",
+ required=True,
+ allow_blank=True)
+ vnfPackageId = serializers.CharField(
+ help_text="VNF Package ID", required=True)
+ vnfdProvider = serializers.CharField(
+ help_text="VNFD Provider", required=True, allow_blank=True)
+ vnfdVersion = serializers.CharField(
+ help_text="VNFD Version", required=True, allow_blank=True)
+ vnfVersion = serializers.CharField(
+ help_text="VNF Version",
+ required=True,
+ allow_blank=True)
+ csarName = serializers.CharField(
+ help_text="CSAR Name",
+ required=True,
+ allow_blank=True)
+ vnfdModel = serializers.CharField(
+ help_text="VNFD Model",
+ required=True,
+ allow_blank=True)
+ downloadUrl = serializers.CharField(
+ help_text="URL to download VNFD Model",
+ required=True,
+ allow_blank=True)
+
+
+class NfImageInfoSerializer(serializers.Serializer):
+ index = serializers.CharField(
+ help_text="Index of VNF Image",
+ required=True)
+ fileName = serializers.CharField(
+ help_text="Image file name", required=True)
+ imageId = serializers.CharField(help_text="Image ID", required=True)
+ vimId = serializers.CharField(help_text="VIM ID", required=True)
+ vimUser = serializers.CharField(help_text="User of VIM", required=True)
+ tenant = serializers.CharField(help_text="Tenant", required=True)
+ status = serializers.CharField(help_text="Status", required=True)
+
+
+class NfPackageSerializer(serializers.Serializer):
+ csarId = serializers.CharField(help_text="CSAR ID", required=True)
+ packageInfo = NfPackageInfoSerializer(
+ help_text="VNF Package Info", required=True)
+ imageInfo = NfImageInfoSerializer(
+ help_text="Image Info",
+ required=False,
+ many=True,
+ allow_null=True)
+
+
+class NfPackagesSerializer(serializers.ListSerializer):
+ child = NfPackageSerializer()
+
+
+class PostJobResponseSerializer(serializers.Serializer):
+ jobId = serializers.CharField(help_text="jobId", required=True)
+
+
+class ParseModelRequestSerializer(serializers.Serializer):
+ csarId = serializers.CharField(help_text="CSAR ID", required=True)
+ inputs = serializers.JSONField(help_text="Inputs", required=False)
+
+
+class ParseModelResponseSerializer(serializers.Serializer):
+ model = serializers.JSONField(help_text="Model", required=True)
+
+
+class EtsiNsdInfoModelSerializer(serializers.ModelSerializer):
+
+ class Meta:
+ model = EtsiNsdInfoModel
+
+
+class EtsiVnfdInfoModelSerializer(serializers.ModelSerializer):
+
+ class Meta:
+ model = EtsiVnfdInfoModel
+
+
+class ParseNSPackageResponseSerializer(serializers.Serializer):
+ model = EtsiNsdInfoModelSerializer(help_text="NSD Model", required=True)
+
+
+class ParseNfPackageResponseSerializer(serializers.Serializer):
+ model = EtsiVnfdInfoModelSerializer(help_text="VNFD Model", required=True)
diff --git a/catalog/settings.py b/catalog/settings.py
index 3c13adeb..ff19ff25 100644
--- a/catalog/settings.py
+++ b/catalog/settings.py
@@ -19,7 +19,10 @@ import redisco
from catalog.pub.config.config import REDIS_HOST, REDIS_PORT, REDIS_PASSWD
from catalog.pub.config.config import DB_NAME, DB_IP, DB_USER, DB_PASSWD, DB_PORT
-from catalog.pub.config import config
+from catalog.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
@@ -46,7 +49,33 @@ INSTALLED_APPS = [
'rest_framework',
'catalog.pub.database',
'catalog.samples',
- 'catalog.swagger'
+ 'catalog.swagger',
+
+ 'drf_yasg',
+]
+
+# drf-yasg
+SWAGGER_SETTINGS = {
+ 'LOGIN_URL': '/admin/login',
+ 'LOGOUT_URL': '/admin/logout',
+
+ 'DEFAULT_INFO': 'catalog.urls.swagger_info'
+}
+
+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',
+ ],
+ },
+ },
]
MIDDLEWARE_CLASSES = [
@@ -58,6 +87,7 @@ MIDDLEWARE_CLASSES = [
'django.contrib.auth.middleware.SessionAuthenticationMiddleware',
'django.contrib.messages.middleware.MessageMiddleware',
'django.middleware.clickjacking.XFrameOptionsMiddleware',
+ 'catalog.middleware.LogContextMiddleware',
]
ROOT_URLCONF = 'catalog.urls'
@@ -102,41 +132,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': {
- 'catalog_handler': {
- 'level': 'DEBUG',
- 'class': 'logging.handlers.RotatingFileHandler',
- 'filename': os.path.join(BASE_DIR, 'logs/runtime_catalog.log'),
- 'formatter': 'standard',
- 'maxBytes': 1024 * 1024 * 50,
- 'backupCount': 5,
- },
- },
-
- 'loggers': {
- 'catalog': {
- 'handlers': ['catalog_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': {
+# 'catalog_handler': {
+# 'level': 'DEBUG',
+# 'class': 'logging.handlers.RotatingFileHandler',
+# 'filename': os.path.join(BASE_DIR, 'logs/runtime_catalog.log'),
+# 'formatter': 'standard',
+# 'maxBytes': 1024 * 1024 * 50,
+# 'backupCount': 5,
+# },
+# },
+#
+# 'loggers': {
+# 'catalog': {
+# 'handlers': ['catalog_handler'],
+# 'level': 'DEBUG',
+# 'propagate': False
+# },
+# }
+# }
+
+LOGGING_CONFIG = None
+# yaml configuration of logging
+LOGGING_FILE = os.path.join(BASE_DIR, 'catalog/log.yml')
+log_config.yamlConfig(filepath=LOGGING_FILE, watchDog=True)
if 'test' in sys.argv:
- config.REG_TO_MSB_WHEN_START = False
+ pub_config.REG_TO_MSB_WHEN_START = False
DATABASES = {}
DATABASES['default'] = {
'ENGINE': 'django.db.backends.sqlite3',
diff --git a/catalog/swagger/urls.py b/catalog/swagger/urls.py
index a7da03d1..b5e91f07 100644
--- a/catalog/swagger/urls.py
+++ b/catalog/swagger/urls.py
@@ -12,13 +12,10 @@
# 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 catalog.swagger.views import SwaggerJsonView
-urlpatterns = patterns('',
- url(r'^api/catalog/v1/swagger.json$', SwaggerJsonView.as_view())
- )
-
-urlpatterns = format_suffix_patterns(urlpatterns)
+urlpatterns = [
+ url(r'^api/catalog/v1/swagger.json$', SwaggerJsonView.as_view())
+]
diff --git a/catalog/swagger/vfc.catalog.swagger.json b/catalog/swagger/vfc.catalog.swagger.json
index 39e8e6ab..b5f784c9 100644
--- a/catalog/swagger/vfc.catalog.swagger.json
+++ b/catalog/swagger/vfc.catalog.swagger.json
@@ -141,8 +141,8 @@
}
],
"responses": {
- "202": {
- "description": "",
+ "200": {
+ "description": "Delete NS Package Response",
"schema": {
"$ref": "#/definitions/NsPkgDelResponse"
}
@@ -329,7 +329,7 @@
],
"responses": {
"202": {
- "description": "",
+ "description": "Delete VNF Pakcage Response",
"schema": {
"$ref": "#/definitions/VnfPkgDelResponse"
}
@@ -390,7 +390,7 @@
"job"
],
"summary": "jobstatus",
- "description": "",
+ "description": "Get Job Status",
"operationId": "get_jobstatus",
"parameters": [
{
@@ -409,7 +409,41 @@
}
],
"responses": {
- "202": {
+ "200": {
+ "description": "",
+ "schema": {
+ "$ref": "#/definitions/JobDetailInfo"
+ }
+ }
+ }
+ },
+ "post": {
+ "tags": [
+ "job"
+ ],
+ "summary": "Update Job Status",
+ "description": "Update Job Status",
+ "operationId": "post_jobstatus",
+ "parameters": [
+ {
+ "required": true,
+ "type": "string",
+ "description": "job Id",
+ "name": "jobId",
+ "in": "path"
+ },
+ {
+ "required": true,
+ "schema": {
+ "$ref": "#/definitions/PostJobRequest"
+ },
+ "description": "job status",
+ "name": "responseId",
+ "in": "body"
+ }
+ ],
+ "responses": {
+ "200": {
"description": "",
"schema": {
"$ref": "#/definitions/JobDetailInfo"
@@ -477,9 +511,6 @@
},
"packageInfo": {
"$ref": "#/definitions/NsPkgInfo"
- },
- "NsInstanceInfo": {
- "$ref": "#/definitions/NsInstListInfo"
}
}
},
@@ -588,9 +619,6 @@
},
"imageInfo": {
"$ref": "#/definitions/VnfPkgImgListInfo"
- },
- "vnfInstanceInfo": {
- "$ref": "#/definitions/VnfInstListInfo"
}
}
},
@@ -712,6 +740,20 @@
}
}
},
+ "PostJobRequest": {
+ "type": "object",
+ "properties": {
+ "progress": {
+ "type": "string"
+ },
+ "desc": {
+ "type": "string"
+ },
+ "errcode": {
+ "type": "string"
+ }
+ }
+ },
"JobDetailInfo":{
"type": "object",
"properties": {
diff --git a/catalog/urls.py b/catalog/urls.py
index fbdf7e4b..291e9f92 100644
--- a/catalog/urls.py
+++ b/catalog/urls.py
@@ -14,8 +14,42 @@
from django.conf.urls import include, url
from catalog.pub.config.config import REG_TO_MSB_WHEN_START, REG_TO_MSB_REG_URL, REG_TO_MSB_REG_PARAM
+from rest_framework import permissions
+
+from drf_yasg import openapi
+from drf_yasg.views import get_schema_view
+
+
+# Add code for generating swagger automatically.
+swagger_info = openapi.Info(
+ title="Snippets API",
+ default_version='v1',
+ description="""This is a VFC project for the catalog."""
+)
+
+SchemaView = get_schema_view(
+ validators=['ssv', 'flex'],
+ public=True,
+ permission_classes=(permissions.AllowAny,),
+)
+
urlpatterns = [
+
+ # Add code for generating swagger automatically.
+ 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'),
url(r'^', include('catalog.samples.urls')),
url(r'^', include('catalog.packages.urls')),
url(r'^', include('catalog.jobs.urls')),
@@ -26,4 +60,7 @@ urlpatterns = [
if REG_TO_MSB_WHEN_START:
import json
from catalog.pub.utils.restcall import req_by_msb
- req_by_msb(REG_TO_MSB_REG_URL, "POST", json.JSONEncoder().encode(REG_TO_MSB_REG_PARAM))
+ req_by_msb(
+ REG_TO_MSB_REG_URL,
+ "POST",
+ json.JSONEncoder().encode(REG_TO_MSB_REG_PARAM))
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 9115e518..54b03c6b 100644
--- a/pom.xml
+++ b/pom.xml
@@ -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.catalog</groupId>
@@ -27,9 +27,70 @@
<packaging>pom</packaging>
<name>vfc-nfvo-catalog</name>
<description>vfc nfvo catalog</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 db0014ec..319d3263 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
@@ -23,4 +23,12 @@ unittest_xml_reporting==1.12.0
# for parser
cryptography==2.0.3
paramiko==2.0.2
-nfv-toscaparser>=0.5.0 \ No newline at end of file
+nfv-toscaparser==0.5.1.dev25
+
+# for auto swagger
+drf-yasg>=1.2.2
+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 c96b7a73..8623a421 100755
--- a/run.sh
+++ b/run.sh
@@ -13,4 +13,15 @@
# See the License for the specific language governing permissions and
# limitations under the License.
+logDir="/var/log/onap/vfc/catalog/"
+if [ ! -x $logDir ]; then
+ mkdir -p $logDir
+fi
+
nohup python manage.py runserver 0.0.0.0:8806 > /dev/null &
+
+while [ ! -f $logDir/runtime_catalog.log ]; do
+ sleep 1
+done
+
+tail -F $logDir/runtime_catalog.log \ No newline at end of file
diff --git a/tox.ini b/tox.ini
index 7facc7ce..fcc6330e 100644
--- a/tox.ini
+++ b/tox.ini
@@ -22,4 +22,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*"