summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authormaopengzhang <zhang.maopeng1@zte.com.cn>2018-09-12 21:00:41 +0800
committermaopengzhang <zhang.maopeng1@zte.com.cn>2018-09-13 22:53:28 +0800
commit5ae41760c1641e84b9e9d32a10f684c040a5fec5 (patch)
treef10137fdcdc1ae8c5247db4dfa9d127d388748ca
parent438606259fca179b732eeba350ba95f04f5ba838 (diff)
Support INVARIANTID in NSD
Support NSD InvariantID in Catalog Change-Id: Id59531454777d682d3b57ed7c05c25029bc8d8ce Issue-ID: VFC-635 Signed-off-by: maopengzhang <zhang.maopeng1@zte.com.cn>
-rw-r--r--catalog/packages/biz/ns_descriptor.py35
-rw-r--r--catalog/packages/biz/sdc_ns_package.py (renamed from catalog/packages/biz/nspackage.py)56
-rw-r--r--catalog/packages/biz/sdc_vnf_package.py (renamed from catalog/packages/biz/vnfpackage.py)0
-rw-r--r--catalog/packages/tests/test_nspackage.py10
-rw-r--r--catalog/packages/tests/test_vnfpackage.py2
-rw-r--r--catalog/packages/views/catalog_views.py22
-rw-r--r--catalog/pub/database/models.py1
-rw-r--r--catalog/pub/utils/toscaparser/__init__.py25
-rw-r--r--catalog/pub/utils/toscaparser/basemodel.py123
-rw-r--r--catalog/pub/utils/toscaparser/const.py27
-rw-r--r--catalog/pub/utils/toscaparser/nsdmodel.py5
-rw-r--r--catalog/pub/utils/toscaparser/pnfmodel.py6
-rw-r--r--catalog/pub/utils/toscaparser/servicemodel.py129
-rw-r--r--catalog/pub/utils/toscaparser/tests.py13
-rw-r--r--catalog/pub/utils/toscaparser/vnfdmodel.py6
15 files changed, 315 insertions, 145 deletions
diff --git a/catalog/packages/biz/ns_descriptor.py b/catalog/packages/biz/ns_descriptor.py
index d781e17b..9a484b20 100644
--- a/catalog/packages/biz/ns_descriptor.py
+++ b/catalog/packages/biz/ns_descriptor.py
@@ -25,20 +25,23 @@ from catalog.pub.database.models import NSPackageModel, PnfPackageModel, VnfPack
from catalog.pub.exceptions import CatalogException, ResourceNotFoundException
from catalog.pub.utils import fileutil, toscaparser
from catalog.pub.utils.values import ignore_case_get
+from catalog.pub.utils.toscaparser.const import NS_UUID, NS_INVARIANTUUID, NS_NAME, NS_VERSION, NS_DESIGNER, NS_DESCRIPTION
logger = logging.getLogger(__name__)
+METADATA = "metadata"
+
class NsDescriptor(object):
def __init__(self):
pass
- def create(self, data):
+ def create(self, data, id=None):
logger.info('Start to create a NSD...')
user_defined_data = ignore_case_get(data, 'userDefinedData')
data = {
- 'id': str(uuid.uuid4()),
+ 'id': id if id else str(uuid.uuid4()),
'nsdOnboardingState': PKG_STATUS.CREATED,
'nsdOperationalState': PKG_STATUS.DISABLED,
'nsdUsageState': PKG_STATUS.NOT_IN_USE,
@@ -116,31 +119,35 @@ class NsDescriptor(object):
logger.info('NSD(%s) has been downloaded.' % nsd_info_id)
return read(local_file_path, start, end)
- def parse_nsd_and_save(self, nsd_info_id, local_file_name):
+ def parse_nsd_and_save(self, nsd_info_id, local_file_name, isETSI=True):
logger.info('Start to process NSD(%s)...' % nsd_info_id)
ns_pkgs = NSPackageModel.objects.filter(nsPackageId=nsd_info_id)
ns_pkgs.update(onboardingState=PKG_STATUS.PROCESSING)
- nsd_json = toscaparser.parse_nsd(local_file_name)
+
+ nsd_json = toscaparser.parse_nsd(local_file_name, isETSI)
nsd = json.JSONDecoder().decode(nsd_json)
- nsd_id = nsd["metadata"]["id"]
- if nsd_id and NSPackageModel.objects.filter(nsdId=nsd_id):
- logger.info('NSD(%s) already exists.' % nsd_id)
+ nsd_id = nsd[METADATA].get(NS_UUID, "undefined")
+ if nsd_id == "undefined":
+ raise CatalogException("Service UUID(%s) does not exist in metadata." % nsd_id)
+ if NSPackageModel.objects.filter(nsdId=nsd_id):
raise CatalogException("NSD(%s) already exists." % nsd_id)
for vnf in nsd["vnfs"]:
vnfd_id = vnf["properties"]["id"]
pkg = VnfPackageModel.objects.filter(vnfdId=vnfd_id)
if not pkg:
- logger.error("VNFD is not distributed.")
+ vnfd_name = vnf.get("vnf_id", "undefined")
+ logger.error("[%s] is not distributed.", vnfd_name)
raise CatalogException("VNF package(%s) is not distributed." % vnfd_id)
ns_pkgs.update(
- nsdId=nsd_id,
- nsdName=nsd["metadata"].get("name", nsd_id),
- nsdDesginer=nsd["metadata"].get("vendor", "undefined"),
- nsdDescription=nsd["metadata"].get("description", ""),
- nsdVersion=nsd["metadata"].get("version", "undefined"),
+ nsdId=nsd[METADATA].get(NS_UUID, "undefined"),
+ nsdName=nsd[METADATA].get(NS_NAME, "undefined"),
+ nsdDesginer=nsd[METADATA].get(NS_DESIGNER, "undefined"),
+ nsdDescription=nsd[METADATA].get(NS_DESCRIPTION, ""),
+ nsdVersion=nsd[METADATA].get(NS_VERSION, "undefined"),
+ invariantId=nsd[METADATA].get(NS_INVARIANTUUID, "undefined"),
onboardingState=PKG_STATUS.ONBOARDED,
operationalState=PKG_STATUS.ENABLED,
usageState=PKG_STATUS.NOT_IN_USE,
@@ -158,7 +165,7 @@ class NsDescriptor(object):
'nsdName': ns_pkg.nsdName,
'nsdVersion': ns_pkg.nsdVersion,
'nsdDesigner': ns_pkg.nsdDesginer,
- 'nsdInvariantId': None, # TODO
+ 'nsdInvariantId': ns_pkg.invariantId,
'vnfPkgIds': [],
'pnfdInfoIds': [], # TODO
'nestedNsdInfoIds': [], # TODO
diff --git a/catalog/packages/biz/nspackage.py b/catalog/packages/biz/sdc_ns_package.py
index cf1f2cd5..b079f3e3 100644
--- a/catalog/packages/biz/nspackage.py
+++ b/catalog/packages/biz/sdc_ns_package.py
@@ -12,7 +12,6 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-import json
import logging
import os
import sys
@@ -20,16 +19,18 @@ import traceback
from catalog.pub.config.config import CATALOG_ROOT_PATH, CATALOG_URL_PATH, MSB_SERVICE_IP
from catalog.pub.config.config import REG_TO_MSB_REG_PARAM
-from catalog.pub.database.models import NSPackageModel, VnfPackageModel
+from catalog.pub.database.models import NSPackageModel
from catalog.pub.exceptions import CatalogException
from catalog.pub.msapi import sdc
-from catalog.pub.utils import fileutil
from catalog.pub.utils import toscaparser
+from catalog.packages.biz.ns_descriptor import NsDescriptor
logger = logging.getLogger(__name__)
STATUS_SUCCESS, STATUS_FAILED = "success", "failed"
+METADATA = "metadata"
+
def fmt_ns_pkg_rsp(status, desc, error_code="500"):
return [0, {"status": status, "statusDescription": desc, "errorCode": error_code}]
@@ -40,11 +41,11 @@ def ns_on_distribute(csar_id):
try:
ret = NsPackage().on_distribute(csar_id)
except CatalogException as e:
- NsPackage().delete_catalog(csar_id)
+ NsPackage().delete_csar(csar_id)
return fmt_ns_pkg_rsp(STATUS_FAILED, e.message)
except:
logger.error(traceback.format_exc())
- NsPackage().delete_catalog(csar_id)
+ NsPackage().delete_csar(csar_id)
return fmt_ns_pkg_rsp(STATUS_FAILED, str(sys.exc_info()))
if ret[0]:
return fmt_ns_pkg_rsp(STATUS_FAILED, ret[1])
@@ -95,7 +96,7 @@ def parse_nsd(csar_id, inputs):
if not ns_pkg:
raise CatalogException("NS CSAR(%s) does not exist." % csar_id)
csar_path = ns_pkg[0].localFilePath
- ret = {"model": toscaparser.parse_nsd(csar_path, inputs)}
+ ret = {"model": toscaparser.parse_nsd(csar_path, inputs, False)}
except CatalogException as e:
return [1, e.message]
except Exception as e:
@@ -122,39 +123,17 @@ class NsPackage(object):
csar_name = "%s.csar" % artifact.get("name", csar_id)
local_file_name = sdc.download_artifacts(artifact["toscaModelURL"], local_path, csar_name)
- nsd_json = toscaparser.parse_nsd(local_file_name)
- nsd = json.JSONDecoder().decode(nsd_json)
-
- nsd_id = nsd["metadata"]["id"]
- if NSPackageModel.objects.filter(nsdId=nsd_id):
- raise CatalogException("NSD(%s) already exists." % nsd_id)
-
- for vnf in nsd["vnfs"]:
- vnfd_id = vnf["properties"]["id"]
- pkg = VnfPackageModel.objects.filter(vnfdId=vnfd_id)
- if not pkg:
- vnfd_name = vnf.get("vnf_id", "undefined")
- logger.error("[%s] is not distributed.", vnfd_name)
- raise CatalogException("VNF package(%s) is not distributed." % vnfd_id)
-
- NSPackageModel(
- nsPackageId=csar_id,
- nsdId=nsd_id,
- nsdName=nsd["metadata"].get("name", nsd_id),
- nsdDesginer=nsd["metadata"].get("vendor", "undefined"),
- nsdDescription=nsd["metadata"].get("description", ""),
- nsdVersion=nsd["metadata"].get("version", "undefined"),
- nsPackageUri=csar_name,
- sdcCsarId=csar_id,
- localFilePath=local_file_name,
- nsdModel=nsd_json
- ).save()
-
+ data = {
+ 'userDefinedData': ""
+ }
+ nsd = NsDescriptor()
+ nsd.create(data, csar_id)
+ nsd.parse_nsd_and_save(csar_id, local_file_name, False)
return [0, "CSAR(%s) distributed successfully." % csar_id]
def delete_csar(self, csar_id):
- NSPackageModel.objects.filter(nsPackageId=csar_id).delete()
- self.delete_catalog(csar_id)
+ nsd = NsDescriptor()
+ nsd.delete_single(csar_id)
return [0, "Delete CSAR(%s) successfully." % csar_id]
def get_csars(self):
@@ -175,6 +154,7 @@ class NsPackage(object):
package_info["nsdVersion"] = csars[0].nsdVersion
package_info["csarName"] = csars[0].nsPackageUri
package_info["nsdModel"] = csars[0].nsdModel
+ package_info["nsdInvariantId"] = csars[0].invariantId
package_info["downloadUrl"] = "http://%s:%s/%s/%s/%s" % (
MSB_SERVICE_IP,
REG_TO_MSB_REG_PARAM["nodes"][0]["port"],
@@ -185,7 +165,3 @@ class NsPackage(object):
raise CatalogException("Ns package[%s] not Found." % csar_id)
return [0, {"csarId": csar_id, "packageInfo": package_info}]
-
- def delete_catalog(self, csar_id):
- local_path = os.path.join(CATALOG_ROOT_PATH, csar_id)
- fileutil.delete_dirs(local_path)
diff --git a/catalog/packages/biz/vnfpackage.py b/catalog/packages/biz/sdc_vnf_package.py
index 55de8096..55de8096 100644
--- a/catalog/packages/biz/vnfpackage.py
+++ b/catalog/packages/biz/sdc_vnf_package.py
diff --git a/catalog/packages/tests/test_nspackage.py b/catalog/packages/tests/test_nspackage.py
index 9af82312..80b4acb4 100644
--- a/catalog/packages/tests/test_nspackage.py
+++ b/catalog/packages/tests/test_nspackage.py
@@ -385,7 +385,9 @@ class TestNsPackage(TestCase):
"nsPackageId": "13",
"downloadUrl": "http://127.0.0.1:8806/static/catalog/13/13.csar",
"nsdModel": "",
- "nsdVersion": "2"}},
+ "nsdVersion": "2",
+ "nsdInvariantId": None
+ }},
{"csarId": "14",
"packageInfo": {"csarName": "14.csar",
"nsdProvider": "3",
@@ -393,7 +395,8 @@ class TestNsPackage(TestCase):
"nsPackageId": "14",
"downloadUrl": "http://127.0.0.1:8806/static/catalog/14/14.csar",
"nsdModel": "",
- "nsdVersion": "3"}}]
+ "nsdVersion": "3",
+ "nsdInvariantId": None}}]
self.assertEqual(expect_data, resp.data)
def test_ns_pkg_get_one(self):
@@ -415,7 +418,8 @@ 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",
+ "nsdInvariantId": None}}
self.assertEqual(expect_data, resp.data)
def test_ns_pkg_get_one_not_found(self):
diff --git a/catalog/packages/tests/test_vnfpackage.py b/catalog/packages/tests/test_vnfpackage.py
index a3cbe94a..0086129d 100644
--- a/catalog/packages/tests/test_vnfpackage.py
+++ b/catalog/packages/tests/test_vnfpackage.py
@@ -17,7 +17,7 @@ import mock
from rest_framework.test import APIClient
from django.test import TestCase
from rest_framework import status
-from catalog.packages.biz.vnfpackage import NfDistributeThread, NfPkgDeleteThread
+from catalog.packages.biz.sdc_vnf_package import NfDistributeThread, NfPkgDeleteThread
from catalog.pub.database.models import JobStatusModel, JobModel
from catalog.pub.database.models import VnfPackageModel
from catalog.pub.msapi import sdc
diff --git a/catalog/packages/views/catalog_views.py b/catalog/packages/views/catalog_views.py
index 157af9fd..fd7f5d43 100644
--- a/catalog/packages/views/catalog_views.py
+++ b/catalog/packages/views/catalog_views.py
@@ -20,7 +20,7 @@ from drf_yasg.utils import no_body, swagger_auto_schema
from rest_framework import status
from rest_framework.decorators import api_view
from rest_framework.response import Response
-from catalog.packages.biz import vnfpackage, nspackage
+from catalog.packages.biz import sdc_vnf_package, sdc_ns_package
from catalog.packages.serializers.catalog_serializers import InternalErrorRequestSerializer
from catalog.packages.serializers.catalog_serializers import NfPackageDistributeRequestSerializer
from catalog.packages.serializers.catalog_serializers import NfPackageSerializer
@@ -59,7 +59,7 @@ def nspackages_rc(request, *args, **kwargs):
if request.method == 'GET':
# Gets ns package list
- ret = nspackage.ns_get_csars()
+ ret = sdc_ns_package.ns_get_csars()
normal_status = status.HTTP_200_OK
if ret[0] == 0:
@@ -77,7 +77,7 @@ def nspackages_rc(request, *args, **kwargs):
csar_id = ignore_case_get(request.data, "csarId")
logger.debug("csar_id is %s", csar_id)
- ret = nspackage.ns_on_distribute(csar_id)
+ ret = sdc_ns_package.ns_on_distribute(csar_id)
normal_status = status.HTTP_202_ACCEPTED
logger.debug("Leave %s, Return value is %s", fun_name(), ret)
@@ -113,7 +113,7 @@ def nfpackages_rc(request, *args, **kwargs):
request.method)
ret, normal_status, response_serializer, validation_error = None, None, None, None
if request.method == 'GET':
- ret = vnfpackage.nf_get_csars()
+ ret = sdc_vnf_package.nf_get_csars()
normal_status = status.HTTP_200_OK
response_serializer = NfPackagesSerializer(data=ret[1])
elif request.method == 'POST':
@@ -128,7 +128,7 @@ def nfpackages_rc(request, *args, **kwargs):
vim_ids = ignore_case_get(request_serivalizer.data, "vimIds")
lab_vim_id = ignore_case_get(request_serivalizer.data, "labVimId")
job_id = str(uuid.uuid4())
- vnfpackage.NfDistributeThread(
+ sdc_vnf_package.NfDistributeThread(
csar_id, vim_ids, lab_vim_id, job_id).start()
ret = [0, {"jobId": job_id}]
normal_status = status.HTTP_202_ACCEPTED
@@ -189,7 +189,7 @@ def ns_rd_csar(request, *args, **kwargs):
fun_name(), request.method, csar_id)
ret, normal_status, response_serializer, validation_error = None, None, None, None
if request.method == 'GET':
- ret = nspackage.ns_get_csar(csar_id)
+ ret = sdc_ns_package.ns_get_csar(csar_id)
normal_status = status.HTTP_200_OK
if ret[0] == 0:
response_serializer = NsPackageSerializer(data=ret[1])
@@ -197,7 +197,7 @@ def ns_rd_csar(request, *args, **kwargs):
if validation_error:
return validation_error
elif request.method == 'DELETE':
- ret = nspackage.ns_delete_csar(csar_id)
+ ret = sdc_ns_package.ns_delete_csar(csar_id)
normal_status = status.HTTP_200_OK
logger.info("Leave %s, Return value is %s", fun_name(), ret)
if ret[0] != 0:
@@ -248,13 +248,13 @@ def nf_rd_csar(request, *args, **kwargs):
ret, normal_status, response_serializer, validation_error = None, None, None, None
if request.method == 'GET':
- ret = vnfpackage.nf_get_csar(csar_id)
+ ret = sdc_vnf_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())
- vnfpackage.NfPkgDeleteThread(csar_id, job_id).start()
+ sdc_vnf_package.NfPkgDeleteThread(csar_id, job_id).start()
ret = [0, {"jobId": job_id}]
normal_status = status.HTTP_202_ACCEPTED
response_serializer = PostJobResponseSerializer(data=ret[1])
@@ -290,7 +290,7 @@ def ns_model_parser(request, *args, **kwargs):
fun_name(),
csar_id,
inputs)
- ret = nspackage.parse_nsd(csar_id, inputs)
+ ret = sdc_ns_package.parse_nsd(csar_id, inputs)
logger.info("Leave %s, Return value is %s", fun_name(), ret)
if ret[0] != 0:
return Response(
@@ -323,7 +323,7 @@ def vnf_model_parser(request, *args, **kwargs):
fun_name(),
csar_id,
inputs)
- ret = vnfpackage.parse_vnfd(csar_id, inputs)
+ ret = sdc_vnf_package.parse_vnfd(csar_id, inputs)
logger.info("Leave %s, Return value is %s", fun_name(), ret)
if ret[0] != 0:
return Response(
diff --git a/catalog/pub/database/models.py b/catalog/pub/database/models.py
index 7d215cc7..d150386d 100644
--- a/catalog/pub/database/models.py
+++ b/catalog/pub/database/models.py
@@ -25,6 +25,7 @@ class NSPackageModel(models.Model):
usageState = models.CharField(db_column='USAGESTATE', max_length=20, blank=True, null=True) # usageState
deletionPending = models.CharField(db_column='DELETIONPENDING', max_length=20, blank=True, null=True) # deletionPending
nsdId = models.CharField(db_column='NSDID', max_length=50, blank=True, null=True)
+ invariantId = models.CharField(db_column='INVARIANTID', max_length=50, blank=True, null=True) # nsdInvariantId
nsdName = models.CharField(db_column='NSDNAME', max_length=50, blank=True, null=True)
nsdDesginer = models.CharField(db_column='NSDDESIGNER', max_length=50, null=True, blank=True)
nsdDescription = models.CharField(db_column='NSDDESCRIPTION', max_length=100, null=True, blank=True)
diff --git a/catalog/pub/utils/toscaparser/__init__.py b/catalog/pub/utils/toscaparser/__init__.py
index b172d678..12df6e89 100644
--- a/catalog/pub/utils/toscaparser/__init__.py
+++ b/catalog/pub/utils/toscaparser/__init__.py
@@ -17,24 +17,37 @@ import json
from catalog.pub.utils.toscaparser.nsdmodel import EtsiNsdInfoModel
from catalog.pub.utils.toscaparser.vnfdmodel import EtsiVnfdInfoModel
from catalog.pub.utils.toscaparser.pnfmodel import PnfdInfoModel
+from catalog.pub.utils.toscaparser.servicemodel import SdcServiceModel
-def parse_nsd(path, input_parameters=[]):
- tosca_obj = EtsiNsdInfoModel(path, input_parameters)
+def parse_nsd(path, input_parameters=[], isETSI=True):
+ if isETSI:
+ tosca_obj = EtsiNsdInfoModel(path, input_parameters)
+ else:
+ tosca_obj = SdcServiceModel(path, input_parameters)
+
strResponse = json.dumps(tosca_obj, default=lambda obj: obj.__dict__)
strResponse = strResponse.replace(': null', ': ""')
return strResponse
-def parse_vnfd(path, input_parameters=[]):
- tosca_obj = EtsiVnfdInfoModel(path, input_parameters)
+def parse_vnfd(path, input_parameters=[], isETSI=True):
+ if isETSI:
+ tosca_obj = EtsiVnfdInfoModel(path, input_parameters)
+ else:
+ # SDC VF Model TBD
+ tosca_obj = {}
strResponse = json.dumps(tosca_obj, default=lambda obj: obj.__dict__)
strResponse = strResponse.replace(': null', ': ""')
return strResponse
-def parse_pnfd(path, input_parameters=[]):
- tosca_obj = PnfdInfoModel(path, input_parameters)
+def parse_pnfd(path, input_parameters=[], isETSI=True):
+ if isETSI:
+ tosca_obj = PnfdInfoModel(path, input_parameters)
+ else:
+ # SDC PNF Model TBD
+ tosca_obj = {}
strResponse = json.dumps(tosca_obj, default=lambda obj: obj.__dict__)
strResponse = strResponse.replace(': null', ': ""')
return strResponse
diff --git a/catalog/pub/utils/toscaparser/basemodel.py b/catalog/pub/utils/toscaparser/basemodel.py
index 54e1fd97..f45f7469 100644
--- a/catalog/pub/utils/toscaparser/basemodel.py
+++ b/catalog/pub/utils/toscaparser/basemodel.py
@@ -12,7 +12,6 @@
# See the License for the specific language governing permissions and
# limitations under the License.
-import copy
import ftplib
import json
import logging
@@ -30,6 +29,24 @@ from catalog.pub.utils.toscaparser.dataentityext import DataEntityExt
logger = logging.getLogger(__name__)
+METADATA = "metadata"
+PROPERTIES = "properties"
+DESCRIPTION = "description"
+REQUIREMENTS = "requirements"
+INTERFACES = "interfaces"
+TOPOLOGY_TEMPLATE = "topology_template"
+INPUTS = "inputs"
+CAPABILITIES = "capabilities"
+ATTRIBUTES = "attributes"
+ARTIFACTS = "artifacts"
+DERIVED_FROM = "derived_from"
+
+NODE_NAME = "name"
+NODE_TYPE = "nodeType"
+NODE_ROOT = "tosca.nodes.Root"
+GROUP_TYPE = "groupType"
+GROUPS_ROOT = "tosca.groups.Root"
+
class BaseInfoModel(object):
@@ -40,16 +57,8 @@ class BaseInfoModel(object):
def parseModel(self, tosca):
pass
- def buildInputs(self, top_inputs):
- ret = {}
- for tmpinput in top_inputs:
- tmp = {}
- tmp['type'] = tmpinput.type
- tmp['description'] = tmpinput.description
- tmp['default'] = tmpinput.default
-
- ret[tmpinput.name] = tmp
- return ret
+ def buildInputs(self, tosca):
+ return tosca.tpl.get(TOPOLOGY_TEMPLATE, '').get(INPUTS, {})
def buildToscaTemplate(self, path, params):
file_name = None
@@ -177,34 +186,31 @@ class BaseInfoModel(object):
if f is not None:
f.close()
- def buidMetadata(self, tosca):
- if 'metadata' in tosca.tpl:
- self.metadata = copy.deepcopy(tosca.tpl['metadata'])
- if tosca.tpl['metadata'].get('UUID', ''):
- self.metadata['id'] = tosca.tpl['metadata']['UUID']
+ def buildMetadata(self, tosca):
+ return tosca.tpl.get(METADATA, {}) if tosca else {}
def buildNode(self, nodeTemplate, tosca):
inputs = tosca.inputs
parsed_params = tosca.parsed_params
ret = {}
- ret['name'] = nodeTemplate.name
- ret['nodeType'] = nodeTemplate.type
- if 'description' in nodeTemplate.entity_tpl:
- ret['description'] = nodeTemplate.entity_tpl['description']
+ ret[NODE_NAME] = nodeTemplate.name
+ ret[NODE_TYPE] = nodeTemplate.type
+ if DESCRIPTION in nodeTemplate.entity_tpl:
+ ret[DESCRIPTION] = nodeTemplate.entity_tpl[DESCRIPTION]
else:
- ret['description'] = ''
- if 'metadata' in nodeTemplate.entity_tpl:
- ret['metadata'] = nodeTemplate.entity_tpl['metadata']
+ ret[DESCRIPTION] = ''
+ if METADATA in nodeTemplate.entity_tpl:
+ ret[METADATA] = nodeTemplate.entity_tpl[METADATA]
else:
- ret['metadata'] = ''
+ ret[METADATA] = ''
props = self.buildProperties_ex(nodeTemplate, tosca.topology_template)
- ret['properties'] = self.verify_properties(props, inputs, parsed_params)
- ret['requirements'] = self.build_requirements(nodeTemplate)
+ ret[PROPERTIES] = self.verify_properties(props, inputs, parsed_params)
+ ret[REQUIREMENTS] = self.build_requirements(nodeTemplate)
self.buildCapabilities(nodeTemplate, inputs, ret)
self.buildArtifacts(nodeTemplate, inputs, ret)
interfaces = self.build_interfaces(nodeTemplate)
if interfaces:
- ret['interfaces'] = interfaces
+ ret[INTERFACES] = interfaces
return ret
def buildProperties(self, nodeTemplate, parsed_params):
@@ -219,8 +225,8 @@ class BaseInfoModel(object):
tmp = {}
tmp[item.value.name] = item.value.input_name
properties[k] = tmp
- if 'attributes' in nodeTemplate.entity_tpl:
- for k, item in nodeTemplate.entity_tpl['attributes'].items():
+ if ATTRIBUTES in nodeTemplate.entity_tpl:
+ for k, item in nodeTemplate.entity_tpl[ATTRIBUTES].items():
properties[k] = str(item)
return properties
@@ -319,13 +325,13 @@ class BaseInfoModel(object):
return rets
def buildCapabilities(self, nodeTemplate, inputs, ret):
- capabilities = json.dumps(nodeTemplate.entity_tpl.get('capabilities', None))
+ capabilities = json.dumps(nodeTemplate.entity_tpl.get(CAPABILITIES, None))
match = re.findall(r'\{"get_input":\s*"([\w|\-]+)"\}', capabilities)
for m in match:
aa = [input_def for input_def in inputs if m == input_def.name][0]
capabilities = re.sub(r'\{"get_input":\s*"([\w|\-]+)"\}', json.dumps(aa.default), capabilities, 1)
if capabilities != 'null':
- ret['capabilities'] = json.loads(capabilities)
+ ret[CAPABILITIES] = json.loads(capabilities)
def buildArtifacts(self, nodeTemplate, inputs, ret):
artifacts = json.dumps(nodeTemplate.entity_tpl.get('artifacts', None))
@@ -334,19 +340,19 @@ class BaseInfoModel(object):
aa = [input_def for input_def in inputs if m == input_def.name][0]
artifacts = re.sub(r'\{"get_input":\s*"([\w|\-]+)"\}', json.dumps(aa.default), artifacts, 1)
if artifacts != 'null':
- ret['artifacts'] = json.loads(artifacts)
+ ret[ARTIFACTS] = json.loads(artifacts)
def build_interfaces(self, node_template):
- if 'interfaces' in node_template.entity_tpl:
- return node_template.entity_tpl['interfaces']
+ if INTERFACES in node_template.entity_tpl:
+ return node_template.entity_tpl[INTERFACES]
return None
def isNodeTypeX(self, node, nodeTypes, x):
- node_type = node['nodeType']
+ node_type = node[NODE_TYPE]
while node_type != x:
node_type_derived = node_type
- node_type = nodeTypes[node_type]['derived_from']
- if node_type == "tosca.nodes.Root" or node_type == node_type_derived:
+ node_type = nodeTypes[node_type][DERIVED_FROM]
+ if node_type == NODE_ROOT or node_type == node_type_derived:
return False
return True
@@ -355,7 +361,7 @@ class BaseInfoModel(object):
def getRequirementByNodeName(self, nodeTemplates, storage_name, prop):
for node in nodeTemplates:
- if node['name'] == storage_name:
+ if node[NODE_NAME] == storage_name:
if prop in node:
return node[prop]
@@ -371,8 +377,8 @@ class BaseInfoModel(object):
def getRequirementByName(self, node, requirementName):
requirements = []
- if 'requirements' in node:
- for item in node['requirements']:
+ if REQUIREMENTS in node:
+ for item in node[REQUIREMENTS]:
for key, value in item.items():
if key == requirementName:
requirements.append(value)
@@ -410,13 +416,13 @@ class BaseInfoModel(object):
def get_node_by_name(self, node_templates, name):
for node in node_templates:
- if node['name'] == name:
+ if node[NODE_NAME] == name:
return node
return None
def getCapabilityByName(self, node, capabilityName):
- if 'capabilities' in node and capabilityName in node['capabilities']:
- return node['capabilities'][capabilityName]
+ if CAPABILITIES in node and capabilityName in node[CAPABILITIES]:
+ return node[CAPABILITIES][capabilityName]
return None
def get_base_path(self, tosca):
@@ -425,22 +431,14 @@ class BaseInfoModel(object):
def build_artifacts(self, node):
rets = []
- if 'artifacts' in node and len(node['artifacts']) > 0:
- artifacts = node['artifacts']
+ if ARTIFACTS in node and len(node[ARTIFACTS]) > 0:
+ artifacts = node[ARTIFACTS]
for name, value in artifacts.items():
ret = {}
+ ret['artifact_name'] = name
+ ret['file'] = value
if isinstance(value, dict):
- ret['artifact_name'] = name
- ret['type'] = value.get('type', '')
- ret['file'] = value.get('file', '')
- ret['repository'] = value.get('repository', '')
- ret['deploy_path'] = value.get('deploy_path', '')
- else:
- ret['artifact_name'] = name
- ret['type'] = ''
- ret['file'] = value
- ret['repository'] = ''
- ret['deploy_path'] = ''
+ ret.update(value)
rets.append(ret)
return rets
@@ -449,10 +447,17 @@ class BaseInfoModel(object):
return self.get_node_by_name(node_templates, req_node_name)
def isGroupTypeX(self, group, groupTypes, x):
- group_type = group['groupType']
+ group_type = group[GROUP_TYPE]
while group_type != x:
group_type_derived = group_type
- group_type = groupTypes[group_type]['derived_from']
- if group_type == "tosca.groups.Root" or group_type == group_type_derived:
+ group_type = groupTypes[group_type][DERIVED_FROM]
+ if group_type == GROUPS_ROOT or group_type == group_type_derived:
return False
return True
+
+ def setTargetValues(dict_target, target_keys, dict_source, source_keys):
+ i = 0
+ for item in source_keys:
+ dict_target[target_keys[i]] = dict_source.get(item, "")
+ i += 1
+ return dict_target
diff --git a/catalog/pub/utils/toscaparser/const.py b/catalog/pub/utils/toscaparser/const.py
new file mode 100644
index 00000000..1631c128
--- /dev/null
+++ b/catalog/pub/utils/toscaparser/const.py
@@ -0,0 +1,27 @@
+# Copyright 2018 ZTE Corporation.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+NS_METADATA_SECTIONS = (NS_UUID, NS_INVARIANTUUID, NS_NAME, NS_VERSION, NS_DESIGNER, NS_DESCRIPTION) =\
+ ("id", "invariant_id", "name", "version", "designer", "description")
+
+PNF_METADATA_SECTIONS = (PNF_UUID, PNF_INVARIANTUUID, PNF_NAME, PNF_METADATA_DESCRIPTION, PNF_VERSION, PNF_PROVIDER) = \
+ ("descriptor_id", "descriptor_invariant_id", "name", "description", "version", "provider")
+PNF_SECTIONS = (PNF_ID, PNF_METADATA, PNF_PROPERTIES, PNF_DESCRIPTION) = \
+ ("pnf_id", "metadata", "properties", "description")
+
+VNF_SECTIONS = (VNF_ID, VNF_METADATA, VNF_PROPERTIES, VNF_DESCRIPTION) = \
+ ("vnf_id", "metadata", "properties", "description")
+
+VL_SECTIONS = (VL_ID, VL_METADATA, VL_PROPERTIES, VL_DESCRIPTION) = \
+ ("vl_id", "metadata", "properties", "description")
diff --git a/catalog/pub/utils/toscaparser/nsdmodel.py b/catalog/pub/utils/toscaparser/nsdmodel.py
index ae99e9bb..9d72642f 100644
--- a/catalog/pub/utils/toscaparser/nsdmodel.py
+++ b/catalog/pub/utils/toscaparser/nsdmodel.py
@@ -32,9 +32,8 @@ class EtsiNsdInfoModel(BaseInfoModel):
super(EtsiNsdInfoModel, self).__init__(path, params)
def parseModel(self, tosca):
- self.buidMetadata(tosca)
- if hasattr(tosca, 'topology_template') and hasattr(tosca.topology_template, 'inputs'):
- self.inputs = self.buildInputs(tosca.topology_template.inputs)
+ self.metadata = self.buildMetadata(tosca)
+ self.inputs = self.buildInputs(tosca)
nodeTemplates = map(functools.partial(self.buildNode, tosca=tosca), tosca.nodetemplates)
types = tosca.topology_template.custom_defs
self.basepath = self.get_base_path(tosca)
diff --git a/catalog/pub/utils/toscaparser/pnfmodel.py b/catalog/pub/utils/toscaparser/pnfmodel.py
index 7dc99d80..1acf6d4c 100644
--- a/catalog/pub/utils/toscaparser/pnfmodel.py
+++ b/catalog/pub/utils/toscaparser/pnfmodel.py
@@ -24,10 +24,8 @@ class PnfdInfoModel(BaseInfoModel):
super(PnfdInfoModel, self).__init__(path, params)
def parseModel(self, tosca):
- self.buidMetadata(tosca)
- if hasattr(tosca, 'topology_template') and hasattr(tosca.topology_template, 'inputs'):
- self.inputs = self.buildInputs(tosca.topology_template.inputs)
-
+ self.metadata = self.buildMetadata(tosca)
+ self.inputs = self.buildInputs(tosca)
nodeTemplates = map(functools.partial(self.buildNode, tosca=tosca),
tosca.nodetemplates)
self.basepath = self.get_base_path(tosca)
diff --git a/catalog/pub/utils/toscaparser/servicemodel.py b/catalog/pub/utils/toscaparser/servicemodel.py
new file mode 100644
index 00000000..249710d9
--- /dev/null
+++ b/catalog/pub/utils/toscaparser/servicemodel.py
@@ -0,0 +1,129 @@
+# 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 functools
+import logging
+from catalog.pub.utils.toscaparser.const import NS_METADATA_SECTIONS, PNF_METADATA_SECTIONS, VNF_SECTIONS, PNF_SECTIONS, VL_SECTIONS
+from catalog.pub.utils.toscaparser.basemodel import BaseInfoModel
+logger = logging.getLogger(__name__)
+
+SDC_SERVICE_SECTIONS = (SERVICE_TYPE, SRV_DESCRIPTION) = (
+ 'org.openecomp.resource.abstract.nodes.service', 'description')
+
+SDC_SERVICE_METADATA_SECTIONS = (SRV_UUID, SRV_INVARIANTUUID, SRV_NAME) = (
+ 'UUID', 'invariantUUID', 'name')
+
+SDC_VL = (VL_TYPE) = ('nfv.ext.zte.VL')
+SDC_VL_SECTIONS = (VL_ID, VL_METADATA, VL_PROPERTIES, VL_DESCRIPTION) = \
+ ("name", "metadata", "properties", "description")
+
+SDC_VF = (VF_TYPE, VF_UUID) = \
+ ('org.openecomp.resource.abstract.nodes.VF', 'UUID')
+SDC_VF_SECTIONS = (VF_ID, VF_METADATA, VF_PROPERTIES, VF_DESCRIPTION) = \
+ ("name", "metadata", "properties", "description")
+
+SDC_PNF = (PNF_TYPE) = \
+ ('org.openecomp.resource.abstract.nodes.PNF')
+SDC_PNF_METADATA_SECTIONS = (SDC_PNF_UUID, SDC_PNF_INVARIANTUUID, SDC_PNF_NAME, SDC_PNF_METADATA_DESCRIPTION, SDC_PNF_VERSION) = \
+ ("UUID", "invariantUUID", "name", "description", "version")
+SDC_PNF_SECTIONS = (SDC_PNF_ID, SDC_PNF_METADATA, SDC_PNF_PROPERTIES, SDC_PNF_DESCRIPTION) = \
+ ("name", "metadata", "properties", "description")
+
+
+class SdcServiceModel(BaseInfoModel):
+
+ def __init__(self, path, params):
+ super(SdcServiceModel, self).__init__(path, params)
+
+ def parseModel(self, tosca):
+ self.metadata = self._buildServiceMetadata(tosca)
+ self.inputs = self.buildInputs(tosca)
+ nodeTemplates = map(functools.partial(self.buildNode, tosca=tosca), tosca.nodetemplates)
+ types = tosca.topology_template.custom_defs
+ self.basepath = self.get_base_path(tosca)
+ self.vnfs = self._get_all_vnf(nodeTemplates, types)
+ self.pnfs = self._get_all_pnf(nodeTemplates, types)
+ self.vls = self._get_all_vl(nodeTemplates, types)
+
+ def _buildServiceMetadata(self, tosca):
+ """ SDC service Meta Format
+ invariantUUID: e2618ee1 - a29a - 44c4 - a52a - b718fe1269f4
+ UUID: 2362d14a - 115f - 4a2b - b449 - e2f93c0b7c89
+ name: demoVLB
+ description: catalogservicedescription
+ type: Service
+ category: NetworkL1 - 3
+ serviceType: ''
+ serviceRole: ''
+ serviceEcompNaming: true
+ ecompGeneratedNaming: true
+ namingPolicy: ''
+ """
+ metadata_temp = self.buildMetadata(tosca)
+ self.setTargetValues(self.metadata, NS_METADATA_SECTIONS, metadata_temp, SDC_SERVICE_METADATA_SECTIONS)
+
+ def _get_all_vnf(self, nodeTemplates, node_types):
+ """ SDC Resource Metadata
+ invariantUUID: 9ed46ddc-8eb7-4cb0-a1b6-04136c921af4
+ UUID: b56ba35d-45fb-41e3-b6b8-b4f66917baa1
+ customizationUUID: af0a6e64-967b-476b-87bc-959dcf59c305
+ version: '1.0'
+ name: b7d2fceb-dd11-43cd-a3fa
+ description: vendor software product
+ type: VF
+ category: Generic
+ subcategory: Abstract
+ resourceVendor: b9d9f9f7-7994-4f0d-8104
+ resourceVendorRelease: '1.0'
+ resourceVendorModelNumber: ''
+ """
+ vnfs = []
+ for node in nodeTemplates:
+ if self.isNodeTypeX(node, node_types, VF_TYPE):
+ vnf = {}
+ self.setTargetValues(vnf, VNF_SECTIONS, node, SDC_VF_SECTIONS)
+ if node['metadata']:
+ vnf['properties']['id'] = node['metadata'].get('UUID', 'undefined')
+ vnf['dependencies'] = self._get_networks(node, node_types)
+ vnf['networks'] = self._get_networks(node, node_types)
+ vnfs.append(vnf)
+ return vnfs
+
+ def _get_all_pnf(self, nodeTemplates, node_types):
+ pnfs = []
+ for node in nodeTemplates:
+ if self.isNodeTypeX(node, node_types, PNF_TYPE):
+ pnf = {}
+ self.setTargetValues(pnf, PNF_SECTIONS, node, SDC_PNF_SECTIONS)
+ self.setTargetValues(pnf['properties'], PNF_METADATA_SECTIONS, node['metadata'], SDC_PNF_METADATA_SECTIONS)
+ pnf['networks'] = self._get_networks(node, node_types)
+ pnfs.append(pnf)
+ return pnfs
+
+ def _get_all_vl(self, nodeTemplates, node_types):
+ vls = []
+ for node in nodeTemplates:
+ if self.isNodeTypeX(node, node_types, VL_TYPE):
+ vl = {}
+ self.setTargetValues(vl, VL_SECTIONS, node, SDC_VL_SECTIONS)
+ vls.append(vl)
+ return vls
+
+ def _get_networks(self, node, node_types):
+ rets = []
+ if 'requirements' in node and self.isNodeTypeX(node, node_types, VF_TYPE):
+ for item in node['requirements']:
+ for key, value in item.items():
+ rets.append({"key_name": key, "vl_id": self.get_requirement_node_name(value)})
+ return rets
diff --git a/catalog/pub/utils/toscaparser/tests.py b/catalog/pub/utils/toscaparser/tests.py
index 36ceb2a3..39be7f64 100644
--- a/catalog/pub/utils/toscaparser/tests.py
+++ b/catalog/pub/utils/toscaparser/tests.py
@@ -14,6 +14,8 @@
import json
import os
import logging
+import tempfile
+import shutil
from django.test import TestCase
@@ -30,6 +32,7 @@ class TestToscaparser(TestCase):
pass
def test_nsd_parse(self):
+ self.remove_temp_dir()
ran_csar = os.path.dirname(os.path.abspath(__file__)) + "/testdata/ns/ran.csar"
nsd_json = parse_nsd(ran_csar)
metadata = json.loads(nsd_json).get("metadata")
@@ -46,6 +49,7 @@ class TestToscaparser(TestCase):
self.assertNotEqual("RAN-NS", metadata.get("template_name", ""))
def test_vnf_parse(self):
+ self.remove_temp_dir()
csar_path = os.path.dirname(os.path.abspath(__file__)) + "/testdata/vnf"
input_parameters = [{"value": "222222", "key": "sdncontroller"}]
vcpe = ["infra", "vbng", "vbrgemu", "vgmux", "vgw"]
@@ -58,7 +62,16 @@ class TestToscaparser(TestCase):
self.assertEqual(("vCPE_%s" % vcpe_part), metadata.get("template_name", ""))
def test_pnfd_parse(self):
+ self.remove_temp_dir()
csar_path = os.path.dirname(os.path.abspath(__file__)) + "/testdata/pnf/ran-du.csar"
pnfd_json = parse_pnfd(csar_path)
metadata = json.loads(pnfd_json).get("metadata")
self.assertEqual("RAN_DU", metadata.get("template_name", ""))
+
+ def remove_temp_dir(self):
+ tempdir = tempfile.gettempdir()
+ for dir in os.listdir(tempdir):
+ if dir.startswith("tmp"):
+ path = tempfile.tempdir + "/" + dir
+ if (not os.path.isfile(path)) and os.path.exists(path):
+ shutil.rmtree(tempfile.tempdir + "/" + dir)
diff --git a/catalog/pub/utils/toscaparser/vnfdmodel.py b/catalog/pub/utils/toscaparser/vnfdmodel.py
index 135963b2..de29d605 100644
--- a/catalog/pub/utils/toscaparser/vnfdmodel.py
+++ b/catalog/pub/utils/toscaparser/vnfdmodel.py
@@ -28,10 +28,8 @@ class EtsiVnfdInfoModel(BaseInfoModel):
super(EtsiVnfdInfoModel, self).__init__(path, params)
def parseModel(self, tosca):
- self.buidMetadata(tosca)
- if hasattr(tosca, 'topology_template') and hasattr(tosca.topology_template, 'inputs'):
- self.inputs = self.buildInputs(tosca.topology_template.inputs)
-
+ self.metadata = self.buildMetadata(tosca)
+ self.inputs = self.buildInputs(tosca)
nodeTemplates = map(functools.partial(self.buildNode, tosca=tosca),
tosca.nodetemplates)
node_types = tosca.topology_template.custom_defs