update from RIFT as of 696b75d2fe9fb046261b08c616f1bcf6c0b54a9b second try
[osm/SO.git] / rwlaunchpad / plugins / rwlaunchpadtasklet / rift / package / convert.py
index 7571c57..143b3e2 100644 (file)
@@ -1,6 +1,6 @@
 
 
-# 
-#   Copyright 2016 RIFT.IO Inc
+#
+#   Copyright 2016-2017 RIFT.IO Inc
 #
 #   Licensed under the Apache License, Version 2.0 (the "License");
 #   you may not use this file except in compliance with the License.
 #
 #   Licensed under the Apache License, Version 2.0 (the "License");
 #   you may not use this file except in compliance with the License.
 #
 
 import json
 #
 
 import json
+import logging
 import os
 import os
-import tempfile
+import yaml
 
 import gi
 gi.require_version('RwNsdYang', '1.0')
 
 import gi
 gi.require_version('RwNsdYang', '1.0')
+gi.require_version('RwProjectNsdYang', '1.0')
 gi.require_version('RwVnfdYang', '1.0')
 gi.require_version('RwVnfdYang', '1.0')
+gi.require_version('RwProjectVnfdYang', '1.0')
 gi.require_version('RwYang', '1.0')
 from gi.repository import (
         RwNsdYang,
         RwVnfdYang,
         NsdYang,
         VnfdYang,
 gi.require_version('RwYang', '1.0')
 from gi.repository import (
         RwNsdYang,
         RwVnfdYang,
         NsdYang,
         VnfdYang,
+        RwProjectNsdYang,
+        RwProjectVnfdYang,
+        ProjectNsdYang,
+        ProjectVnfdYang,
         RwYang,
         )
 
         RwYang,
         )
 
+from rift.mano.utils.project import NS_PROJECT
+from rift.rwlib.translation.json2xml import InvalidSchemaException
 
 class UnknownExtensionError(Exception):
     pass
 
 class UnknownExtensionError(Exception):
     pass
@@ -49,12 +58,17 @@ def decode(desc_data):
 
 class ProtoMessageSerializer(object):
     """(De)Serializer/deserializer fo a specific protobuf message into various formats"""
 
 class ProtoMessageSerializer(object):
     """(De)Serializer/deserializer fo a specific protobuf message into various formats"""
-    libncx_model = None
+    libyang_model = None
 
 
-    def __init__(self, yang_ns, yang_pb_cls):
+    def __init__(self, yang_ns, yang_pb_cls,
+                 yang_ns_project, yang_pb_project_cls):
         """ Create a serializer for a specific protobuf message """
         self._yang_ns = yang_ns
         self._yang_pb_cls = yang_pb_cls
         """ Create a serializer for a specific protobuf message """
         self._yang_ns = yang_ns
         self._yang_pb_cls = yang_pb_cls
+        self._yang_ns_project = yang_ns_project
+        self._yang_pb_project_cls = yang_pb_project_cls
+
+        self._log = logging.getLogger('rw-maon-log')
 
     @classmethod
     def _deserialize_extension_method_map(cls):
 
     @classmethod
     def _deserialize_extension_method_map(cls):
@@ -100,37 +114,92 @@ class ProtoMessageSerializer(object):
         """ The Protobuf's GI class (e.g. RwVnfdYang.YangData_Vnfd_VnfdCatalog_Vnfd) """
         return self._yang_pb_cls
 
         """ The Protobuf's GI class (e.g. RwVnfdYang.YangData_Vnfd_VnfdCatalog_Vnfd) """
         return self._yang_pb_cls
 
+    @property
+    def yang_ns_project(self):
+        """ The Protobuf's GI namespace class (e.g. RwProjectVnfdYang) """
+        return self._yang_ns_project
+
+    @property
+    def yang_class_project(self):
+        """ The Protobuf's GI class (e.g. RwProjectVnfdYang.YangData_RwProject_Project_VnfdCatalog_Vnfd) """
+        return self._yang_pb_project_cls
+
     @property
     def model(self):
         cls = self.__class__
 
     @property
     def model(self):
         cls = self.__class__
 
