Add toscaparser util files 75/8775/1
authorfengyuanxing <feng.yuanxing@zte.com.cn>
Fri, 25 Aug 2017 09:10:48 +0000 (17:10 +0800)
committerfengyuanxing <feng.yuanxing@zte.com.cn>
Fri, 25 Aug 2017 09:10:48 +0000 (17:10 +0800)
Issue_Id: VFC-152

Change-Id: I3e3b4475a7a1dd89bed2e379e019b7e73e5b3845
Signed-off-by: fengyuanxing <feng.yuanxing@zte.com.cn>
catalog/pub/utils/idutil.py [new file with mode: 0644]
catalog/pub/utils/jobutil.py [new file with mode: 0644]
catalog/pub/utils/toscaparser/__init__.py [new file with mode: 0644]
catalog/pub/utils/toscaparser/basemodel.py [new file with mode: 0644]
catalog/pub/utils/toscaparser/convert.py [new file with mode: 0644]
catalog/pub/utils/toscaparser/dataentityext.py [new file with mode: 0644]
catalog/pub/utils/toscaparser/nsdmodel.py [new file with mode: 0644]
catalog/pub/utils/toscaparser/parser.py [new file with mode: 0644]
catalog/pub/utils/toscaparser/vnfdmodel.py [new file with mode: 0644]

