Project

General

Profile

Actions

Bug #44881

open

unit tests mocking of lvm binaries incomplete

Added by Jan Fajerski about 4 years ago.

Status:
New
Priority:
Normal
Assignee:
-
Target version:
-
% Done:

0%

Source:
Tags:
Backport:
Regression:
No
Severity:
3 - minor
Reviewed:
Affected Versions:
ceph-qa-suite:
Pull request ID:
Crash signature (v1):
Crash signature (v2):

Description

Fails tests on machines, that don't have lvm installed:

--> Executable pvs not in PATH: /home/jenkins-build/build/workspace/ceph-volume-pr/src/ceph-volume/.tox/py35/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
------------------------------ Captured log call -------------------------------
WARNING  ceph_volume.util.system:terminal.py:170 Executable pvs not in PATH: /home/jenkins-build/build/workspace/ceph-volume-pr/src/ceph-volume/.tox/py35/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
INFO     ceph_volume.process:process.py:191 Running command: pvs --noheadings --readonly --separator=";" -a -o lv_tags,lv_path,lv_name,vg_name,lv_uuid,lv_size /dev/sda1
_______________________ TestDevice.test_vgs_is_not_empty _______________________

self = <test_device.TestDevice object at 0x7f5484d6c438>
device_info = <function device_info.<locals>.apply at 0x7f5484d59268>
monkeypatch = <_pytest.monkeypatch.MonkeyPatch object at 0x7f5484d6cf60>

    def test_vgs_is_not_empty(self, device_info, monkeypatch):
        vg = api.VolumeGroup(vg_name='foo/bar', vg_free_count=6,
                             vg_extent_size=1073741824)
        monkeypatch.setattr(api, 'get_device_vgs', lambda x: [vg])
        lsblk = {"TYPE": "disk"}
        device_info(lsblk=lsblk)
>       disk = device.Device("/dev/nvme0n1")

ceph_volume/tests/util/test_device.py:50: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
ceph_volume/util/device.py:92: in __init__
    self._parse()
ceph_volume/util/device.py:148: in _parse
    self._set_lvm_membership()
ceph_volume/util/device.py:250: in _set_lvm_membership
    self.lvs.extend(lvm.get_device_lvs(path))
ceph_volume/api/lvm.py:1379: in get_device_lvs
    verbose_on_failure=False
ceph_volume/process.py:201: in call
    **kw
/usr/lib/python3.5/subprocess.py:947: in __init__
    restore_signals, start_new_session)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <subprocess.Popen object at 0x7f5484da2eb8>
