Abstract the json functions into a separate module
authorIustin Pop <iustin@google.com>
Mon, 21 Apr 2008 13:01:54 +0000 (13:01 +0000)
committerIustin Pop <iustin@google.com>
Mon, 21 Apr 2008 13:01:54 +0000 (13:01 +0000)
This simple patch adds a new module that holds the simplejson functions
for serialization/deserialization. This reduces the amount of redundant
code.

The patch also adds some normalizations to the json output:
  - the output text will always have an EOL as last char
  - extra spaces before EOL are removed

Reviewed-by: ultrotter

lib/Makefile.am
lib/cmdlib.py
lib/config.py
lib/objects.py
lib/serializer.py [new file with mode: 0644]

index 0f82d0d..fe6e7c4 100644 (file)
@@ -4,7 +4,7 @@ nodist_pkgpython_PYTHON = _autoconf.py
 pkgpython_PYTHON = __init__.py backend.py cli.py cmdlib.py config.py \
        objects.py errors.py logger.py ssh.py utils.py rpc.py \
        bdev.py hypervisor.py opcodes.py mcpu.py constants.py \
-       ssconf.py
+       ssconf.py serializer.py
 
 nobase_pkgpython_PYTHON = rapi/__init__.py \
        rapi/resources.py rapi/RESTHTTPServer.py
index 8658eeb..8b99360 100644 (file)
@@ -30,7 +30,6 @@ import time
 import tempfile
 import re
 import platform
-import simplejson
 
 from ganeti import rpc
 from ganeti import ssh
@@ -43,14 +42,7 @@ from ganeti import constants
 from ganeti import objects
 from ganeti import opcodes
 from ganeti import ssconf
-
-
-# Check whether the simplejson module supports indentation
-_JSON_INDENT = 2
-try:
-  simplejson.dumps(1, indent=_JSON_INDENT)
-except TypeError:
-  _JSON_INDENT = None
+from ganeti import serializer
 
 
 class LogicalUnit(object):
@@ -3052,10 +3044,7 @@ class LUCreateInstance(LogicalUnit):
 
     _IAllocatorAddNewInstance(al_data, op)
 
-    if _JSON_INDENT is None:
-      text = simplejson.dumps(al_data)
-    else:
-      text = simplejson.dumps(al_data, indent=_JSON_INDENT)
+    text = serializer.Dump(al_data)
 
     result = _IAllocatorRun(self.op.iallocator, text)
 
@@ -4945,7 +4934,7 @@ def _IAllocatorValidateResult(data):
 
   """
   try:
-    rdict = simplejson.loads(data)
+    rdict = serializer.Load(data)
   except Exception, err:
     raise errors.OpExecError("Can't parse iallocator results: %s" % str(err))
 
@@ -5037,10 +5026,7 @@ class LUTestAllocator(NoHooksLU):
     else:
       _IAllocatorAddRelocateInstance(data, self.op)
 
-    if _JSON_INDENT is None:
-      text = simplejson.dumps(data)
-    else:
-      text = simplejson.dumps(data, indent=_JSON_INDENT)
+    text = serializer.Dump(data)
     if self.op.direction == constants.IALLOCATOR_DIR_IN:
       result = text
     else:
index d8c2605..fa7f350 100644 (file)
@@ -41,6 +41,7 @@ from ganeti import utils
 from ganeti import constants
 from ganeti import rpc
 from ganeti import objects
+from ganeti import serializer
 
 
 class ConfigWriter:
@@ -491,7 +492,7 @@ class ConfigWriter:
     f = open(self._cfg_file, 'r')
     try:
       try:
-        data = objects.ConfigData.Load(f)
+        data = objects.ConfigData.FromDict(serializer.Load(f.read()))
       except Exception, err:
         raise errors.ConfigurationError(err)
     finally:
@@ -549,11 +550,12 @@ class ConfigWriter:
     if destination is None:
       destination = self._cfg_file
     self._BumpSerialNo()
+    txt = serializer.Dump(self._config_data.ToDict())
     dir_name, file_name = os.path.split(destination)
     fd, name = tempfile.mkstemp('.newconfig', file_name, dir_name)
     f = os.fdopen(fd, 'w')
     try:
-      self._config_data.Dump(f)
+      f.write(txt)
       os.fsync(f.fileno())
     finally:
       f.close()
index 6dd5141..8a7a56e 100644 (file)
@@ -27,7 +27,6 @@ pass to and from external parties.
 """
 
 
-import simplejson
 import ConfigParser
 import re
 from cStringIO import StringIO
@@ -40,14 +39,6 @@ __all__ = ["ConfigObject", "ConfigData", "NIC", "Disk", "Instance",
            "OS", "Node", "Cluster"]
 
 
-# Check whether the simplejson module supports indentation
-_JSON_INDENT = 2
-try:
-  simplejson.dumps(1, indent=_JSON_INDENT)
-except TypeError:
-  _JSON_INDENT = None
-
-
 class ConfigObject(object):
   """A generic config object.
 
@@ -90,34 +81,6 @@ class ConfigObject(object):
       if name in self.__slots__:
         setattr(self, name, state[name])
 
-  def Dump(self, fobj):
-    """Dump to a file object.
-
-    """
-    data = self.ToDict()
-    if _JSON_INDENT is None:
-      simplejson.dump(data, fobj)
-    else:
-      simplejson.dump(data, fobj, indent=_JSON_INDENT)
-
-  @classmethod
-  def Load(cls, fobj):
-    """Load data from the given stream.
-
-    """
-    return cls.FromDict(simplejson.load(fobj))
-
-  def Dumps(self):
-    """Dump and return the string representation."""
-    buf = StringIO()
-    self.Dump(buf)
-    return buf.getvalue()
-
-  @classmethod
-  def Loads(cls, data):
-    """Load data from a string."""
-    return cls.Load(StringIO(data))
-
   def ToDict(self):
     """Convert to a dict holding only standard python types.
 
diff --git a/lib/serializer.py b/lib/serializer.py
new file mode 100644 (file)
index 0000000..d00dbc5
--- /dev/null
@@ -0,0 +1,60 @@
+#
+#
+
+# Copyright (C) 2007, 2008 Google Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 2 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful, but
+# WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program; if not, write to the Free Software
+# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+# 02110-1301, USA.
+
+"""Serializer abstraction module
+
+This module introduces a simple abstraction over the serialization
+backend (currently json).
+
+"""
+
+import simplejson
+import ConfigParser
+import re
+
+# Check whether the simplejson module supports indentation
+_JSON_INDENT = 2
+try:
+  simplejson.dumps(1, indent=_JSON_INDENT)
+except TypeError:
+  _JSON_INDENT = None
+
+_RE_EOLSP = re.compile('\s+$', re.MULTILINE)
+
+
+def Dump(data):
+  """Serialize a given object.
+
+  """
+  if _JSON_INDENT is None:
+    txt = simplejson.dumps(data)
+  else:
+    txt = simplejson.dumps(data, indent=_JSON_INDENT)
+  if not txt.endswith('\n'):
+    txt += '\n'
+  txt = _RE_EOLSP.sub("", txt)
+  return txt
+
+
+def Load(txt):
+  """Unserialize data from a string.
+
+  """
+  return simplejson.loads(txt)