From 8d14b30de885c9531ad7d2b365f5fd473b8702e1 Mon Sep 17 00:00:00 2001
From: Iustin Pop <iustin@google.com>
Date: Mon, 21 Apr 2008 13:04:57 +0000
Subject: [PATCH] Abstract the json functions into a separate module

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   |  2 +-
 lib/cmdlib.py     | 22 ++++-------------
 lib/config.py     |  6 +++--
 lib/objects.py    | 37 -----------------------------
 lib/serializer.py | 60 +++++++++++++++++++++++++++++++++++++++++++++++
 5 files changed, 69 insertions(+), 58 deletions(-)
 create mode 100644 lib/serializer.py

diff --git a/lib/Makefile.am b/lib/Makefile.am
index 994b2a394..067034540 100644
--- a/lib/Makefile.am
+++ b/lib/Makefile.am
@@ -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 locking.py luxi.py jqueue.py
+	ssconf.py locking.py luxi.py jqueue.py serializer.py
 
 all-local: _autoconf.py
 
diff --git a/lib/cmdlib.py b/lib/cmdlib.py
index 873f216db..2acbc05a5 100644
--- a/lib/cmdlib.py
+++ b/lib/cmdlib.py
@@ -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):
@@ -3162,10 +3154,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)
 
@@ -4876,7 +4865,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))
 
@@ -4968,10 +4957,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:
diff --git a/lib/config.py b/lib/config.py
index 3b2599412..59d72515f 100644
--- a/lib/config.py
+++ b/lib/config.py
@@ -42,6 +42,7 @@ from ganeti import utils
 from ganeti import constants
 from ganeti import rpc
 from ganeti import objects
+from ganeti import serializer
 
 
 class ConfigWriter:
@@ -502,7 +503,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:
@@ -560,11 +561,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()
diff --git a/lib/objects.py b/lib/objects.py
index 74c0c7e64..c84043375 100644
--- a/lib/objects.py
+++ b/lib/objects.py
@@ -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
index 000000000..d00dbc593
--- /dev/null
+++ b/lib/serializer.py
@@ -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)
-- 
GitLab