diff --git a/catalog/pub/utils/idutil.py b/catalog/pub/utils/idutil.py
new file mode 100644 (file)
index 0000000..85bebb8
--- /dev/null
@@ -0,0 +1,20 @@
+# Copyright 2016 ZTE Corporation.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+from redisco import containers as cont
+
+
+def get_auto_id(id_type, id_group="auto_id_hash"):
+    auto_id_hash = cont.Hash(id_group)
+    auto_id_hash.hincrby(id_type, 1)
+    return auto_id_hash.hget(id_type)
diff --git a/catalog/pub/utils/jobutil.py b/catalog/pub/utils/jobutil.py
new file mode 100644 (file)
index 0000000..c5e8cdf
--- /dev/null
@@ -0,0 +1,143 @@
+# Copyright 2016-2017 ZTE Corporation.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+import datetime
+import logging
+import uuid
+import traceback
+
+from catalog.pub.database.models import JobStatusModel, JobModel
+from catalog.pub.utils import idutil
+
+logger = logging.getLogger(__name__)
+
+
+def enum(**enums):
+    return type('Enum', (), enums)
+
+
+JOB_STATUS = enum(PROCESSING=0, FINISH=1)
+JOB_MODEL_STATUS = enum(STARTED='started', PROCESSING='processing', FINISHED='finished', ERROR='error',
+                        TIMEOUT='timeout')
+JOB_TYPE = enum(CREATE_VNF="create vnf", TERMINATE_VNF="terminate vnf", GRANT_VNF="grant vnf", MANUAL_SCALE_VNF="manual scale vnf",
+                HEAL_VNF="heal vnf")
+
+
+class JobUtil(object):
+    def __init__(self):
+        pass
+
+    @staticmethod
+    def __gen_job_id(job_name):
+        return "%s-%s" % (job_name if job_name else "UnknownJob", uuid.uuid1())
+
+    @staticmethod
+    def query_job_status(job_id, index_id=-1):
+        #logger.info("Query job status, jobid =[%s], responseid [%d]" % (job_id, index_id))
+        jobs = []
+        if index_id < 0:
+            row = JobStatusModel.objects.filter(jobid=job_id).order_by("-indexid").first()
+            if row:
+                jobs.append(row)
+        else:
+            [jobs.append(job) for job in JobStatusModel.objects.filter(jobid=job_id).order_by("-indexid")
+             if job.indexid > index_id]
+
+        #logger.info("Query job status, rows=%s" % str(jobs))
+        return jobs
+
+    @staticmethod
+    def is_job_exists(job_id):
+        jobs = JobModel.objects.filter(jobid=job_id)
+        return len(jobs) > 0
+
+    @staticmethod
+    def create_job(inst_type, jobaction, inst_id, user='', job_id=None, res_name=''):
+        if job_id is None:
+            job_id = JobUtil.__gen_job_id(
+                '%s-%s-%s' % (str(inst_type).replace(' ', '_'), str(jobaction).replace(' ', '_'), str(inst_id)))
+        job = JobModel()
+        job.jobid = job_id
+        job.jobtype = inst_type
+        job.jobaction = jobaction
+        job.resid = str(inst_id)
+        job.status = JOB_STATUS.PROCESSING
+        job.user = user
+        job.starttime = datetime.datetime.now().strftime('%Y-%m-%d %X')
+        job.progress = 0
+        job.resname = res_name
+        logger.debug("create a new job, jobid=%s, jobtype=%s, jobaction=%s, resid=%s, status=%d" %
+                     (job.jobid, job.jobtype, job.jobaction, job.resid, job.status))
+        job.save()
+        return job_id
+
+    @staticmethod
+    def clear_job(job_id):
+        [job.delete() for job in JobModel.objects.filter(jobid=job_id)]
+        logger.debug("Clear job, job_id=%s" % job_id)
+
+    @staticmethod
+    def add_job_status(job_id, progress, status_decs, error_code=""):
+        jobs = JobModel.objects.filter(jobid=job_id)
+        if not jobs:
+            logger.error("Job[%s] is not exists, please create job first." % job_id)
+            raise Exception("Job[%s] is not exists." % job_id)
+        try:
+            int_progress = int(progress)
+            job_status = JobStatusModel()
+            job_status.indexid = int(idutil.get_auto_id(job_id))
+            job_status.jobid = job_id
+            job_status.status = "processing"
+            job_status.progress = int_progress
+
+            if job_status.progress == 0:
+                job_status.status = "started"
+            elif job_status.progress == 100:
+                job_status.status = "finished"
+            elif job_status.progress == 101:
+                job_status.status = "partly_finished"
+            elif job_status.progress > 101:
+                job_status.status = "error"
+
+            if error_code == "255":
+                job_status.status = "error"
+
+            job_status.descp = status_decs
+            job_status.errcode = error_code
+            job_status.addtime = datetime.datetime.now().strftime('%Y-%m-%d %X')
+            job_status.save()
+            logger.debug("Add a new job status, jobid=%s, indexid=%d,"
+                         " status=%s, description=%s, progress=%d, errcode=%s, addtime=%r" %
+                         (job_status.jobid, job_status.indexid, job_status.status, job_status.descp,
+                          job_status.progress, job_status.errcode, job_status.addtime))
+
+            job = jobs[0]
+            job.progress = int_progress
+            if job_status.progress >= 100:
+                job.status = JOB_STATUS.FINISH
+                job.endtime = datetime.datetime.now().strftime('%Y-%m-%d %X')
+            job.save()
+            logger.debug("update job, jobid=%s, progress=%d" % (job_status.jobid, int_progress))
+        except:
+            logger.error(traceback.format_exc())
+
+    @staticmethod
+    def clear_job_status(job_id):
+        [job.delete() for job in JobStatusModel.objects.filter(jobid=job_id)]
+        logger.debug("Clear job status, job_id=%s" % job_id)
+
+    @staticmethod
+    def get_unfinished_jobs(url_prefix, inst_id, inst_type):
+        jobs = JobModel.objects.filter(resid=inst_id, jobtype=inst_type, status=JOB_STATUS.PROCESSING)
+        progresses = reduce(lambda content, job: content + [url_prefix + "/" + job.jobid], jobs, [])
+        return progresses
diff --git a/catalog/pub/utils/toscaparser/__init__.py b/catalog/pub/utils/toscaparser/__init__.py
new file mode 100644 (file)
index 0000000..9ac71d3
--- /dev/null
@@ -0,0 +1,31 @@
+# Copyright 2017 ZTE Corporation.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+import json
+
+from catalog.pub.utils.toscaparser.nsdmodel import EtsiNsdInfoModel
+from catalog.pub.utils.toscaparser.vnfdmodel import EtsiVnfdInfoModel
+
+
+def parse_nsd(path, input_parameters=[]):
+    tosca_obj = EtsiNsdInfoModel(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)
+    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
new file mode 100644 (file)
index 0000000..6e2685c
--- /dev/null
@@ -0,0 +1,281 @@
+# Copyright 2017 ZTE Corporation.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import copy
+import json
+import os
+import re
+import shutil
+import urllib
+
+from toscaparser.functions import GetInput
+from toscaparser.tosca_template import ToscaTemplate
+
+from catalog.pub.utils.toscaparser.dataentityext import DataEntityExt
+
+
+class BaseInfoModel(object):
+
+    def buildToscaTemplate(self, path, params):
+        file_name = None
+        try:
+            file_name = self._check_download_file(path)
+            valid_params = self._validate_input_params(file_name, params)
+            return self._create_tosca_template(file_name, valid_params)
+        finally:
+            if file_name != None and file_name != path and os.path.exists(file_name):
+                try:
+                    os.remove(file_name)
+                except Exception, e:
+                    pass
+
+    def _validate_input_params(self, path, params):
+        valid_params = {}
+        if params and len(params) > 0:
+            tmp = self._create_tosca_template(path, None)
+            for key,value in params.items():
+                if hasattr(tmp, 'inputs') and len(tmp.inputs) > 0:
+                    for input_def in tmp.inputs:
+                        if (input_def.name == key):
+                            valid_params[key] = DataEntityExt.validate_datatype(input_def.type, value)
+
+        return valid_params
+
+    def _create_tosca_template(self, file_name, valid_params):
+        tosca_tpl = None
+        try:
+            tosca_tpl = ToscaTemplate(file_name, valid_params)
+            print "-----------------------------"
+            print '\n'.join(['%s:%s' % item for item in tosca_tpl.__dict__.items()])
+            print "-----------------------------"
+            return tosca_tpl
+        finally:
+            if tosca_tpl != None and hasattr(tosca_tpl, "temp_dir") and os.path.exists(tosca_tpl.temp_dir):
+                try:
+                    shutil.rmtree(tosca_tpl.temp_dir)
+                except Exception, e:
+                    pass
+
+    def _check_download_file(self, path):
+        if (path.startswith("ftp") or path.startswith("sftp")):
+            return self.downloadFileFromFtpServer(path)
+        elif (path.startswith("http")):
+            return self.download_file_from_httpserver(path)
+        return path
+
+    def download_file_from_httpserver(self, path):
+        path = path.encode("utf-8")
+        tmps = str.split(path, '/')
+        localFileName = tmps[len(tmps) - 1]
+        urllib.urlretrieve(path, localFileName)
+        return localFileName
+
+    def downloadFileFromFtpServer(self, path):
+        path = path.encode("utf-8")
+        tmp = str.split(path, '://')
+        protocol = tmp[0]
+        tmp = str.split(tmp[1], ':')
+        if len(tmp) == 2:
+            userName = tmp[0]
+            tmp = str.split(tmp[1], '@')
+            userPwd = tmp[0]
+            index = tmp[1].index('/')
+            hostIp = tmp[1][0:index]
+            remoteFileName = tmp[1][index:len(tmp[1])]
+            if protocol.lower() == 'ftp':
+                hostPort = 21
+            else:
+                hostPort = 22
+
+        if len(tmp) == 3:
+            userName = tmp[0]
+            userPwd = str.split(tmp[1], '@')[0]
+            hostIp = str.split(tmp[1], '@')[1]
+            index = tmp[2].index('/')
+            hostPort = tmp[2][0:index]
+            remoteFileName = tmp[2][index:len(tmp[2])]
+
+        localFileName = str.split(remoteFileName, '/')
+        localFileName = localFileName[len(localFileName) - 1]
+
+        if protocol.lower() == 'sftp':
+            self.sftp_get(userName, userPwd, hostIp, hostPort, remoteFileName, localFileName)
+        else:
+            self.ftp_get(userName, userPwd, hostIp, hostPort, remoteFileName, localFileName)
+        return localFileName
+
+    def buidMetadata(self, tosca):
+        if 'metadata' in tosca.tpl:
+            self.metadata = copy.deepcopy(tosca.tpl['metadata'])
+
+    def buildProperties(self, nodeTemplate, parsed_params):
+        properties = {}
+        isMappingParams = parsed_params and len(parsed_params) > 0
+        for k, item in nodeTemplate.get_properties().items():
+            properties[k] = item.value
+            if isinstance(item.value, GetInput):
+                if item.value.result() and isMappingParams:
+                    properties[k] = DataEntityExt.validate_datatype(item.type, item.value.result())
+                else:
+                    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():
+                properties[k] = str(item)
+        return properties
+
+
+    def verify_properties(self, props, inputs, parsed_params):
+        ret_props = {}
+        if (props and len(props) > 0):
+            for key, value in props.items():
+                ret_props[key] = self._verify_value(value, inputs, parsed_params)
+                #                 if isinstance(value, str):
+                #                     ret_props[key] = self._verify_string(inputs, parsed_params, value);
+                #                     continue
+                #                 if isinstance(value, list):
+                #                     ret_props[key] = map(lambda x: self._verify_dict(inputs, parsed_params, x), value)
+                #                     continue
+                #                 if isinstance(value, dict):
+                #                     ret_props[key] = self._verify_map(inputs, parsed_params, value)
+                #                     continue
+                #                 ret_props[key] = value
+        return ret_props
+
+    def build_requirements(self, node_template):
+        rets = []
+        for req in node_template.requirements:
+            for req_name, req_value in req.items():
+                if (isinstance(req_value, dict)):
+                    if ('node' in req_value and req_value['node'] not in node_template.templates):
+                        continue  # No target requirement for aria parser, not add to result.
+                rets.append({req_name : req_value})
+        return rets
+
+    def buildCapabilities(self, nodeTemplate, inputs, ret):
+        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)
+
+    def buildArtifacts(self, nodeTemplate, inputs, ret):
+        artifacts = json.dumps(nodeTemplate.entity_tpl.get('artifacts', None))
+        match = re.findall(r'\{"get_input":\s*"([\w|\-]+)"\}',artifacts)
+        for m in match:
+            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)
+
+    def build_interfaces(self, node_template):
+        if 'interfaces' in node_template.entity_tpl:
+            return node_template.entity_tpl['interfaces']
+        return None
+
+    def isVnf(self, node):
+        return node['nodeType'].upper().find('.VNF.') >= 0 or node['nodeType'].upper().endswith('.VNF')
+
+    def isPnf(self, node):
+        return node['nodeType'].upper().find('.PNF.') >= 0 or node['nodeType'].upper().endswith('.PNF')
+
+    def isCp(self, node):
+        return node['nodeType'].upper().find('.CP.') >= 0 or node['nodeType'].upper().endswith('.CP')
+
+    def isVl(self, node):
+        return node['nodeType'].upper().find('.VIRTUALLINK.') >= 0 or node['nodeType'].upper().find('.VL.') >= 0 or \
+               node['nodeType'].upper().endswith('.VIRTUALLINK') or node['nodeType'].upper().endswith('.VL')
+
+    def get_requirement_node_name(self, req_value):
+        return self.get_prop_from_obj(req_value, 'node')
+
+    def get_prop_from_obj(self, obj, prop):
+        if isinstance(obj, str):
+            return obj
+        if (isinstance(obj, dict) and prop in obj):
+            return obj[prop]
+        return None
+
+    def getNodeDependencys(self, node):
+        return self.getRequirementByName(node, 'dependency')
+
+    def getVirtualLinks(self, node):
+        return self.getRequirementByName(node, 'virtualLink')
+
+    def getVirtualbindings(self, node):
+        return self.getRequirementByName(node, 'virtualbinding')
+
+
+    def getRequirementByName(self, node, requirementName):
+        requirements = []
+        if 'requirements' in node:
+            for item in node['requirements']:
+                for key, value in item.items():
+                    if key == requirementName:
+                        requirements.append(value)
+        return requirements
+
+    def get_networks(self, node):
+        rets = []
+        if 'requirements' in node:
+            for item in node['requirements']:
+                for key, value in item.items():
+                    if key.upper().find('VIRTUALLINK') >=0:
+                        rets.append({"key_name":key, "vl_id":self.get_requirement_node_name(value)})
+        return rets
+
+    def _verify_value(self, value, inputs, parsed_params):
+        if isinstance(value, str):
+            return self._verify_string(inputs, parsed_params, value)
+        if isinstance(value, list) or isinstance(value, dict):
+            return self._verify_object(value, inputs, parsed_params)
+        return value
+
+    def _verify_object(self, value, inputs, parsed_params):
+        s = self._verify_string(inputs, parsed_params, json.dumps(value))
+        return json.loads(s)
+
+    def _get_input_name(self, getInput):
+        input_name = getInput.split(':')[1]
+        input_name = input_name.strip()
+        return input_name.replace('"', '').replace('}', '')
+
+    def _verify_string(self, inputs, parsed_params, value):
+        getInputs = re.findall(r'{"get_input": "[a-zA-Z_0-9]+"}', value)
+        for getInput in getInputs:
+            input_name = self._get_input_name(getInput)
+            if parsed_params and input_name in parsed_params:
+                value = value.replace(getInput, json.dumps(parsed_params[input_name]))
+            else:
+                for input_def in inputs:
+                    if input_def.default and input_name == input_def.name:
+                        value = value.replace(getInput, json.dumps(input_def.default))
+        return value
+
+    def get_node_vl_id(self, node):
+        vl_ids = map(lambda x: self.get_requirement_node_name(x), self.getVirtualLinks(node))
+        if len(vl_ids) > 0:
+            return vl_ids[0]
+        return ""
+
+    def get_node_by_name(self, node_templates, name):
+        for node in node_templates:
+            if node['name'] == name:
+                return node
+        return None
\ No newline at end of file
diff --git a/catalog/pub/utils/toscaparser/convert.py b/catalog/pub/utils/toscaparser/convert.py
new file mode 100644 (file)
index 0000000..46de453
--- /dev/null
@@ -0,0 +1,20 @@
+# Copyright 2017 ZTE Corporation.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+
+def convert_nsd(nsd_object):
+    pass
+
+def convert_vnfd(vnfd_object):
+    pass
\ No newline at end of file
diff --git a/catalog/pub/utils/toscaparser/dataentityext.py b/catalog/pub/utils/toscaparser/dataentityext.py
new file mode 100644 (file)
index 0000000..f78faa3
--- /dev/null
@@ -0,0 +1,36 @@
+# Copyright 2017 ZTE Corporation.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+
+from toscaparser.dataentity import DataEntity
+from toscaparser.elements.constraints import Schema
+from toscaparser.common.exception import ExceptionCollector
+
+class DataEntityExt(object):
+    '''A complex data value entity ext.'''
+    
+    @staticmethod
+    def validate_datatype(type, value, entry_schema=None, custom_def=None):
+        if value:
+            if (type == Schema.STRING):
+                return str(value)
+            elif type == Schema.FLOAT:
+                try:
+                    return float(value)
+                except Exception:
+                    ExceptionCollector.appendException(ValueError(('"%s" is not an float.') % value))
+    
+            return DataEntity.validate_datatype(type, value, entry_schema, custom_def)
+        return value
+
diff --git a/catalog/pub/utils/toscaparser/nsdmodel.py b/catalog/pub/utils/toscaparser/nsdmodel.py
new file mode 100644 (file)
index 0000000..fe5d006
--- /dev/null
@@ -0,0 +1,289 @@
+# Copyright 2017 ZTE Corporation.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+import functools
+
+from catalog.pub.utils.toscaparser.basemodel import BaseInfoModel
+
+
+class EtsiNsdInfoModel(BaseInfoModel):
+
+    def __init__(self, path, params):
+        tosca = self.buildToscaTemplate(path, params)
+        self.parseModel(tosca)
+
+    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)
+
+        nodeTemplates = map(functools.partial(self.buildNode, inputs=tosca.inputs, parsed_params=tosca.parsed_params),
+                            tosca.nodetemplates)
+
+        self.vnfs = self._get_all_vnf(nodeTemplates)
+        self.pnfs = self._get_all_pnf(nodeTemplates)
+        self.vls = self.get_all_vl(nodeTemplates)
+        self.cps = self.get_all_cp(nodeTemplates)
+        self.routers = self.get_all_router(nodeTemplates)
+        self.fps = self._get_all_fp(nodeTemplates)
+        self.vnffgs = self._get_all_vnffg(tosca.topology_template.groups)
+        self.server_groups = self.get_all_server_group(tosca.topology_template.groups)
+
+
+    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 buildNode(self, nodeTemplate, inputs, parsed_params):
+        ret ={}
+        ret['name'] = nodeTemplate.name
+        ret['nodeType'] = nodeTemplate.type
+        if 'description' in nodeTemplate.entity_tpl:
+            ret['description'] = nodeTemplate.entity_tpl['description']
+        else:
+            ret['description'] = ''
+        props = self.buildProperties(nodeTemplate, parsed_params)
+        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
+        return ret
+
+    def _get_all_vnf(self, nodeTemplates):
+        vnfs = []
+        for node in nodeTemplates:
+            if self.isVnf(node):
+                vnf = {}
+                vnf['vnf_id'] = node['name']
+                vnf['description'] = node['description']
+                vnf['properties'] = node['properties']
+                vnf['dependencies'] = map(lambda x: self.get_requirement_node_name(x), self.getNodeDependencys(node))
+                vnf['networks'] = self.get_networks(node)
+
+                vnfs.append(vnf)
+        return vnfs
+
+    def _get_all_pnf(self, nodeTemplates):
+        pnfs = []
+        for node in nodeTemplates:
+            if self.isPnf(node):
+                pnf = {}
+                pnf['pnf_id'] = node['name']
+                pnf['description'] = node['description']
+                pnf['properties'] = node['properties']
+                pnf['cps'] = self.getVirtalBindingCpIds(node, nodeTemplates)
+
+                pnfs.append(pnf)
+        return pnfs
+
+    def getVirtalBindingCpIds(self, node, nodeTemplates):
+        return map(lambda x: x['name'], self.getVirtalBindingCps(node, nodeTemplates))
+
+    def getVirtalBindingCps(self, node, nodeTemplates):
+        cps = []
+        for tmpnode in nodeTemplates:
+            if 'requirements' in tmpnode:
+                for item in tmpnode['requirements']:
+                    for key, value in item.items():
+                        if key.upper().startswith('VIRTUALBINDING'):
+                            req_node_name = self.get_requirement_node_name(value)
+                            if req_node_name != None and req_node_name == node['name']:
+                                cps.append(tmpnode)
+        return cps
+
+    def get_all_vl(self, nodeTemplates):
+        vls = []
+        for node in nodeTemplates:
+            if self.isVl(node):
+                vl = {}
+                vl['vl_id'] = node['name']
+                vl['description'] = node['description']
+                vl['properties'] = node['properties']
+                vl['route_external'] = False
+                vl['route_id'] = self._get_vl_route_id(node)
+                vls.append(vl)
+            if self._isExternalVL(node):
+                vl = {}
+                vl['vl_id'] = node['name']
+                vl['description'] = node['description']
+                vl['properties'] = node['properties']
+                vl['route_external'] = True
+                vls.append(vl)
+        return vls
+
+    def _get_vl_route_id(self, node):
+        route_ids = map(lambda x: self.get_requirement_node_name(x),
+                        self.getRequirementByName(node, 'virtual_route'))
+        if len(route_ids) > 0:
+            return route_ids[0]
+        return ""
+
+    def _isExternalVL(self, node):
+        return node['nodeType'].upper().find('.ROUTEEXTERNALVL') >= 0
+
+    def get_all_cp(self, nodeTemplates):
+        cps = []
+        for node in nodeTemplates:
+            if self.isCp(node):
+                cp = {}
+                cp['cp_id'] = node['name']
+                cp['cpd_id'] = node['name']
+                cp['description'] = node['description']
+                cp['properties'] = node['properties']
+                cp['vl_id'] = self.get_node_vl_id(node)
+                binding_node_ids = map(lambda x: self.get_requirement_node_name(x), self.getVirtualbindings(node))
+                #                 cp['vnf_id'] = self._filter_vnf_id(binding_node_ids, nodeTemplates)
+                cp['pnf_id'] = self._filter_pnf_id(binding_node_ids, nodeTemplates)
+                vls = self.buil_cp_vls(node)
+                if len(vls) > 1:
+                    cp['vls'] = vls
+                cps.append(cp)
+        return cps
+
+    def buil_cp_vls(self, node):
+        return map(lambda x: self._build_cp_vl(x), self.getVirtualLinks(node))
+
+    def _build_cp_vl(self, req):
+        cp_vl = {}
+        cp_vl['vl_id'] = self.get_prop_from_obj(req, 'node')
+        relationship = self.get_prop_from_obj(req, 'relationship')
+        if relationship != None:
+            properties = self.get_prop_from_obj(relationship, 'properties')
+            if properties != None and isinstance(properties, dict):
+                for key, value in properties.items():
+                    cp_vl[key] = value
+        return cp_vl
+
+    def _filter_pnf_id(self, node_ids, node_templates):
+        for node_id in node_ids:
+            node = self.get_node_by_name(node_templates, node_id)
+            if self.isPnf(node):
+                return node_id
+        return ""
+
+    def get_all_router(self, nodeTemplates):
+        rets = []
+        for node in nodeTemplates:
+            if self._isRouter(node):
+                ret = {}
+                ret['router_id'] = node['name']
+                ret['description'] = node['description']
+                ret['properties'] = node['properties']
+                ret['external_vl_id'] = self._get_router_external_vl_id(node)
+                ret['external_ip_addresses'] = self._get_external_ip_addresses(node)
+
+                rets.append(ret)
+        return rets
+
+    def _isRouter(self, node):
+        return node['nodeType'].upper().find('.ROUTER.') >= 0 or node['nodeType'].upper().endswith('.ROUTER')
+
+    def _get_router_external_vl(self, node):
+        return self.getRequirementByName(node, 'external_virtual_link')
+
+    def _get_router_external_vl_id(self, node):
+        ids = map(lambda x: self.get_requirement_node_name(x), self._get_router_external_vl(node))
+        if len(ids) > 0:
+            return ids[0]
+        return ""
+
+    def _get_external_ip_addresses(self, node):
+        external_vls = self._get_router_external_vl(node)
+        if len(external_vls) > 0:
+            if 'relationship' in external_vls[0] and 'properties' in external_vls[0]['relationship'] and 'router_ip_address' in external_vls[0]['relationship']['properties']:
+                return external_vls[0]['relationship']['properties']['router_ip_address']
+        return []
+
+    def _get_all_fp(self, nodeTemplates):
+        fps = []
+        for node in nodeTemplates:
+            if self._isFp(node):
+                fp = {}
+                fp['fp_id'] = node['name']
+                fp['description'] = node['description']
+                fp['properties'] = node['properties']
+                fp['forwarder_list'] = self._getForwarderList(node, nodeTemplates)
+
+                fps.append(fp)
+        return fps
+
+    def _isFp(self, node):
+        return node['nodeType'].upper().find('.FP.') >= 0 or node['nodeType'].upper().find('.SFP.') >= 0 or node[
+            'nodeType'].upper().endswith('.FP') or node['nodeType'].upper().endswith('.SFP')
+
+    def _getForwarderList(self, node, node_templates):
+        forwarderList = []
+        if 'requirements' in node:
+            for item in node['requirements']:
+                for key, value in item.items():
+                    if key == 'forwarder':
+                        tmpnode = self.get_node_by_req(node_templates, value)
+                        type = 'cp' if self.isCp(tmpnode) else 'vnf'
+                        req_node_name = self.get_requirement_node_name(value)
+                        if isinstance(value, dict) and 'capability' in value:
+                            forwarderList.append(
+                                {"type": type, "node_name": req_node_name, "capability": value['capability']})
+                        else:
+                            forwarderList.append({"type": type, "node_name": req_node_name, "capability": ""})
+
+        return forwarderList
+
+    def get_node_by_req(self, node_templates, req):
+        req_node_name = self.get_requirement_node_name(req)
+        return self.get_node_by_name(node_templates, req_node_name)
+
+    def _get_all_vnffg(self, groups):
+        vnffgs = []
+        for group in groups:
+            if self._isVnffg(group):
+                vnffg = {}
+                vnffg['vnffg_id'] = group.name
+                vnffg['description'] = group.description
+                if 'properties' in group.tpl:
+                    vnffg['properties'] = group.tpl['properties']
+                vnffg['members'] = group.members
+
+                vnffgs.append(vnffg)
+        return vnffgs
+
+    def _isVnffg(self, group):
+        return group.type.upper().find('.VNFFG.') >= 0 or group.type.upper().find(
+            '.SFC.') >= 0 or group.type.upper().endswith('.VNFFG') or group.type.upper().endswith('.SFC')
+
+    def get_all_server_group(self, groups):
+        rets = []
+        for group in groups:
+            if self._isServerGroup(group):
+                ret = {}
+                ret['group_id'] = group.name
+                ret['description'] = group.description
+                if 'properties' in group.tpl:
+                    ret['properties'] = group.tpl['properties']
+                ret['members'] = group.members
+
+                rets.append(ret)
+        return rets
+
+    def _isServerGroup(self, group):
+        return group.type.upper().find('.AFFINITYORANTIAFFINITYGROUP.') >= 0 or group.type.upper().endswith(
+            '.AFFINITYORANTIAFFINITYGROUP')
diff --git a/catalog/pub/utils/toscaparser/parser.py b/catalog/pub/utils/toscaparser/parser.py
new file mode 100644 (file)
index 0000000..7ce31b9
--- /dev/null
@@ -0,0 +1,51 @@
+# Copyright 2017 ZTE Corporation.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+from os import R_OK, access
+
+from catalog.pub.exceptions import NSLCMException
+from toscaparser.tosca_template import ToscaTemplate
+
+def parse_nsd_model(path, input_parameters):
+    isexist = check_file_exist(path)
+    if isexist:
+        nsd_tpl = parse_nsd_csar(path, input_parameters)
+    else:
+        raise NSLCMException('%s is not exist.' % path)
+    return nsd_tpl
+
+
+def parse_vnfd_model(path, input_parameters):
+    isexist = check_file_exist(path)
+    if isexist:
+        vnfd_tpl = parse_vnfd_csar(path, input_parameters)
+    else:
+        raise NSLCMException('%s is not exist.' % path)
+    return vnfd_tpl
+
+def check_file_exist(path):
+    if path.exists(path) and path.isfile(path) and access(path, R_OK):
+        return True
+    else:
+        return False
+
+def parse_nsd_csar(path, input_parameters=[], a_file=True):
+    nsd_object = None
+    nsd_object = ToscaTemplate(path, input_parameters)
+    return nsd_object
+
+
+def parse_vnfd_csar(path, input_parameters=[], a_file=True):
+    vnfd_object = None
+    vnfd_object = ToscaTemplate(path, input_parameters)
+    return vnfd_object
\ No newline at end of file
diff --git a/catalog/pub/utils/toscaparser/vnfdmodel.py b/catalog/pub/utils/toscaparser/vnfdmodel.py
new file mode 100644 (file)
index 0000000..3964f1f
--- /dev/null
@@ -0,0 +1,21 @@
+# Copyright 2017 ZTE Corporation.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+#         http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+
+from catalog.pub.utils.toscaparser import EtsiNsdInfoModel
+
+
+class EtsiVnfdInfoModel(EtsiNsdInfoModel):
+
+    def __init__(self, path, params):
+        super(EtsiVnfdInfoModel, self).__init__(path, params)