← Back to team overview

cloud-init-dev team mailing list archive

[Merge] ~smoser/cloud-init:feature/subp_add_update_env into cloud-init:master

 

Scott Moser has proposed merging ~smoser/cloud-init:feature/subp_add_update_env into cloud-init:master.

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

For more details, see:
https://code.launchpad.net/~smoser/cloud-init/+git/cloud-init/+merge/306391
-- 
Your team cloud init development team is requested to review the proposed merge of ~smoser/cloud-init:feature/subp_add_update_env into cloud-init:master.
diff --git a/cloudinit/util.py b/cloudinit/util.py
index 6c5cf74..05cb587 100644
--- a/cloudinit/util.py
+++ b/cloudinit/util.py
@@ -1762,7 +1762,7 @@ def delete_dir_contents(dirname):
 
 
 def subp(args, data=None, rcs=None, env=None, capture=True, shell=False,
-         logstring=False, decode="replace", target=None):
+         logstring=False, decode="replace", target=None, update_env=None):
 
     # not supported in cloud-init (yet), for now kept in the call signature
     # to ease maintaining code shared between cloud-init and curtin
@@ -1773,6 +1773,13 @@ def subp(args, data=None, rcs=None, env=None, capture=True, shell=False,
         rcs = [0]
 
     devnull_fp = None
+
+    if update_env:
+        if env is None:
+            env = os.environ
+        env = env.copy()
+        env.update(update_env)
+
     try:
         if target_path(target) != "/":
             args = ['chroot', target] + list(args)
diff --git a/tests/unittests/test_util.py b/tests/unittests/test_util.py
index d2031f5..81a13e2 100644
--- a/tests/unittests/test_util.py
+++ b/tests/unittests/test_util.py
@@ -516,6 +516,7 @@ class TestSubp(helpers.TestCase):
     utf8_invalid = b'ab\xaadef'
     utf8_valid = b'start \xc3\xa9 end'
     utf8_valid_2 = b'd\xc3\xa9j\xc8\xa7'
+    printenv = ['bash', '-c', 'for n in "$@"; do echo "$n=${!n}"; done', '--']
 
     def printf_cmd(self, *args):
         # bash's printf supports \xaa.  So does /usr/bin/printf
@@ -566,6 +567,29 @@ class TestSubp(helpers.TestCase):
         self.assertEqual(err, data)
         self.assertEqual(out, b'')
 
+    def test_subp_reads_env(self):
+        with mock.patch.dict("os.environ", values={'FOO': 'BAR'}):
+            out, err = util.subp(self.printenv + ['FOO'], capture=True)
+            self.assertEqual('FOO=BAR', out.splitlines()[0])
+
+    def test_subp_env_and_update_env(self):
+        out, err = util.subp(
+            self.printenv + ['FOO', 'HOME', 'K1', 'K2'], capture=True,
+            env={'FOO': 'BAR'},
+            update_env={'HOME': '/myhome', 'K2': 'V2'})
+        self.assertEqual(
+            ['FOO=BAR', 'HOME=/myhome', 'K1=', 'K2=V2'], out.splitlines())
+
+    def test_subp_update_env(self):
+        extra = {'FOO': 'BAR', 'HOME': '/root', 'K1': 'V1'}
+        with mock.patch.dict("os.environ", values=extra) as env:
+            out, err = util.subp(
+                self.printenv + ['FOO', 'HOME', 'K1', 'K2'], capture=True,
+                update_env={'HOME': '/myhome', 'K2': 'V2'})
+
+        self.assertEqual(
+            ['FOO=BAR', 'HOME=/myhome', 'K1=V1', 'K2=V2'], out.splitlines())
+
     def test_returns_none_if_no_capture(self):
         (out, err) = util.subp(self.stdin2out, data=b'', capture=False)
         self.assertEqual(err, None)

Follow ups