From: fengyuanxing Date: Fri, 25 Aug 2017 09:10:48 +0000 (+0800) Subject: Add toscaparser util files X-Git-Tag: v1.0.0~91 X-Git-Url: https://gerrit.onap.org/r/gitweb?a=commitdiff_plain;h=refs%2Fchanges%2F75%2F8775%2F1;p=vfc%2Fnfvo%2Fcatalog.git Add toscaparser util files Issue_Id: VFC-152 Change-Id: I3e3b4475a7a1dd89bed2e379e019b7e73e5b3845 Signed-off-by: fengyuanxing --- diff --git a/catalog/pub/utils/idutil.py b/catalog/pub/utils/idutil.py new file mode 100644 index 00000000..85bebb83 --- /dev/null +++ b/catalog/pub/utils/idutil.py @@ -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 index 00000000..c5e8cdf6 --- /dev/null +++ b/catalog/pub/utils/jobutil.py @@ -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 index 00000000..9ac71d3e --- /dev/null +++ b/catalog/pub/utils/toscaparser/__init__.py @@ -0,0 +1,31 @@ +# Copyright 2017 ZTE Corporation. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +import 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 index 00000000..6e2685ce --- /dev/null +++ b/catalog/pub/utils/toscaparser/basemodel.py @@ -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 index 00000000..46de453c --- /dev/null +++ b/catalog/pub/utils/toscaparser/convert.py @@ -0,0 +1,20 @@ +# Copyright 2017 ZTE Corporation. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + + +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 index 00000000..f78faa34 --- /dev/null +++ b/catalog/pub/utils/toscaparser/dataentityext.py @@ -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 index 00000000..fe5d0060 --- /dev/null +++ b/catalog/pub/utils/toscaparser/nsdmodel.py @@ -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 index 00000000..7ce31b94 --- /dev/null +++ b/catalog/pub/utils/toscaparser/parser.py @@ -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 index 00000000..3964f1f8 --- /dev/null +++ b/catalog/pub/utils/toscaparser/vnfdmodel.py @@ -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)