first commit
Change-Id: I8a65ee5527dd16d81e87c8ac5d4bdb471e5e759d
Signed-off-by: lombardof <flombardo@cnit.it>
diff --git a/lib/TopologyModels/example/example.yaml b/lib/TopologyModels/example/example.yaml
new file mode 100644
index 0000000..04633f5
--- /dev/null
+++ b/lib/TopologyModels/example/example.yaml
@@ -0,0 +1,53 @@
+name: Example #Model name
+description: example #Model description
+version: 1.0 #Model version
+designer: Pierluigi Greto #Model designer
+nodes: #List of nodes, with id and label used in the gui (We can add more fields)
+ examplenode1:
+ label: EXN1
+ examplenode2:
+ label: EXN2
+layer: #List of Layers
+ exampleLayer:
+ nodes: #List of node to be visualized in the current layer
+ examplenode1:
+ addable:
+ callback: addNode
+ removable: true
+ examplenode1:
+ addable:
+ callback: addNode
+ removable: true
+ allowed_edges: #List of allowed edges between the layer's nodes
+ examplenode1: #Edge's source
+ destination: #List of edge's destination with the list of controls callback id to call when there is a connections
+ examplenode1:
+ direct_edge: false
+ removable: true
+ examplenode2:
+ direct_edge: false
+ removable: true
+action: #Action to show on rightclick on a node/link
+ rightclick:
+ node:
+ delete:
+ title: Delete
+ callback: deleteNode
+ link:
+ delete:
+ title: Delete
+ callback: deleteLink
+
+callback: #List of callbacks used
+ addNode:
+ file: example_controller.js
+ class: ExampleController
+ removeNode:
+ file: example_controller.js
+ class: ExampleController
+ addLink:
+ file: example_controller.js
+ class: ExampleController
+ removeLink:
+ file: example_controller.js
+ class: ExampleController
diff --git a/lib/TopologyModels/osm/osm.yaml b/lib/TopologyModels/osm/osm.yaml
new file mode 100644
index 0000000..59ac883
--- /dev/null
+++ b/lib/TopologyModels/osm/osm.yaml
@@ -0,0 +1,187 @@
+name: Osm #Model name
+description: Osm #Model description
+version: 1.0 #Model version
+designer: Francesco Lombardo #Model designer
+nodes: #List of nodes, with id and label used in the gui (We can add more fields)
+ vnf:
+ label: VNF
+ ns_vl:
+ label: VL
+ ns_cp:
+ label: SAP
+ vnf_vl:
+ label: intVL
+ vnf_vdu:
+ label: VDU
+ vnf_ext_cp:
+ label: ExtCP
+ vnf_vdu_cp:
+ label: VduCP
+layer: #List of Layers
+ ns:
+ nodes: #List of node to be visualized in the current layer
+ vnf:
+ addable:
+ callback: addVnf
+ removable:
+ callback: removeNode
+ expands : vnf
+ ns_vl:
+ addable:
+ callback: addNode
+ removable:
+ callback: removeNode
+ ns_cp:
+ addable:
+ callback: addNode
+ removable:
+ callback: removeNode
+ allowed_edges: #List of allowed edges between the layer's nodes
+ vnf: #Edge's source
+ destination: #List of edge's destination with the list of controls callback id to call when there is a connections
+ ns_vl:
+ callback: linkVnftoNsVl
+ direct_edge: false
+ removable:
+ callback: removeLink
+ ns_cp:
+ callback: linkVnftoNsCp
+ direct_edge: false
+ removable:
+ callback: removeLink
+ ns_vl:
+ destination:
+ vnf:
+ callback: linkVnftoNsVl
+ direct_edge: false
+ removable:
+ callback: removeLink
+ ns_cp:
+ callback: nsCpExclusiveConnection
+ direct_edge: false
+ removable:
+ callback: removeLink
+
+ ns_cp:
+ destination:
+ vnf:
+ callback: linkVnftoNsCp
+ direct_edge: false
+ removable:
+ callback: removeLink
+ ns_vl:
+ callback: nsCpExclusiveConnection
+ direct_edge: false
+ removable:
+ callback: removeLink
+ action: #Action to show on rightclick all types of node/link
+ node:
+ addToCurrentVNFFG:
+ title: Add to current VNFFG
+ callback: addToCurrentVNFFG
+ link:
+
+ vnf:
+ nodes: #List of node to be visualized in the current layer
+ vnf_vl:
+ addable:
+ callback: addNode
+ removable:
+ callback: removeNode
+ vnf_vdu:
+ addable:
+ callback: addVnfVdu
+ removable:
+ callback: removeVnfVdu
+ vnf_ext_cp:
+ addable:
+ callback: addNode
+ removable:
+ callback: removeNode
+ vnf_vdu_cp:
+ addable:
+ callback: addVnfVduCp
+ removable:
+ callback: removeVnfVduCp
+ allowed_edges: #List of allowed edges between the layer's nodes
+ vnf_vl: #Edge's source
+ destination: #List of edge's destination with the list of controls callback id to call when there is a connections
+ vnf_vdu_cp:
+ callback: linkVltoVduCp
+ direct_edge: false
+ removable:
+ callback: removeLink
+ vnf_ext_cp:
+ callback: linkVnfVltoExpCp
+ direct_edge: false
+ removable:
+ callback: removeLink
+ vnf_ext_cp:
+ destination:
+ vnf_vl:
+ callback: linkVnfVltoExpCp
+ direct_edge: false
+ removable:
+ callback: removeLink
+ vnf_vdu_cp:
+ destination:
+ vnf_vl:
+ callback: linkVltoVduCp
+ direct_edge: false
+ removable:
+ callback: removeLink
+
+
+
+callback: #List of callbacks used
+ chooseVnfExp:
+ file: osm_controller.js
+ class: OSMController
+ nsCpExclusiveConnection:
+ file: osm_controller.js
+ class: OSMController
+ getVduConnectedToVduCp:
+ file: osm_controller.js
+ class: OSMController
+ addVnf:
+ file: osm_controller.js
+ class: OSMController
+ addNode:
+ file: osm_controller.js
+ class: OSMController
+ addVnfVdu:
+ file: osm_controller.js
+ class: OSMController
+ addVnfVduCp:
+ file: osm_controller.js
+ class: OSMController
+ addLink:
+ file: osm_controller.js
+ class: OSMController
+ linkVnftoNsCp:
+ file: osm_controller.js
+ class: OSMController
+ linkVnftoNsVl:
+ file: osm_controller.js
+ class: OSMController
+ linkVltoVduCp:
+ file: osm_controller.js
+ class: OSMController
+ linkVnfVltoExpCp:
+ file: osm_controller.js
+ class: OSMController
+ removeNode:
+ file: osm_controller.js
+ class: OSMController
+ removeVnfVdu:
+ file: osm_controller.js
+ class: OSMController
+ removeVnfVduCp:
+ file: osm_controller.js
+ class: OSMController
+ removeLink:
+ file: osm_controller.js
+ class: OSMController
+ addToCurrentVNFFG:
+ file: osm_controller.js
+ class: OSMController
diff --git a/lib/__init__.py b/lib/__init__.py
new file mode 100644
index 0000000..bfcc6bf
--- /dev/null
+++ b/lib/__init__.py
@@ -0,0 +1 @@
+__all__ = ["Util", 'etsi']
diff --git a/lib/osm/__init__.py b/lib/osm/__init__.py
new file mode 100644
index 0000000..26d8656
--- /dev/null
+++ b/lib/osm/__init__.py
@@ -0,0 +1 @@
+__all__ = ["osm_parser", "osm_rdcl_graph"]
\ No newline at end of file
diff --git a/lib/osm/osm_parser.py b/lib/osm/osm_parser.py
new file mode 100644
index 0000000..a596405
--- /dev/null
+++ b/lib/osm/osm_parser.py
@@ -0,0 +1,89 @@
+#
+# Copyright 2017 CNIT - Consorzio Nazionale Interuniversitario per le Telecomunicazioni
+#
+# 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 BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+import json
+import pyaml
+import yaml
+from lib.util import Util
+from lib.parser import Parser
+import logging
+import traceback
+import glob
+import os
+
+logging.basicConfig(level=logging.DEBUG)
+log = logging.getLogger('OsmParser')
+
+class OsmParser(Parser):
+ """Parser methods for osm project type
+
+ """
+
+ def __init__(self):
+ super(OsmParser, self).__init__()
+
+ @classmethod
+ def importprojectdir(cls,dir_project, file_type):
+ """Imports all descriptor files under a given folder
+
+ this method is specific for Osm project type
+ """
+
+ project = {
+ 'nsd':{},
+
+ 'vnfd':{},
+
+ 'positions': {}
+ }
+
+
+ for desc_type in project:
+ cur_type_path = os.path.join(dir_project, desc_type.upper())
+ log.debug(cur_type_path)
+ if os.path.isdir(cur_type_path):
+ for file in glob.glob(os.path.join(cur_type_path, '*.'+file_type)):
+ if file_type == 'json':
+ project[desc_type][os.path.basename(file).split('.')[0]] = Util.loadjsonfile(file)
+ elif file_type == 'yaml':
+ project[desc_type][os.path.basename(file).split('.')[0]] = Util.loadyamlfile(file)
+
+
+ for vertices_file in glob.glob(os.path.join(dir_project, '*.json')):
+ if os.path.basename(vertices_file) == 'vertices.json':
+ project['positions']['vertices'] = Util.loadjsonfile(vertices_file)
+
+ return project
+
+ @classmethod
+ def importprojectfiles(cls, file_dict):
+ """Imports descriptors (extracted from the new project POST)
+
+ The keys in the dictionary are the file types
+ """
+ project = {
+ 'nsd':{},
+
+ 'vnfd':{},
+
+ }
+ for desc_type in project:
+ if desc_type in file_dict:
+ files_desc_type = file_dict[desc_type]
+ for file in files_desc_type:
+ project[desc_type][os.path.splitext(file.name)[0]] = json.loads(file.read())
+
+ return project
\ No newline at end of file
diff --git a/lib/osm/osm_rdcl_graph.py b/lib/osm/osm_rdcl_graph.py
new file mode 100644
index 0000000..91b798f
--- /dev/null
+++ b/lib/osm/osm_rdcl_graph.py
@@ -0,0 +1,51 @@
+#
+# Copyright 2017 CNIT - Consorzio Nazionale Interuniversitario per le Telecomunicazioni
+#
+# 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 BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+import json
+import logging
+import copy
+from lib.rdcl_graph import RdclGraph
+
+logging.basicConfig(level=logging.DEBUG)
+log = logging.getLogger('OsmRdclGraph')
+
+class OsmRdclGraph(RdclGraph):
+ """Operates on the graph representation used for the GUI graph views"""
+
+ def __init__(self):
+ pass
+
+
+ def build_graph_from_project(self, json_project, model={}):
+ """Creates a single graph for a whole project"""
+
+ #print "json_project ",json_project
+ graph_object = {
+ 'vertices': [],
+ 'edges': [],
+ 'graph_parameters': {},
+ 'model': model
+ }
+ try:
+ positions = json_project['positions'] if 'positions' in json_project else False
+ log.debug('build graph from project json')
+
+
+ except Exception as e:
+ log.exception('Exception in build_graph_from_project')
+ raise
+
+ return graph_object
diff --git a/lib/osm/osmclient/__init__.py b/lib/osm/osmclient/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/lib/osm/osmclient/__init__.py
diff --git a/lib/osm/osmclient/client.py b/lib/osm/osmclient/client.py
new file mode 100644
index 0000000..48c9815
--- /dev/null
+++ b/lib/osm/osmclient/client.py
@@ -0,0 +1,430 @@
+import requests
+import logging
+import json
+import tarfile
+import yaml
+import pyaml
+import StringIO
+from lib.util import Util
+import hashlib
+import os
+
+logging.basicConfig(level=logging.DEBUG)
+log = logging.getLogger('helper.py')
+
+
+class Client(object):
+ def __init__(self, host=os.getenv('OSM_SERVER', "localhost"), so_port=9999, so_project='admin', ro_host=None, ro_port=9090, **kwargs):
+
+ self._user = 'admin'
+ self._password = 'admin'
+ # self._project = so_project
+ self._project = so_project
+ self._token_endpoint = 'admin/v1/tokens'
+ self._user_endpoint = 'admin/v1/users'
+
+ self._headers = {}
+ self._host = host
+
+ self._base_path = "https://{0}:{1}/osm".format(self._host, so_port)
+
+ def get_token(self):
+ postfields_dict = {'username': self._user,
+ 'password': self._password,
+ 'project-id': self._project}
+ token_url = "{0}/{1}".format(self._base_path, self._token_endpoint)
+ token = self._send_post(token_url, None, postfields_dict, headers={"Content-Type": "application/yaml", "accept": "application/json"})
+ if token is not None:
+ return token['id']
+ return None
+
+ def vim_list(self):
+ token = self.get_token()
+ if token:
+ self._headers['Authorization'] = 'Bearer {}'.format(token)
+ self._headers['accept'] = 'application/json'
+ _url = "{0}/admin/v1/vims".format(self._base_path)
+ return self._send_get(_url, headers=self._headers)
+
+ def vim_delete(self, id):
+ token = self.get_token()
+ if token:
+ self._headers['Authorization'] = 'Bearer {}'.format(token)
+ self._headers['accept'] = 'application/json'
+ _url = "{0}/admin/v1/vims/{1}".format(self._base_path, id)
+ return self._send_delete(_url, headers=self._headers)
+ return None
+
+ def vim_get(self, id):
+ token = self.get_token()
+ if token:
+ self._headers['Authorization'] = 'Bearer {}'.format(token)
+ self._headers['accept'] = 'application/json'
+ _url = "{0}/admin/v1/vims/{1}".format(self._base_path, id)
+ return self._send_get(_url, headers=self._headers)
+ return None
+
+ def vim_create(self, vim_data):
+ token = self.get_token()
+ headers = {}
+ if token:
+ headers['Authorization'] = 'Bearer {}'.format(token)
+ headers['Content-Type'] = 'application/json'
+ headers['accept'] = 'application/json'
+
+ _url = "{0}/admin/v1/vims".format(self._base_path)
+ return self._send_post(_url, headers=headers,
+ json=vim_data)
+ return None
+
+ def nsd_list(self):
+ token = self.get_token()
+ if token:
+ self._headers['Authorization'] = 'Bearer {}'.format(token)
+ self._headers['Content-Type'] = 'application/yaml'
+ self._headers['accept'] = 'application/json'
+ _url = "{0}/nsd/v1/ns_descriptors_content".format(self._base_path)
+ return self._send_get(_url, headers=self._headers)
+ return None
+
+ def nsd_get(self, id):
+ token = self.get_token()
+ if token:
+ self._headers['Authorization'] = 'Bearer {}'.format(token)
+ self._headers['Content-Type'] = 'application/yaml'
+ #self._headers['accept'] = 'application/json'
+ _url = "{0}/nsd/v1/ns_descriptors/{1}/nsd".format(self._base_path,id)
+ return yaml.load(self._send_get(_url, headers=self._headers))
+ return None
+
+ def nsd_delete(self, id):
+ token = self.get_token()
+ if token:
+ self._headers['Authorization'] = 'Bearer {}'.format(token)
+ self._headers['Content-Type'] = 'application/yaml'
+ self._headers['accept'] = 'application/json'
+ _url = "{0}/nsd/v1/ns_descriptors_content/{1}".format(self._base_path, id)
+ return self._send_delete(_url, headers=self._headers)
+ return None
+
+ def _descriptor_update(self, tarf, data):
+ print tarf.getnames()
+ # extract the package on a tmp directory
+ tarf.extractall('/tmp')
+
+ for name in tarf.getnames():
+ if name.endswith(".yaml") or name.endswith(".yml"):
+ with open('/tmp/' + name, 'w') as outfile:
+ yaml.safe_dump(data, outfile, default_flow_style=False)
+ break
+
+ tarf_temp = tarfile.open('/tmp/' + tarf.getnames()[0] + ".tar.gz", "w:gz")
+ # tarf_temp = tarfile.open("pippo.tar.gz", "w:gz")
+ print tarf_temp.getnames()
+ # tarf_temp.add('/tmp/'+tarf.getnames()[0])
+ for tarinfo in tarf:
+ # if tarinfo.name.startswith(tarf.getnames()[0]):
+ # new_name = tarinfo.name[len(tarf.getnames()[0]):]
+ tarf_temp.add('/tmp/' + tarinfo.name, tarinfo.name, recursive=False)
+ print tarf_temp.getnames()
+ tarf_temp.close()
+ return tarf
+
+ def nsd_update(self, id, data):
+ token = self.get_token()
+ headers = {}
+ if token:
+ # get the package onboarded
+ tar_pkg = self.get_nsd_pkg(id)
+ tarf = tarfile.open(fileobj=tar_pkg)
+
+ tarf = self._descriptor_update(tarf, data)
+ headers['Authorization'] = 'Bearer {}'.format(token)
+ headers['Content-Type'] = 'application/gzip'
+ headers['accept'] = 'application/json'
+ headers['Content-File-MD5'] = self.md5(open('/tmp/' + tarf.getnames()[0] + ".tar.gz", 'rb'))
+ #headers['Content-File-MD5'] = self.md5(open("pippo.tar.gz", 'rb'))
+
+ _url = "{0}/nsd/v1/ns_descriptors/{1}/nsd_content".format(self._base_path, id)
+ return self._send_put(_url, headers=headers, data=open('/tmp/'+tarf.getnames()[0] + ".tar.gz", 'rb'))
+ #return self._send_put(_url, headers=headers, data=open("pippo.tar.gz", 'rb'))
+
+ return None
+
+ def nsd_onboard(self, package):
+ token = self.get_token()
+ headers = {}
+ if token:
+
+ headers['Authorization'] = 'Bearer {}'.format(token)
+ headers['Content-Type'] = 'application/gzip'
+ headers['accept'] = 'application/json'
+ with open('/tmp/'+package.name, 'wb+') as destination:
+ for chunk in package.chunks():
+ destination.write(chunk)
+ headers['Content-File-MD5'] = self.md5(open('/tmp/'+package.name, 'rb'))
+
+ _url = "{0}/nsd/v1/ns_descriptors_content/".format(self._base_path)
+ return self._send_post(_url, headers=headers,
+ data=open('/tmp/'+package.name, 'rb'))
+ return None
+
+ def nsd_artifacts(self, id):
+ token = self.get_token()
+ if token:
+ self._headers['Authorization'] = 'Bearer {}'.format(token)
+ self._headers['Content-Type'] = 'application/yaml'
+ self._headers['accept'] = 'text/plain'
+ _url = "{0}/nsd/v1/ns_descriptors/{1}/artifacts".format(self._base_path, id)
+ return self._send_get(_url, headers=self._headers)
+ return None
+
+ def ns_list(self):
+ token = self.get_token()
+ if token:
+ self._headers['Authorization'] = 'Bearer {}'.format(token)
+ self._headers['Content-Type'] = 'application/yaml'
+ self._headers['accept'] = 'application/json'
+ _url = "{0}/nslcm/v1/ns_instances_content".format(self._base_path)
+ return self._send_get(_url, headers=self._headers)
+ return None
+
+ def ns_create(self, ns_data):
+ token = self.get_token()
+ headers = {}
+ if token:
+ headers['Authorization'] = 'Bearer {}'.format(token)
+ headers['Content-Type'] = 'application/yaml'
+ headers['accept'] = 'application/json'
+
+ _url = "{0}/nslcm/v1/ns_instances_content".format(self._base_path)
+ return self._send_post(_url, headers=headers,
+ json=ns_data)
+ return None
+
+ def ns_get(self, id):
+ token = self.get_token()
+ if token:
+ self._headers['Authorization'] = 'Bearer {}'.format(token)
+ self._headers['Content-Type'] = 'application/json'
+ self._headers['accept'] = 'application/json'
+ _url = "{0}/nslcm/v1/ns_instances_content/{1}".format(self._base_path, id)
+ return self._send_get(_url, headers=self._headers)
+ return None
+
+ def ns_delete(self, id):
+ token = self.get_token()
+ if token:
+ self._headers['Authorization'] = 'Bearer {}'.format(token)
+ #self._headers['Content-Type'] = 'application/yaml'
+ self._headers['accept'] = 'application/json'
+ _url = "{0}/nslcm/v1/ns_instances_content/{1}".format(self._base_path, id)
+ return self._send_delete(_url, headers=self._headers)
+ return None
+
+ def ns_action(self, id, action_payload):
+ token = self.get_token()
+ headers = {}
+ if token:
+ headers['Authorization'] = 'Bearer {}'.format(token)
+ headers['Content-Type'] = 'application/json'
+ headers['accept'] = 'application/json'
+
+ _url = "{0}/nslcm/v1/ns_instances/{1}/action".format(self._base_path, id)
+ return self._send_post(_url, headers=headers,
+ json=action_payload)
+ return None
+
+ def vnfd_list(self):
+ token = self.get_token()
+ if token:
+ self._headers['Authorization'] = 'Bearer {}'.format(token)
+ self._headers['Content-Type'] = 'application/yaml'
+ self._headers['accept'] = 'application/json'
+ _url = "{0}/vnfpkgm/v1/vnf_packages_content".format(self._base_path)
+ return self._send_get(_url, headers=self._headers)
+ return None
+
+ def vnfd_get(self, id):
+ token = self.get_token()
+ if token:
+ self._headers['Authorization'] = 'Bearer {}'.format(token)
+ self._headers['Content-Type'] = 'application/yaml'
+ #self._headers['accept'] = 'application/yaml'
+ _url = "{0}/vnfpkgm/v1/vnf_packages/{1}/vnfd".format(self._base_path, id)
+ return yaml.load(self._send_get(_url, headers=self._headers))
+ return None
+
+ def vnfd_delete(self, id):
+ token = self.get_token()
+ if token:
+ self._headers['Authorization'] = 'Bearer {}'.format(token)
+ self._headers['Content-Type'] = 'application/yaml'
+ self._headers['accept'] = 'application/json'
+ _url = "{0}/vnfpkgm/v1/vnf_packages_content/{1}".format(self._base_path, id)
+ return self._send_delete(_url, headers=self._headers)
+ return None
+
+ def vnfd_update(self, id, data):
+ token = self.get_token()
+ headers = {}
+ if token:
+ # get the package onboarded
+ tar_pkg = self.get_vnfd_pkg(id)
+ tarf = tarfile.open(fileobj=tar_pkg)
+
+ tarf = self._descriptor_update(tarf, data)
+ headers['Authorization'] = 'Bearer {}'.format(token)
+ headers['Content-Type'] = 'application/gzip'
+ headers['accept'] = 'application/json'
+ headers['Content-File-MD5'] = self.md5(open('/tmp/' + tarf.getnames()[0] + ".tar.gz", 'rb'))
+ # headers['Content-File-MD5'] = self.md5(open("pippo.tar.gz", 'rb'))
+
+ _url = "{0}/vnfpkgm/v1/vnf_packages/{1}/package_content".format(self._base_path, id)
+ return self._send_put(_url, headers=headers, data=open('/tmp/' + tarf.getnames()[0] + ".tar.gz", 'rb'))
+ # return self._send_put(_url, headers=headers, data=open("pippo.tar.gz", 'rb'))
+
+ return None
+
+ def vnfd_onboard(self, package):
+ token = self.get_token()
+ headers = {}
+ if token:
+ headers['Authorization'] = 'Bearer {}'.format(token)
+ headers['Content-Type'] = 'application/gzip'
+ headers['accept'] = 'application/json'
+ with open('/tmp/'+package.name, 'wb+') as destination:
+ for chunk in package.chunks():
+ destination.write(chunk)
+ headers['Content-File-MD5'] = self.md5(open('/tmp/'+package.name, 'rb'))
+ _url = "{0}/vnfpkgm/v1/vnf_packages_content".format(self._base_path)
+ return self._send_post(_url, headers=headers,
+ data=open('/tmp/' + package.name, 'rb'))
+ return None
+ def vnf_packages_artifacts(self, id):
+ token = self.get_token()
+ if token:
+ self._headers['Authorization'] = 'Bearer {}'.format(token)
+ self._headers['Content-Type'] = 'application/yaml'
+ _url = "{0}/vnfpkgm/v1/vnf_packages/{1}/artifacts".format(self._base_path, id)
+ return self._send_get(_url, headers=self._headers)
+ return None
+
+ def _upload_package(self, filename, package):
+ token = self.get_token()
+ headers = {}
+ if token:
+ headers['Authorization'] = 'Bearer {}'.format(token)
+ headers['Content-Type'] = 'application/gzip'
+ headers['Content-File-MD5'] = self.md5(package)
+ headers['accept'] = 'application/json'
+ return None
+
+ def _send_post(self, url, data=None, json=None, **kwargs):
+ try:
+ r = requests.post(url, data=data, json=json, verify=False, **kwargs)
+ #print r.text
+ except Exception as e:
+ log.exception(e)
+ #print "Exception during send POST"
+ return {'error': 'error during connection to agent'}
+ return Util.json_loads_byteified(r.text)
+
+ def _send_put(self, url, data=None, json=None, **kwargs):
+ try:
+ r = requests.put(url, data=data, json=json, verify=False, **kwargs)
+ print r.text
+ except Exception as e:
+ log.exception(e)
+ #print "Exception during send PUT"
+ return {'error': 'error during connection to agent'}
+
+ return r.json
+
+ def _send_get(self, url, params=None, **kwargs):
+ try:
+ r = requests.get(url, params=None, verify=False, stream=True, **kwargs)
+ #print r.headers
+ except Exception as e:
+ log.exception(e)
+ #print "Exception during send GET"
+ return {'error': 'error during connection to agent'}
+ if 'accept' in kwargs['headers']:
+ accept = kwargs['headers']['accept']
+ if accept == 'application/json':
+ #print "json"
+ return Util.json_loads_byteified(r.text)
+ elif accept == 'application/zip':
+ tarf =StringIO.StringIO(r.content)
+ #tarf = tarfile.open(fileobj=StringIO.StringIO(r.content))
+ # for tarinfo in tarf:
+ # #print(tarinfo.name, "is", tarinfo.size, "bytes in size and is")
+ # if tarinfo.isreg():
+ # #print("a regular file.")
+ # elif tarinfo.isdir():
+ # #print("a directory.")
+ # else:
+ # #print("something else.")
+ return tarf
+ else:
+ return r.text
+ else:
+ return r.text
+
+ def _send_delete(self, url, params=None, **kwargs):
+ try:
+ r = requests.delete(url, params=None, verify=False, **kwargs)
+ len(r.content)
+ print r.text
+ except Exception as e:
+ log.exception(e)
+ print "Exception during send DELETE"
+ return {'error': 'error during connection to agent'}
+ return r.json
+
+ def md5(self, f):
+ hash_md5 = hashlib.md5()
+ for chunk in iter(lambda: f.read(1024), b""):
+ hash_md5.update(chunk)
+ return hash_md5.hexdigest()
+
+ def get_nsd_pkg(self, id):
+ token = self.get_token()
+ if token:
+ self._headers['Authorization'] = 'Bearer {}'.format(token)
+ #self._headers['Content-Type'] = 'application/yaml'
+ self._headers['accept'] = 'application/zip'
+ _url = "{0}/nsd/v1/ns_descriptors/{1}/nsd_content".format(self._base_path, id)
+ return self._send_get(_url, headers=self._headers)
+ return None
+
+ def get_vnfd_pkg(self, id):
+ token = self.get_token()
+ if token:
+ self._headers['Authorization'] = 'Bearer {}'.format(token)
+ #self._headers['Content-Type'] = 'application/yaml'
+ self._headers['accept'] = 'application/zip'
+ _url = "{0}/vnfpkgm/v1/vnf_packages/{1}/package_content".format(self._base_path, id)
+ return self._send_get(_url, headers=self._headers)
+ return None
+
+
+
+if __name__ == '__main__':
+
+
+ client = Client()
+ package = client.get_nsd_pkg('be489dfb-5f15-48c1-b693-67d830c591e5')
+ tarf = tarfile.open(fileobj=package)
+ tarf.extractall('/tmp')
+ yaml_object = yaml.safe_dump({}, default_flow_style=False)
+ yaml_file = open('/tmp/cirros_2vnf_ns/cirros_2vnf_nsd.yaml', 'w')
+ yaml_object = pyaml.dump(yaml_object, yaml_file, safe=True)
+ tarf_temp = tarfile.open(tarf.getnames()[0]+".tar.gz", "w:gz")
+
+ for tarinfo in tarf:
+ tarf_temp.add('/tmp/'+tarinfo.name, tarinfo.name)
+ tarf_temp.close()
+
+
+
diff --git a/lib/parser.py b/lib/parser.py
new file mode 100644
index 0000000..1b764d2
--- /dev/null
+++ b/lib/parser.py
@@ -0,0 +1,46 @@
+#
+# Copyright 2017 CNIT - Consorzio Nazionale Interuniversitario per le Telecomunicazioni
+#
+# 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 BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+import json
+import pyaml
+import yaml
+from lib.util import Util
+import logging
+import traceback
+import glob
+import os
+
+
+class Parser(object):
+ """Parser methods base class
+
+ """
+
+ def __init__(self):
+ pass
+
+ @classmethod
+ def importprojectdir(cls,dir_project, type):
+ """Imports all files under a given folder
+
+ Returns an empty project
+ """
+
+ project = {}
+ return project
+
+ def get_all_ns_descriptors(self, nsd_id, project_data):
+ raise NotImplementedError
\ No newline at end of file
diff --git a/lib/rdcl_graph.py b/lib/rdcl_graph.py
new file mode 100644
index 0000000..9d96251
--- /dev/null
+++ b/lib/rdcl_graph.py
@@ -0,0 +1,82 @@
+#
+# Copyright 2017 CNIT - Consorzio Nazionale Interuniversitario per le Telecomunicazioni
+#
+# 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 BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+import json
+import logging
+import copy
+
+logging.basicConfig(level=logging.DEBUG)
+log = logging.getLogger('RdclGraph')
+
+
+class RdclGraph(object):
+ """ Operates on the graph representation used for the GUI graph views """
+
+ node_t3d_base = {
+ 'info': {
+ 'property': {
+ 'custom_label': '',
+ },
+ 'type': '',
+ 'group': []
+ }
+ }
+
+ def __init__(self):
+ pass
+
+ def add_link(self, source, target, view, group, graph_object, optional={}):
+ if (source is None) or (target is None):
+ return
+ edge_obj = {
+ 'source': source,
+ 'target': target,
+ 'view': view,
+ 'group': [group],
+
+ }
+
+ edge_obj.update(optional)
+ if edge_obj not in graph_object['edges']:
+ graph_object['edges'].append(edge_obj)
+
+ def add_node(self, id, type, group, positions, graph_object, optional={}):
+ if id is None:
+ return
+ node = next((x for x in graph_object['vertices'] if x['id'] == id), None)
+ if node is not None:
+ node['info']['group'].append(group)
+ else:
+ node = copy.deepcopy(self.node_t3d_base)
+ node['id'] = id
+ node['info']['type'] = type
+ if group is not None:
+ node['info']['group'].append(group)
+ if positions and id in positions['vertices'] and 'x' in positions['vertices'][id] and 'y' in positions['vertices'][id]:
+ node['fx'] = positions['vertices'][id]['x']
+ node['fy'] = positions['vertices'][id]['y']
+ node['info'].update(optional)
+ graph_object['vertices'].append(node)
+
+ def is_directed_edge(self, source_type=None, target_type=None, layer=None, model={}):
+ if source_type is None or target_type is None or layer is None:
+ return None
+ if layer in model['layer'] and 'allowed_edges' in model['layer'][layer]:
+ if source_type in model['layer'][layer]['allowed_edges'] and target_type in model['layer'][layer]['allowed_edges'][source_type]['destination']:
+ edge_pro = model['layer'][layer]['allowed_edges'][source_type]['destination'][target_type]
+ return edge_pro['direct_edge'] if 'direct_edge' in edge_pro else False
+
+ return None
diff --git a/lib/util.py b/lib/util.py
new file mode 100644
index 0000000..71fc36b
--- /dev/null
+++ b/lib/util.py
@@ -0,0 +1,198 @@
+#
+# Copyright 2017 CNIT - Consorzio Nazionale Interuniversitario per le Telecomunicazioni
+#
+# 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 BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+#
+
+import json
+import yaml
+import pyaml
+import logging
+import jsonschema
+import uuid
+
+_lib_name = 'Util'
+
+
+logging.basicConfig(level=logging.DEBUG)
+log = logging.getLogger('lib/util.py')
+
+
+class Util(object):
+
+ def __init__(self):
+ # logging.basicConfig(level=logging.DEBUG)
+ # self.log = logging.getLogger('UtilLogger')
+ pass
+
+
+ @classmethod
+ def json_load_byteified(cls, file_handle):
+ return cls._byteify(
+ json.load(file_handle, object_hook=cls._byteify),
+ ignore_dicts=True
+ )
+
+ @classmethod
+ def json_loads_byteified(cls, json_text):
+ return cls._byteify(
+ json.loads(json_text, object_hook=cls._byteify),
+ ignore_dicts=True
+ )
+
+ @classmethod
+ def _byteify(cls, data, ignore_dicts = False):
+ # if this is a unicode string, return its string representation
+ if isinstance(data, unicode):
+ return data.encode('utf-8')
+ # if this is a list of values, return list of byteified values
+ if isinstance(data, list):
+ return [ cls._byteify(item, ignore_dicts=True) for item in data ]
+ # if this is a dictionary, return dictionary of byteified keys and values
+ # but only if we haven't already byteified it
+ if isinstance(data, dict) and not ignore_dicts:
+ return {
+ cls._byteify(key, ignore_dicts=True): cls._byteify(value, ignore_dicts=True)
+ for key, value in data.iteritems()
+ }
+ # if it's anything else, return it in its original form
+ return data
+
+ @classmethod
+ def yaml2json(cls, object_yaml):
+ """Converts a yaml object into a json representation"""
+ log.debug('yaml2json')
+ return json.dumps(object_yaml, sort_keys=True, indent=2) if not object_yaml is None else None
+
+ @classmethod
+ def json2yaml(cls, object_json):
+ """Converts a json object into a yaml representation"""
+ log.debug('json2yaml')
+ return yaml.safe_dump(object_json, default_flow_style=False) if not object_json is None else None
+
+ @classmethod
+ def openfile(cls, filepath, mode='r', buffering=1):
+ """Returns an open file given a filepath
+
+ If the filepath is already an open file, returns into
+ Raises Exception
+ """
+
+ log.debug('reading file ' + filepath)
+ try:
+ if isinstance(filepath, file):
+ return filepath
+ else:
+ return open(filepath, mode, buffering)
+
+ except IOError as e:
+ log.exception('openfile', e)
+ raise
+
+ @classmethod
+ def loadyamlfile(cls, name):
+ """Returns a yaml object from a filename or an open file
+
+ Raises Exception
+ """
+
+ yaml_object = None
+ try:
+ if isinstance(name, file):
+ yaml_object = yaml.load(name)
+ else:
+ yaml_file = cls.openfile(name)
+ yaml_object = yaml.load(yaml_file)
+
+ return yaml_object
+ except Exception as e:
+ log.exception('Exception loadYamlFile', e)
+ raise
+
+ @classmethod
+ def loadjsonfile(cls, name):
+ """Returns a json object from a filename or an open file
+
+ Raises Exception
+ """
+
+ json_object = None
+ try:
+ #raise IOError('error from throws')
+ if isinstance(name, file):
+ json_object = json.load(name)
+ else:
+ # json_file = self.openfile(name)
+ json_file = cls.openfile(name)
+ json_object = json.load(json_file)
+
+ return json_object
+ except Exception as e:
+ log.exception('Exception loadJsonFile', e)
+ raise
+
+ @classmethod
+ def writejsonfile(cls, name, json_object):
+ """Writes the dump of a json obj to a filename or an open file
+
+ Raises Exception
+ """
+
+ try:
+ log.debug('writejsonfile ' + name)
+ if isinstance(name, file):
+ json_object = json.dump(json_object, name)
+ else:
+ json_file = cls.openfile(name, 'w')
+ json_object = json.dump(json_object, json_file,separators=(',',': '), indent=4)
+ except Exception as e:
+ log.exception('Exception writejsonfile', e)
+ raise
+
+ @classmethod
+ def writeyamlfile(cls, name, yaml_object):
+ """Writes the dump of a yaml obj to a filename or an open file
+
+ Raises Exception
+ """
+
+ try:
+ log.debug('writeyamlfile ' + name)
+ if isinstance(name, file):
+ yaml_object = pyaml.dump(yaml_object, name, safe=True)
+ else:
+ yaml_file = cls.openfile(name, 'w')
+ yaml_object = pyaml.dump(yaml_object, yaml_file, safe=True)
+ except Exception as e:
+ log.exception('Exception writeyamlfile')
+ raise
+
+ @classmethod
+ def validate_json_schema(cls, reference_schema, data):
+ """Validates a json data against a json schema
+
+ Raises Exception
+ """
+
+ try:
+ # schema = cls.loadjsonfile("lib/etsi/schemas/"+type_descriptor+".json")
+ #print 'type_descriptor : '+type_descriptor
+ jsonschema.validate(data, reference_schema)
+ return True
+ except Exception as e:
+ log.exception('Exception validate json schema', e)
+ return False
+
+ @classmethod
+ def get_unique_id(cls):
+ return uuid.uuid4().hex[:6].upper()