-        # Cache the libncx model for the serializer class
-        if cls.libncx_model is None:
-            cls.libncx_model = RwYang.model_create_libncx()
-            cls.libncx_model.load_schema_ypbc(self.yang_namespace.get_schema())
+        # Cache the libyang model for the serializer class
+        if cls.libyang_model is None:
+            cls.libyang_model = RwYang.model_create_libyang()
+            cls.libyang_model.load_schema_ypbc(self.yang_namespace.get_schema())
+            cls.libyang_model.load_schema_ypbc(self.yang_ns_project.get_schema())
 
 
-        return cls.libncx_model
+        return cls.libyang_model
 
 
-    def _from_xml_file_hdl(self, file_hdl):
+    def _from_xml_file_hdl(self, file_hdl, project=None):
         xml = file_hdl.read()
 
         xml = file_hdl.read()
 
-        return self.yang_class.from_xml_v2(self.model, decode(xml), strict=False)
+        return self.yang_class.from_xml_v2(self.model, decode(xml), strict=False) \
+            if not project else self._yang_pb_project_cls.from_xml_v2(self.model, decode(xml), strict=False)
+
+    def _from_json_file_hdl(self, file_hdl, project=None):
+        jstr = file_hdl.read()
+        self._log.debug("Convert from json file: {}".format(jstr))
+
+        try:
+            if not project:
+                desc_msg = self.yang_class.from_json(self.model, decode(jstr), strict=False)
+            else:
+                desc_msg = self._yang_pb_project_cls.from_json(self.model, decode(jstr), strict=False)
+
+            self._log.debug("desc_msg: {}".format(desc_msg.as_dict()))
+            return self.yang_class_project.from_dict(desc_msg.as_dict())
+        except Exception as e:
+            self._log.exception(e)
+            raise e
+
+    def _from_yaml_file_hdl(self, file_hdl, project=None):
+        yml = file_hdl.read()
+
+        try:
+            desc_msg = self.yang_class.from_yaml(self.model, decode(yml), strict=True)
+        except InvalidSchemaException as invalid_scheme_exception:
+            self._log.error("Exception raised during schema translation, %s. Launchpad will" \
+                            "continue to process the remaining elements ", str(invalid_scheme_exception))
+            desc_msg = self.yang_class.from_yaml(self.model, decode(yml), strict=False)
+        except Exception as e:
+            self._log.exception(e)
+            raise e
+
+        return self.yang_class_project.from_dict(desc_msg.as_dict()) 
 
 
-    def _from_json_file_hdl(self, file_hdl):
-        json = file_hdl.read()
+    def to_desc_msg(self, pb_msg, project_rooted=True):
+        """Convert to and from project rooted pb msg  descriptor to catalog
+           rooted pb msg
+           project_rooted: if pb_msg is project rooted or not
+        """
+        if project_rooted:
+            if isinstance(pb_msg, self._yang_pb_project_cls):
+                return self._yang_pb_cls.from_dict(pb_msg.as_dict())
+            elif isinstance(pb_msg, self._yang_pb_cls):
+                return pb_msg
 
 
-        return self.yang_class.from_json(self.model, decode(json), strict=False)
+        else:
+            if isinstance(pb_msg, self._yang_pb_cls):
+                return self._yang_pb_project_cls.from_dict(pb_msg.as_dict())
+            elif isinstance(pb_msg, self._yang_pb_project_cls):
+                return pb_msg
 
 
-    def _from_yaml_file_hdl(self, file_hdl):
-        yaml = file_hdl.read()
+        raise TypeError("Invalid protobuf message type provided: {}".format(type(pb_msg)))
 
 
-        return self.yang_class.from_yaml(self.model, decode(yaml), strict=False)
 
 
-    def to_json_string(self, pb_msg):
+    def to_json_string(self, pb_msg, project_ns=False):
         """ Serialize a protobuf message into JSON
 
         Arguments:
             pb_msg - A GI-protobuf object of type provided into constructor
         """ Serialize a protobuf message into JSON
 
         Arguments:
             pb_msg - A GI-protobuf object of type provided into constructor