args = ['pvs', '--noheadings', '--readonly', '--separator=";"', '-a', '-o', ...]
executable = b'pvs', preexec_fn = None, close_fds = True, pass_fds = ()
cwd = None, env = None, startupinfo = None, creationflags = 0, shell = False
p2cread = 15, p2cwrite = 16, c2pread = 17, c2pwrite = 18, errread = 19
errwrite = 20, restore_signals = True, start_new_session = False

    def _execute_child(self, args, executable, preexec_fn, close_fds,
                       pass_fds, cwd, env,
                       startupinfo, creationflags, shell,
                       p2cread, p2cwrite,
                       c2pread, c2pwrite,
                       errread, errwrite,
                       restore_signals, start_new_session):
        """Execute program (POSIX version)""" 

        if isinstance(args, (str, bytes)):
            args = [args]
        else:
            args = list(args)

        if shell:
            args = ["/bin/sh", "-c"] + args
            if executable:
                args[0] = executable

        if executable is None:
            executable = args[0]
        orig_executable = executable

        # For transferring possible exec failure from child to parent.
        # Data format: "exception name:hex errno:description" 
        # Pickle is not used; it is complex and involves memory allocation.
        errpipe_read, errpipe_write = os.pipe()
        # errpipe_write must not be in the standard io 0, 1, or 2 fd range.
        low_fds_to_close = []
        while errpipe_write < 3:
            low_fds_to_close.append(errpipe_write)
            errpipe_write = os.dup(errpipe_write)
        for low_fd in low_fds_to_close:
            os.close(low_fd)
        try:
            try:
                # We must avoid complex work that could involve
                # malloc or free in the child process to avoid
                # potential deadlocks, thus we do all this here.
                # and pass it to fork_exec()

                if env is not None:
                    env_list = [os.fsencode(k) + b'=' + os.fsencode(v)
                                for k, v in env.items()]
                else:
                    env_list = None  # Use execv instead of execve.
                executable = os.fsencode(executable)
                if os.path.dirname(executable):
                    executable_list = (executable,)
                else:
                    # This matches the behavior of os._execvpe().
                    executable_list = tuple(
                        os.path.join(os.fsencode(dir), executable)
                        for dir in os.get_exec_path(env))
                fds_to_keep = set(pass_fds)
                fds_to_keep.add(errpipe_write)
                self.pid = _posixsubprocess.fork_exec(
                        args, executable_list,
                        close_fds, sorted(fds_to_keep), cwd, env_list,
                        p2cread, p2cwrite, c2pread, c2pwrite,
                        errread, errwrite,
                        errpipe_read, errpipe_write,
                        restore_signals, start_new_session, preexec_fn)
                self._child_created = True
            finally:
                # be sure the FD is closed no matter what
                os.close(errpipe_write)

            # self._devnull is not always defined.
            devnull_fd = getattr(self, '_devnull', None)
            if p2cread != -1 and p2cwrite != -1 and p2cread != devnull_fd:
                os.close(p2cread)
            if c2pwrite != -1 and c2pread != -1 and c2pwrite != devnull_fd:
                os.close(c2pwrite)
            if errwrite != -1 and errread != -1 and errwrite != devnull_fd:
                os.close(errwrite)
            if devnull_fd is not None:
                os.close(devnull_fd)
            # Prevent a double close of these fds from __init__ on error.
            self._closed_child_pipe_fds = True

            # Wait for exec to fail or succeed; possibly raising an
            # exception (limited in size)
            errpipe_data = bytearray()
            while True:
                part = os.read(errpipe_read, 50000)
                errpipe_data += part
                if not part or len(errpipe_data) > 50000:
                    break
        finally:
            # be sure the FD is closed no matter what
            os.close(errpipe_read)

        if errpipe_data:
            try:
                os.waitpid(self.pid, 0)
            except ChildProcessError:
                pass
            try:
                exception_name, hex_errno, err_msg = (
                        errpipe_data.split(b':', 2))
            except ValueError:
                exception_name = b'SubprocessError'
                hex_errno = b'0'
                err_msg = (b'Bad exception data from child: ' +
                           repr(errpipe_data))
            child_exception_type = getattr(
                    builtins, exception_name.decode('ascii'),
                    SubprocessError)
            err_msg = err_msg.decode(errors="surrogatepass")
            if issubclass(child_exception_type, OSError) and hex_errno:
                errno_num = int(hex_errno, 16)
                child_exec_never_called = (err_msg == "noexec")
                if child_exec_never_called:
                    err_msg = "" 
                if errno_num != 0:
                    err_msg = os.strerror(errno_num)
                    if errno_num == errno.ENOENT:
                        if child_exec_never_called:
                            # The error must be from chdir(cwd).
                            err_msg += ': ' + repr(cwd)
                        else:
                            err_msg += ': ' + repr(orig_executable)
>               raise child_exception_type(errno_num, err_msg)
E               FileNotFoundError: [Errno 2] No such file or directory: 'pvs'

/usr/lib/python3.5/subprocess.py:1551: FileNotFoundError
----------------------------- Captured stderr call -----------------------------
--> Executable pvs not in PATH: /home/jenkins-build/build/workspace/ceph-volume-pr/src/ceph-volume/.tox/py35/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
------------------------------ Captured log call -------------------------------
WARNING  ceph_volume.util.system:terminal.py:170 Executable pvs not in PATH: /home/jenkins-build/build/workspace/ceph-volume-pr/src/ceph-volume/.tox/py35/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
INFO     ceph_volume.process:process.py:191 Running command: pvs --noheadings --readonly --separator=";" -a -o lv_tags,lv_path,lv_name,vg_name,lv_uuid,lv_size /dev/nvme0n1
___________________ TestDevice.test_reject_bluestore_device ____________________

