cloud-init-dev team mailing list archive
-
cloud-init-dev team
-
Mailing list archive
-
Message #04086
[Merge] ~smoser/cloud-init:fix/subp-exception-with-bytes into cloud-init:master
Scott Moser has proposed merging ~smoser/cloud-init:fix/subp-exception-with-bytes into cloud-init:master.
Commit message:
subp: make ProcessExecutionError have expected types in stderr, stdout.
When subp raised a ProcessExecutionError, that exception's stderr and
stdout might end up being the string '-' rather than bytes.
This mean that:
try:
subp(mycommand, decode=False)
except ProcessExecutionError as e:
pass
Would have 'e.stdout' set to '-' while the caller would expect bytes.
Requested reviews:
cloud-init commiters (cloud-init-dev)
For more details, see:
https://code.launchpad.net/~smoser/cloud-init/+git/cloud-init/+merge/336497
see commit message
--
Your team cloud-init commiters is requested to review the proposed merge of ~smoser/cloud-init:fix/subp-exception-with-bytes into cloud-init:master.
diff --git a/cloudinit/util.py b/cloudinit/util.py
index e42498d..779d2b2 100644
--- a/cloudinit/util.py
+++ b/cloudinit/util.py
@@ -253,12 +253,18 @@ class ProcessExecutionError(IOError):
self.exit_code = exit_code
if not stderr:
- self.stderr = self.empty_attr
+ if stderr is None:
+ self.stderr = self.empty_attr
+ else:
+ self.stderr = stderr
else:
self.stderr = self._indent_text(stderr)
if not stdout:
- self.stdout = self.empty_attr
+ if stdout is None:
+ self.stdout = self.empty_attr
+ else:
+ self.stdout = stdout
else:
self.stdout = self._indent_text(stdout)
@@ -1829,58 +1835,60 @@ def subp(args, data=None, rcs=None, env=None, capture=True, shell=False,
env = env.copy()
env.update(update_env)
- try:
- if target_path(target) != "/":
- args = ['chroot', target] + list(args)
+ if target_path(target) != "/":
+ args = ['chroot', target] + list(args)
- if not logstring:
- LOG.debug(("Running command %s with allowed return codes %s"
- " (shell=%s, capture=%s)"), args, rcs, shell, capture)
- else:
- LOG.debug(("Running hidden command to protect sensitive "
- "input/output logstring: %s"), logstring)
-
- stdin = None
- stdout = None
- stderr = None
- if capture:
- stdout = subprocess.PIPE
- stderr = subprocess.PIPE
- if data is None:
- # using devnull assures any reads get null, rather
- # than possibly waiting on input.
- devnull_fp = open(os.devnull)
- stdin = devnull_fp
- else:
- stdin = subprocess.PIPE
- if not isinstance(data, bytes):
- data = data.encode()
+ if not logstring:
+ LOG.debug(("Running command %s with allowed return codes %s"
+ " (shell=%s, capture=%s)"), args, rcs, shell, capture)
+ else:
+ LOG.debug(("Running hidden command to protect sensitive "
+ "input/output logstring: %s"), logstring)
+
+ stdin = None
+ stdout = None
+ stderr = None
+ if capture:
+ stdout = subprocess.PIPE
+ stderr = subprocess.PIPE
+ if data is None:
+ # using devnull assures any reads get null, rather
+ # than possibly waiting on input.
+ devnull_fp = open(os.devnull)
+ stdin = devnull_fp
+ else:
+ stdin = subprocess.PIPE
+ if not isinstance(data, bytes):
+ data = data.encode()
+ try:
sp = subprocess.Popen(args, stdout=stdout,
stderr=stderr, stdin=stdin,
env=env, shell=shell)
(out, err) = sp.communicate(data)
-
- # Just ensure blank instead of none.
- if not out and capture:
- out = b''
- if not err and capture:
- err = b''
- if decode:
- def ldecode(data, m='utf-8'):
- if not isinstance(data, bytes):
- return data
- return data.decode(m, decode)
-
- out = ldecode(out)
- err = ldecode(err)
except OSError as e:
- raise ProcessExecutionError(cmd=args, reason=e,
- errno=e.errno)
+ raise ProcessExecutionError(
+ cmd=args, reason=e, errno=e.errno,
+ stdout="-" if decode else b"-",
+ sterr="-" if decode else b"-")
finally:
if devnull_fp:
devnull_fp.close()
+ # Just ensure blank instead of none.
+ if not out and capture:
+ out = b''
+ if not err and capture:
+ err = b''
+ if decode:
+ def ldecode(data, m='utf-8'):
+ if not isinstance(data, bytes):
+ return data
+ return data.decode(m, decode)
+
+ out = ldecode(out)
+ err = ldecode(err)
+
rc = sp.returncode
if rc not in rcs:
raise ProcessExecutionError(stdout=out, stderr=err,
Follow ups