← Back to team overview

cloud-init-dev team mailing list archive

[Merge] ~chad.smith/cloud-init:bug/util-subp-accepts-string-cmd into cloud-init:master

 

Chad Smith has proposed merging ~chad.smith/cloud-init:bug/util-subp-accepts-string-cmd into cloud-init:master.

Requested reviews:
  cloud-init commiters (cloud-init-dev)

For more details, see:
https://code.launchpad.net/~chad.smith/cloud-init/+git/cloud-init/+merge/341437

util: Fix subp regression. Allow specifying subp command as a string.

The command provided to subp can either be a string or a list. This patch
fixes a regression which raised CalledProcessError whenever providing a
string to subp.

LP: #1755965
-- 
Your team cloud-init commiters is requested to review the proposed merge of ~chad.smith/cloud-init:bug/util-subp-accepts-string-cmd into cloud-init:master.
diff --git a/cloudinit/util.py b/cloudinit/util.py
index 083a8ef..c62b602 100644
--- a/cloudinit/util.py
+++ b/cloudinit/util.py
@@ -1867,8 +1867,14 @@ def subp(args, data=None, rcs=None, env=None, capture=True, shell=False,
     # Popen converts entries in the arguments array from non-bytes to bytes.
     # When locale is unset it may use ascii for that encoding which can
     # cause UnicodeDecodeErrors. (LP: #1751051)
-    bytes_args = [x if isinstance(x, six.binary_type) else x.encode("utf-8")
-                  for x in args]
+    if isinstance(args, (list, tuple)):
+        bytes_args = [
+            x if isinstance(x, six.binary_type) else x.encode("utf-8")
+            for x in args]
+    elif isinstance(args, six.binary_type):
+        bytes_args = args
+    else:
+        bytes_args = args.encode("utf-8")
     try:
         sp = subprocess.Popen(bytes_args, stdout=stdout,
                               stderr=stderr, stdin=stdin,
diff --git a/tests/unittests/test_util.py b/tests/unittests/test_util.py
index 89ae40f..499e7c9 100644
--- a/tests/unittests/test_util.py
+++ b/tests/unittests/test_util.py
@@ -632,6 +632,24 @@ class TestSubp(helpers.CiTestCase):
         # but by using bash, we remove dependency on another program.
         return([BASH, '-c', 'printf "$@"', 'printf'] + list(args))
 
+    def test_subp_handles_bytestrings(self):
+        """subp can run a bytestring command if shell is True."""
+        tmp_file = self.tmp_path('test.out')
+        cmd = 'echo HI MOM >> {tmp_file}'.format(tmp_file=tmp_file)
+        (out, _err) = util.subp(cmd.encode('utf-8'), shell=True)
+        self.assertEqual(u'', out)
+        self.assertEqual(u'', _err)
+        self.assertEqual('HI MOM\n', util.load_file(tmp_file))
+
+    def test_subp_handles_strings(self):
+        """subp can run a string command if shell is True."""
+        tmp_file = self.tmp_path('test.out')
+        cmd = 'echo HI MOM >> {tmp_file}'.format(tmp_file=tmp_file)
+        (out, _err) = util.subp(cmd, shell=True)
+        self.assertEqual(u'', out)
+        self.assertEqual(u'', _err)
+        self.assertEqual('HI MOM\n', util.load_file(tmp_file))
+
     def test_subp_handles_utf8(self):
         # The given bytes contain utf-8 accented characters as seen in e.g.
         # the "deja dup" package in Ubuntu.

Follow ups