self = <test_device.TestDevice object at 0x7f5484cf1748>
monkeypatch = <_pytest.monkeypatch.MonkeyPatch object at 0x7f5484cf16d8>
patch_bluestore_label = <PropertyMock name='has_bluestore_label' id='140000982143048'>

    def test_reject_bluestore_device(self, monkeypatch, patch_bluestore_label):
        patch_bluestore_label.return_value = True
>       disk = device.Device("/dev/sda")

ceph_volume/tests/util/test_device.py:207: 
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 
ceph_volume/util/device.py:92: in __init__
    self._parse()
ceph_volume/util/device.py:134: in _parse
    lv = lvm.get_lv_from_argument(self.path)
ceph_volume/api/lvm.py:1324: in get_lv_from_argument
    lv = get_lv(lv_path=argument)
ceph_volume/api/lvm.py:1310: in get_lv
    lvs = Volumes()
ceph_volume/api/lvm.py:1034: in __init__
    self._populate()
ceph_volume/api/lvm.py:1038: in _populate
    for lv_item in get_api_lvs():
ceph_volume/api/lvm.py:898: in get_api_lvs
    verbose_on_failure=False
ceph_volume/process.py:201: in call
    **kw
/usr/lib/python3.5/subprocess.py:947: in __init__
    restore_signals, start_new_session)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <subprocess.Popen object at 0x7f5484cfa7f0>
