diff --git a/diskimage_builder/block_device/level0/localloop.py b/diskimage_builder/block_device/level0/localloop.py index 6d6084030..d5bd2c2e6 100644 --- a/diskimage_builder/block_device/level0/localloop.py +++ b/diskimage_builder/block_device/level0/localloop.py @@ -14,12 +14,12 @@ import logging import os -import subprocess from diskimage_builder.block_device.exception import \ BlockDeviceSetupException from diskimage_builder.block_device.plugin import NodeBase from diskimage_builder.block_device.plugin import PluginBase +from diskimage_builder.block_device.utils import exec_sudo from diskimage_builder.block_device.utils import parse_abs_size_spec @@ -41,17 +41,11 @@ def image_delete(filename): def loopdev_attach(filename): logger.info("loopdev attach") logger.debug("Calling [sudo losetup --show -f %s]", filename) - subp = subprocess.Popen(["sudo", "losetup", "--show", "-f", - filename], stdout=subprocess.PIPE) - rval = subp.wait() - if rval == 0: - # [:-1]: Cut of the newline - block_device = subp.stdout.read()[:-1].decode("utf-8") - logger.info("New block device [%s]", block_device) - return block_device - else: - logger.error("losetup failed") - raise BlockDeviceSetupException("losetup failed") + block_device = exec_sudo(["losetup", "--show", "-f", filename]) + # [:-1]: Cut of the newline + block_device = block_device[:-1] + logger.info("New block device [%s]", block_device) + return block_device def loopdev_detach(loopdev): @@ -59,19 +53,16 @@ def loopdev_detach(loopdev): # loopback dev may be tied up a bit by udev events triggered # by partition events for try_cnt in range(10, 1, -1): - logger.debug("Calling [sudo losetup -d %s]", loopdev) - subp = subprocess.Popen(["sudo", "losetup", "-d", - loopdev]) - rval = subp.wait() - if rval == 0: - logger.info("Successfully detached [%s]", loopdev) - return 0 - else: - logger.error("loopdev detach failed") + try: + exec_sudo(["losetup", "-d", loopdev]) + return + except BlockDeviceSetupException as e: # Do not raise an error - maybe other cleanup methods # can at least do some more work. + logger.error("loopdev detach failed (%s)", e.returncode) + logger.debug("Gave up trying to detach [%s]", loopdev) - return rval + return 1 class LocalLoopNode(NodeBase): diff --git a/diskimage_builder/block_device/level1/lvm.py b/diskimage_builder/block_device/level1/lvm.py index 2da53d1f7..2097f5e56 100644 --- a/diskimage_builder/block_device/level1/lvm.py +++ b/diskimage_builder/block_device/level1/lvm.py @@ -13,7 +13,6 @@ # limitations under the License. import logging -import subprocess from diskimage_builder.block_device.exception \ import BlockDeviceSetupException @@ -313,8 +312,8 @@ class LVMUmountNode(NodeBase): def umount(self): try: exec_sudo(['pvscan', '--cache']) - except subprocess.CalledProcessError as cpe: - logger.debug("pvscan call result [%s]", cpe) + except BlockDeviceSetupException as e: + logger.info("pvscan call failed [%s]", e.returncode) def get_edges(self): # This node depends on all physical device(s), which is diff --git a/diskimage_builder/block_device/utils.py b/diskimage_builder/block_device/utils.py index c89a7d60e..19047818a 100644 --- a/diskimage_builder/block_device/utils.py +++ b/diskimage_builder/block_device/utils.py @@ -12,10 +12,14 @@ # License for the specific language governing permissions and limitations # under the License. +import locale import logging import re import subprocess +from diskimage_builder.block_device.exception import \ + BlockDeviceSetupException + logger = logging.getLogger(__name__) @@ -95,10 +99,16 @@ def exec_sudo(cmd): at debug levels. Arguments: - :param cmd: str command list; for Popen() - :return: nothing - :raises: subprocess.CalledProcessError if return code != 0 + :param cmd: str command list; for Popen() + :return: the stdout+stderror of the called command + :raises BlockDeviceSetupException: if return code != 0. + + Exception values similar to ``subprocess.CalledProcessError`` + + * ``returncode`` : returncode of child + * ``cmd`` : the command run + * ``output`` : stdout+stderr output """ assert isinstance(cmd, list) sudo_cmd = ["sudo"] @@ -116,10 +126,20 @@ def exec_sudo(cmd): stdout=subprocess.PIPE, stderr=subprocess.STDOUT) - for line in iter(proc.stdout.readline, b""): - logger.debug("exec_sudo: %s", line.rstrip()) - + out = "" + with proc.stdout: + for line in iter(proc.stdout.readline, b''): + line = line.decode(encoding=locale.getpreferredencoding(False), + errors='backslashreplace') + out += line + logger.debug("exec_sudo: %s", line.rstrip()) proc.wait() - if proc.returncode != 0: - raise subprocess.CalledProcessError(proc.returncode, - ' '.join(sudo_cmd)) + + if proc.returncode: + e = BlockDeviceSetupException("exec_sudo failed") + e.returncode = proc.returncode + e.cmd = ' '.join(sudo_cmd) + e.output = out + raise e + + return out