← Back to team overview

cloud-init-dev team mailing list archive

[Merge] lp:~harlowja/cloud-init/debug-pretty into lp:cloud-init

 

Joshua Harlow has proposed merging lp:~harlowja/cloud-init/debug-pretty into lp:cloud-init.

Requested reviews:
  cloud init development team (cloud-init-dev)

For more details, see:
https://code.launchpad.net/~harlowja/cloud-init/debug-pretty/+merge/238799

Pretty up the debug module

Previously the usage of the yaml_dumps module was causing
any python unicode key and value to show up as:

'item': !!python/unicode "some string"

This was not very pretty...

Fix this by using safe_dumps (which is also a good thing to
use and allow_unicode=True). Also create a tiny helper function
in the cc_debug module that does not include the yaml start and
end footers (since this module has its own footers and headers).

Also includes a basic sanity test for this module.

-- 
https://code.launchpad.net/~harlowja/cloud-init/debug-pretty/+merge/238799
Your team cloud init development team is requested to review the proposed merge of lp:~harlowja/cloud-init/debug-pretty into lp:cloud-init.
=== modified file 'cloudinit/config/cc_debug.py'
--- cloudinit/config/cc_debug.py	2014-01-23 19:28:59 +0000
+++ cloudinit/config/cc_debug.py	2014-10-18 16:32:48 +0000
@@ -14,10 +14,13 @@
 #    You should have received a copy of the GNU General Public License
 #    along with this program.  If not, see <http://www.gnu.org/licenses/>.
 
+import copy
+from StringIO import StringIO
+
 from cloudinit import type_utils
 from cloudinit import util
-import copy
-from StringIO import StringIO
+
+SKIP_KEYS = frozenset(['log_cfgs'])
 
 
 def _make_header(text):
@@ -31,6 +34,11 @@
     return header.getvalue()
 
 
+def _dumps(obj):
+    text = util.yaml_dumps(obj, explicit_start=False, explicit_end=False)
+    return text.rstrip()
+
+
 def handle(name, cfg, cloud, log, args):
     verbose = util.get_cfg_by_path(cfg, ('debug', 'verbose'), default=True)
     if args:
@@ -46,7 +54,7 @@
         return
     # Clean out some keys that we just don't care about showing...
     dump_cfg = copy.deepcopy(cfg)
-    for k in ['log_cfgs']:
+    for k in SKIP_KEYS:
         dump_cfg.pop(k, None)
     all_keys = list(dump_cfg.keys())
     for k in all_keys:
@@ -55,10 +63,10 @@
     # Now dump it...
     to_print = StringIO()
     to_print.write(_make_header("Config"))
-    to_print.write(util.yaml_dumps(dump_cfg))
+    to_print.write(_dumps(dump_cfg))
     to_print.write("\n")
     to_print.write(_make_header("MetaData"))
-    to_print.write(util.yaml_dumps(cloud.datasource.metadata))
+    to_print.write(_dumps(cloud.datasource.metadata))
     to_print.write("\n")
     to_print.write(_make_header("Misc"))
     to_print.write("Datasource: %s\n" %

=== modified file 'cloudinit/util.py'
--- cloudinit/util.py	2014-09-30 20:24:54 +0000
+++ cloudinit/util.py	2014-10-18 16:32:48 +0000
@@ -1270,14 +1270,14 @@
             logexc(LOG, "Failed writing url content to %s", target_fn)
 
 
-def yaml_dumps(obj):
-    formatted = yaml.dump(obj,
-                    line_break="\n",
-                    indent=4,
-                    explicit_start=True,
-                    explicit_end=True,
-                    default_flow_style=False)
-    return formatted
+def yaml_dumps(obj, explicit_start=True, explicit_end=True):
+    return yaml.safe_dump(obj,
+                          line_break="\n",
+                          indent=4,
+                          explicit_start=explicit_start,
+                          explicit_end=explicit_end,
+                          default_flow_style=False,
+                          allow_unicode=True)
 
 
 def ensure_dir(path, mode=None):

=== added file 'tests/unittests/test_handler/test_handler_debug.py'
--- tests/unittests/test_handler/test_handler_debug.py	1970-01-01 00:00:00 +0000
+++ tests/unittests/test_handler/test_handler_debug.py	2014-10-18 16:32:48 +0000
@@ -0,0 +1,78 @@
+# vi: ts=4 expandtab
+#
+#    Copyright (C) 2014 Yahoo! Inc.
+#
+#    This program is free software: you can redistribute it and/or modify
+#    it under the terms of the GNU General Public License version 3, as
+#    published by the Free Software Foundation.
+#
+#    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, see <http://www.gnu.org/licenses/>.
+
+from cloudinit.config import cc_debug
+
+from cloudinit import cloud
+from cloudinit import distros
+from cloudinit import helpers
+from cloudinit import util
+
+from cloudinit.sources import DataSourceNone
+
+from .. import helpers as t_help
+
+import logging
+
+LOG = logging.getLogger(__name__)
+
+
+class TestDebug(t_help.FilesystemMockingTestCase):
+    def setUp(self):
+        super(TestDebug, self).setUp()
+        self.new_root = self.makeDir(prefix="unittest_")
+
+    def _get_cloud(self, distro, metadata=None):
+        self.patchUtils(self.new_root)
+        paths = helpers.Paths({})
+        cls = distros.fetch(distro)
+        d = cls(distro, {}, paths)
+        ds = DataSourceNone.DataSourceNone({}, d, paths)
+        if metadata:
+            ds.metadata.update(metadata)
+        return cloud.Cloud(ds, paths, {}, d, None)
+
+    def test_debug_write(self):
+        cfg = {
+            'abc': '123',
+            'c': u'\u20a0',
+            'debug': {
+                'verbose': True,
+                # Does not actually write here due to mocking...
+                'output': '/var/log/cloud-init-debug.log',
+            },
+        }
+        cc = self._get_cloud('ubuntu')
+        cc_debug.handle('cc_debug', cfg, cc, LOG, [])
+        contents = util.load_file('/var/log/cloud-init-debug.log')
+        # Some basic sanity tests...
+        self.assertGreater(len(contents), 0)
+        for k in cfg.keys():
+            self.assertIn(k, contents)
+
+    def test_debug_no_write(self):
+        cfg = {
+            'abc': '123',
+            'debug': {
+                'verbose': False,
+                # Does not actually write here due to mocking...
+                'output': '/var/log/cloud-init-debug.log',
+            },
+        }
+        cc = self._get_cloud('ubuntu')
+        cc_debug.handle('cc_debug', cfg, cc, LOG, [])
+        self.assertRaises(IOError,
+                          util.load_file, '/var/log/cloud-init-debug.log')


Follow ups