args = ['lvs', '--noheadings', '--readonly', '--separator=";"', '-a', '-o', ...]
executable = b'lvs', preexec_fn = None, close_fds = True, pass_fds = ()
cwd = None, env = None, startupinfo = None, creationflags = 0, shell = False
p2cread = 15, p2cwrite = 16, c2pread = 17, c2pwrite = 18, errread = 19
errwrite = 20, restore_signals = True, start_new_session = False

    def _execute_child(self, args, executable, preexec_fn, close_fds,
                       pass_fds, cwd, env,
                       startupinfo, creationflags, shell,
                       p2cread, p2cwrite,
                       c2pread, c2pwrite,
                       errread, errwrite,
                       restore_signals, start_new_session):
        """Execute program (POSIX version)""" 

        if isinstance(args, (str, bytes)):
            args = [args]
        else:
            args = list(args)

        if shell:
            args = ["/bin/sh", "-c"] + args
            if executable:
                args[0] = executable

        if executable is None:
            executable = args[0]
        orig_executable = executable

        # For transferring possible exec failure from child to parent.
        # Data format: "exception name:hex errno:description" 
        # Pickle is not used; it is complex and involves memory allocation.
        errpipe_read, errpipe_write = os.pipe()
        # errpipe_write must not be in the standard io 0, 1, or 2 fd range.
        low_fds_to_close = []
        while errpipe_write < 3:
            low_fds_to_close.append(errpipe_write)
            errpipe_write = os.dup(errpipe_write)
        for low_fd in low_fds_to_close:
            os.close(low_fd)
        try:
            try:
                # We must avoid complex work that could involve
                # malloc or free in the child process to avoid
                # potential deadlocks, thus we do all this here.
                # and pass it to fork_exec()

                if env is not None:
                    env_list = [os.fsencode(k) + b'=' + os.fsencode(v)
                                for k, v in env.items()]
                else:
                    env_list = None  # Use execv instead of execve.
                executable = os.fsencode(executable)
                if os.path.dirname(executable):
                    executable_list = (executable,)
                else:
                    # This matches the behavior of os._execvpe().
                    executable_list = tuple(
                        os.path.join(os.fsencode(dir), executable)
                        for dir in os.get_exec_path(env))
                fds_to_keep = set(pass_fds)
                fds_to_keep.add(errpipe_write)
                self.pid = _posixsubprocess.fork_exec(
                        args, executable_list,
                        close_fds, sorted(fds_to_keep), cwd, env_list,
                        p2cread, p2cwrite, c2pread, c2pwrite,
                        errread, errwrite,
                        errpipe_read, errpipe_write,
                        restore_signals, start_new_session, preexec_fn)
                self._child_created = True
            finally:
                # be sure the FD is closed no matter what
                os.close(errpipe_write)

            # self._devnull is not always defined.
            devnull_fd = getattr(self, '_devnull', None)
            if p2cread != -1 and p2cwrite != -1 and p2cread != devnull_fd:
                os.close(p2cread)
            if c2pwrite != -1 and c2pread != -1 and c2pwrite != devnull_fd:
                os.close(c2pwrite)
            if errwrite != -1 and errread != -1 and errwrite != devnull_fd:
                os.close(errwrite)
            if devnull_fd is not None:
                os.close(devnull_fd)
            # Prevent a double close of these fds from __init__ on error.
            self._closed_child_pipe_fds = True

            # Wait for exec to fail or succeed; possibly raising an
            # exception (limited in size)
            errpipe_data = bytearray()
            while True:
                part = os.read(errpipe_read, 50000)
                errpipe_data += part
                if not part or len(errpipe_data) > 50000:
                    break
        finally:
            # be sure the FD is closed no matter what
            os.close(errpipe_read)

        if errpipe_data:
            try:
                os.waitpid(self.pid, 0)
            except ChildProcessError:
                pass
            try:
                exception_name, hex_errno, err_msg = (
                        errpipe_data.split(b':', 2))
            except ValueError:
                exception_name = b'SubprocessError'
                hex_errno = b'0'
                err_msg = (b'Bad exception data from child: ' +
                           repr(errpipe_data))
            child_exception_type = getattr(
                    builtins, exception_name.decode('ascii'),
                    SubprocessError)
            err_msg = err_msg.decode(errors="surrogatepass")
            if issubclass(child_exception_type, OSError) and hex_errno:
                errno_num = int(hex_errno, 16)
                child_exec_never_called = (err_msg == "noexec")
                if child_exec_never_called:
                    err_msg = "" 
                if errno_num != 0:
                    err_msg = os.strerror(errno_num)
                    if errno_num == errno.ENOENT:
                        if child_exec_never_called:
                            # The error must be from chdir(cwd).
                            err_msg += ': ' + repr(cwd)
                        else:
                            err_msg += ': ' + repr(orig_executable)
>               raise child_exception_type(errno_num, err_msg)
E               FileNotFoundError: [Errno 2] No such file or directory: 'lvs'

/usr/lib/python3.5/subprocess.py:1551: FileNotFoundError
----------------------------- Captured stderr call -----------------------------
--> Executable lvs not in PATH: /home/jenkins-build/build/workspace/ceph-volume-pr/src/ceph-volume/.tox/py35/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
------------------------------ Captured log call -------------------------------
INFO     ceph_volume.process:process.py:191 Running command: /bin/lsblk -plno KNAME,NAME,TYPE
INFO     ceph_volume.process:process.py:34 stdout /dev/sda  /dev/sda  disk
INFO     ceph_volume.process:process.py:34 stdout /dev/sda1 /dev/sda1 part
INFO     ceph_volume.process:process.py:34 stdout /dev/sr0  /dev/sr0  rom
WARNING  ceph_volume.util.system:terminal.py:170 Executable lvs not in PATH: /home/jenkins-build/build/workspace/ceph-volume-pr/src/ceph-volume/.tox/py35/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
INFO     ceph_volume.process:process.py:191 Running command: lvs --noheadings --readonly --separator=";" -a -o lv_tags,lv_path,lv_name,vg_name,lv_uuid,lv_size

No data to display

Actions

Also available in: Atom PDF