+            project_ns - Need the desc in project namespace, required for
+                         posting to Restconf as part of onboarding
 
         Returns:
             A JSON string representing the protobuf message
 
         Returns:
             A JSON string representing the protobuf message
@@ -139,22 +208,32 @@ class ProtoMessageSerializer(object):
             SerializationError - Message could not be serialized
             TypeError - Incorrect protobuf type provided
         """
             SerializationError - Message could not be serialized
             TypeError - Incorrect protobuf type provided
         """
-        if not isinstance(pb_msg, self._yang_pb_cls):
-            raise TypeError("Invalid protobuf message type provided")
-
+        self._log.debug("Convert desc to json (ns:{}): {}".format(project_ns, pb_msg.as_dict()))
         try:
         try:
-            json_str = pb_msg.to_json(self.model)
+            # json_str = pb_msg.to_json(self.model)
+
+            desc_msg = self.to_desc_msg(pb_msg, not project_ns)
+            json_str = desc_msg.to_json(self.model)
+            if project_ns:
+                # Remove rw-project:project top level element
+                dic = json.loads(json_str)
+                jstr = json.dumps(dic[NS_PROJECT][0])
+            else:
+                jstr = json_str
 
         except Exception as e:
             raise SerializationError(e)
 
 
         except Exception as e:
             raise SerializationError(e)
 
-        return json_str
+        self._log.debug("Convert desc to json: {}".format(jstr))
+        return jstr
 
 
-    def to_yaml_string(self, pb_msg):
+    def to_yaml_string(self, pb_msg, project_ns=False):
         """ Serialize a protobuf message into YAML
 
         Arguments:
             pb_msg - A GI-protobuf object of type provided into constructor
         """ Serialize a protobuf message into YAML
 
         Arguments:
             pb_msg - A GI-protobuf object of type provided into constructor
+            project_ns - Need the desc in project namespace, required for
+                         posting to Restconf as part of onboarding
 
         Returns:
             A YAML string representing the protobuf message
 
         Returns:
             A YAML string representing the protobuf message
@@ -163,16 +242,23 @@ class ProtoMessageSerializer(object):
             SerializationError - Message could not be serialized
             TypeError - Incorrect protobuf type provided
         """
             SerializationError - Message could not be serialized
             TypeError - Incorrect protobuf type provided
         """
-        if not isinstance(pb_msg, self._yang_pb_cls):
-            raise TypeError("Invalid protobuf message type provided")
-
+        self._log.debug("Convert desc to yaml (ns:{}): {}".format(project_ns, pb_msg.as_dict()))
         try:
         try:
-            yaml_str = pb_msg.to_yaml(self.model)
+            desc_msg = self.to_desc_msg(pb_msg, not project_ns)
+            yaml_str = desc_msg.to_yaml(self.model)
+            if project_ns:
+                # Remove rw-project:project top level element
+                dic = yaml.loads(yaml_str)
+                ystr = yaml.dump(dic[NS_PROJECT][0])
+            else:
+                ystr = yaml_str
+
 
         except Exception as e:
 
         except Exception as e:
+            self._log.exception("Exception converting to yaml: {}".format(e))
             raise SerializationError(e)
 
             raise SerializationError(e)
 
-        return yaml_str
+        return ystr
 
     def to_xml_string(self, pb_msg):
         """ Serialize a protobuf message into XML
 
     def to_xml_string(self, pb_msg):
         """ Serialize a protobuf message into XML
@@ -187,18 +273,17 @@ class ProtoMessageSerializer(object):
             SerializationError - Message could not be serialized
             TypeError - Incorrect protobuf type provided
         """
             SerializationError - Message could not be serialized
             TypeError - Incorrect protobuf type provided
         """
-        if not isinstance(pb_msg, self._yang_pb_cls):
-            raise TypeError("Invalid protobuf message type provided")
-
         try:
         try:
-            xml_str = pb_msg.to_xml_v2(self.model)
+            desc_msg = self.to_desc_msg(pb_msg)
+            xml_str = desc_msg.to_xml_v2(self.model)
 
         except Exception as e:
 
         except Exception as e:
+            self._log.exception("Exception converting to xml: {}".format(e))
             raise SerializationError(e)
 
         return xml_str
 
             raise SerializationError(e)
 
         return xml_str
 
-    def from_file_hdl(self, file_hdl, extension):
+    def from_file_hdl(self, file_hdl, extension, project=None):
         """ Returns the deserialized protobuf message from file contents
 
         This function determines the serialization format based on file extension
         """ Returns the deserialized protobuf message from file contents
 
         This function determines the serialization format based on file extension
@@ -222,7 +307,8 @@ class ProtoMessageSerializer(object):
             raise UnknownExtensionError("Cannot detect message format for %s extension" % extension_lc)
 
         try:
             raise UnknownExtensionError("Cannot detect message format for %s extension" % extension_lc)
 
         try:
-            msg = extension_map[extension_lc](self, file_hdl)
+            self._log.debug("Converting from json..project = {}".format(project))
+            msg = extension_map[extension_lc](self, file_hdl, project)
         except Exception as e:
             raise SerializationError(e)
 
         except Exception as e:
             raise SerializationError(e)
 
@@ -262,22 +348,26 @@ class ProtoMessageSerializer(object):
 class VnfdSerializer(ProtoMessageSerializer):
     """ Creates a serializer for the VNFD descriptor"""
     def __init__(self):
 class VnfdSerializer(ProtoMessageSerializer):
     """ Creates a serializer for the VNFD descriptor"""
     def __init__(self):
-        super().__init__(VnfdYang, VnfdYang.YangData_Vnfd_VnfdCatalog_Vnfd)
+        super().__init__(VnfdYang, VnfdYang.YangData_Vnfd_VnfdCatalog_Vnfd,
+                         ProjectVnfdYang, ProjectVnfdYang.YangData_RwProject_Project_VnfdCatalog_Vnfd)
 
 
 class NsdSerializer(ProtoMessageSerializer):
     """ Creates a serializer for the NSD descriptor"""
     def __init__(self):
 
 
 class NsdSerializer(ProtoMessageSerializer):
     """ Creates a serializer for the NSD descriptor"""
     def __init__(self):
-        super().__init__(NsdYang, NsdYang.YangData_Nsd_NsdCatalog_Nsd)
+        super().__init__(NsdYang, NsdYang.YangData_Nsd_NsdCatalog_Nsd,
+                         ProjectNsdYang, ProjectNsdYang.YangData_RwProject_Project_NsdCatalog_Nsd)
 
 
 class RwVnfdSerializer(ProtoMessageSerializer):
     """ Creates a serializer for the VNFD descriptor"""
     def __init__(self):
 
 
 class RwVnfdSerializer(ProtoMessageSerializer):
     """ Creates a serializer for the VNFD descriptor"""
     def __init__(self):
-        super().__init__(RwVnfdYang, RwVnfdYang.YangData_Vnfd_VnfdCatalog_Vnfd)
+        super().__init__(RwVnfdYang, RwVnfdYang.YangData_Vnfd_VnfdCatalog_Vnfd,
+                         RwProjectVnfdYang, RwProjectVnfdYang.YangData_RwProject_Project_VnfdCatalog_Vnfd)
 
 
 class RwNsdSerializer(ProtoMessageSerializer):
     """ Creates a serializer for the NSD descriptor"""
     def __init__(self):
 
 
 class RwNsdSerializer(ProtoMessageSerializer):
     """ Creates a serializer for the NSD descriptor"""
     def __init__(self):
-        super().__init__(RwNsdYang, RwNsdYang.YangData_Nsd_NsdCatalog_Nsd)
+        super().__init__(RwNsdYang, RwNsdYang.YangData_Nsd_NsdCatalog_Nsd,
+                         RwProjectNsdYang, RwProjectNsdYang.YangData_RwProject_Project_NsdCatalog_Nsd)