[TIP] problem running fabric commands with py.test

Hans Sebastian hnsbstn at gmail.com
Tue Dec 6 17:55:27 PST 2011


Hi all,

I am trying to execute a remote command using fabric in my test run by
py.test. Fabric is a library for using SSH and I myself is quite new to it
and just want to start using it. The problem is when i run it with py.test
I am getting an error, but not when invoking with python. Does anyone
understand what the issue is and how to mitigate it? Below is the output.

Thank you very much.
-hans


(env26)[hsebastian at puri integration]$  py.test test_magic.py
===========================================================================================
test session starts
===========================================================================================
platform darwin -- Python 2.6.1 -- pytest-2.1.1
collected 1 items

test_magic.py F

================================================================================================
FAILURES
=================================================================================================
__________________________________________________________________________________________
TestMagic.test_magic
___________________________________________________________________________________________

self = <test_magic.TestMagic object at 0x10124a8d0>

    def test_magic(self):
        env.key_filename = os.path.join('test.pem')
        env.user = 'ubuntu'
        env.host_string = 'ec2-50-56-84-105.compute-1.amazonaws.com'
>       output = run('ls -al')

test_magic.py:13:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

    @wraps(func)
    def host_prompting_wrapper(*args, **kwargs):
        while not env.get('host_string', False):
            handle_prompt_abort()
            host_string = raw_input("No hosts found. Please specify
(single)"
                                    " host string for connection: ")
            interpret_host_string(host_string)
>       return func(*args, **kwargs)

../../../env26/lib/python2.6/site-packages/fabric/network.py:331:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

command = 'ls -al', shell = True, pty = True, combine_stderr = None

    @needs_host
    def run(command, shell=True, pty=True, combine_stderr=None):
        """
        Run a shell command on a remote host.

        If ``shell`` is True (the default), `run` will execute the given
command
        string via a shell interpreter, the value of which may be
controlled by
        setting ``env.shell`` (defaulting to something similar to
``/bin/bash -l -c
        "<command>"``.) Any double-quote (``"``) or dollar-sign (``$``)
characters
        in ``command`` will be automatically escaped when ``shell`` is True.

        `run` will return the result of the remote program's stdout as a
single
        (likely multiline) string. This string will exhibit ``failed`` and
        ``succeeded`` boolean attributes specifying whether the command
failed or
        succeeded, and will also include the return code as the
``return_code``
        attribute.

        Any text entered in your local terminal will be forwarded to the
remote
        program as it runs, thus allowing you to interact with password or
other
        prompts naturally. For more on how this works, see
        :doc:`/usage/interactivity`.

        You may pass ``pty=False`` to forego creation of a pseudo-terminal
on the
        remote end in case the presence of one causes problems for the
command in
        question. However, this will force Fabric itself to echo any  and
all input
        you type while the command is running, including sensitive
passwords. (With
        ``pty=True``, the remote pseudo-terminal will echo for you, and will
        intelligently handle password-style prompts.) See :ref:`pseudottys`
for
        details.

        Similarly, if you need to programmatically examine the stderr
stream of the
        remote program (exhibited as the ``stderr`` attribute on this
function's
        return value), you may set ``combine_stderr=False``. Doing so has a
high
        chance of causing garbled output to appear on your terminal (though
the
        resulting strings returned by `~fabric.operations.run` will be
properly
        separated). For more info, please read :ref:`combine_streams`.

        Examples::

            run("ls /var/www/")
            run("ls /home/myuser", shell=False)
            output = run('ls /var/www/site1')

        .. versionadded:: 1.0
            The ``succeeded`` and ``stderr`` return value attributes, the
            ``combine_stderr`` kwarg, and interactive behavior.

        .. versionchanged:: 1.0
            The default value of ``pty`` is now ``True``.

        .. versionchanged:: 1.0.2
            The default value of ``combine_stderr`` is now ``None`` instead
of
            ``True``. However, the default *behavior* is unchanged, as the
global
            setting is still ``True``.
        """
>       return _run_command(command, shell, pty, combine_stderr)


    @needs_host
    def sudo(command, shell=True, pty=True, combine_stderr=None, user=None):

../../../env26/lib/python2.6/site-packages/fabric/operations.py:945:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

command = 'ls -al', shell = True, pty = True, combine_stderr = None, sudo =
False, user = None

    def _run_command(command, shell=True, pty=True, combine_stderr=True,
        sudo=False, user=None):
        """
        Underpinnings of `run` and `sudo`. See their docstrings for more
info.
        """
        # Set up new var so original argument can be displayed verbatim
later.
        given_command = command
        # Handle context manager modifications, and shell wrapping
        wrapped_command = _shell_wrap(
            _prefix_commands(_prefix_env_vars(command), 'remote'),
            shell,
            _sudo_prefix(user) if sudo else None
        )
        # Execute info line
        which = 'sudo' if sudo else 'run'
        if output.debug:
            print("[%s] %s: %s" % (env.host_string, which, wrapped_command))
        elif output.running:
            print("[%s] %s: %s" % (env.host_string, which, given_command))

        # Actual execution, stdin/stdout/stderr handling, and termination
        stdout, stderr, status = _execute(default_channel(),
wrapped_command, pty,
>           combine_stderr)

../../../env26/lib/python2.6/site-packages/fabric/operations.py:864:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

    def wrapper(*args, **kwargs):
        try:
>           callable(*args, **kwargs)

../../../env26/lib/python2.6/site-packages/fabric/thread_handling.py:12:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

chan = <paramiko.Channel 1 (closed) -> <paramiko.Transport at 0x124a810L
(cipher aes128-ctr, 128 bits) (active; 0 open channel(s))>>, using_pty =
True

    def input_loop(chan, using_pty):
        while not chan.exit_status_ready():
            if win32:
                have_char = msvcrt.kbhit()
            else:
>               r, w, x = select([sys.stdin], [], [], 0.0)

../../../env26/lib/python2.6/site-packages/fabric/io.py:120:
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _

self = <py._io.capture.DontReadFromInput instance at 0x10124e908>

    def fileno(self):
>       raise ValueError("redirected Stdin is pseudofile, has no fileno()")
E       ValueError: redirected Stdin is pseudofile, has no fileno()

../../../env26/lib/python2.6/site-packages/py/_io/capture.py:346: ValueError
---------------------------------------------------------------------------------------------
Captured stdout
---------------------------------------------------------------------------------------------
[ec2-50-56-84-105.compute-1.amazonaws.com] run: ls -al
[ec2-50-56-84-105.compute-1.amazonaws.com] out: total 40
[ec2-50-56-84-105.compute-1.amazonaws.com] out: drwxr-xr-x 5 ubuntu ubuntu
4096 2011-12-07 00:38 .
[ec2-50-56-84-105.compute-1.amazonaws.com] out: drwxr-xr-x 3 root   root
4096 2011-02-01 22:08 ..
[ec2-50-56-84-105.compute-1.amazonaws.com] out: -rw------- 1 ubuntu
ubuntu   37 2011-12-07 00:38 .bash_history
[ec2-50-56-84-105.compute-1.amazonaws.com] out: -rw-r--r-- 1 ubuntu ubuntu
220 2011-02-01 22:08 .bash_logout
[ec2-50-56-84-105.compute-1.amazonaws.com] out: -rw-r--r-- 1 ubuntu ubuntu
3103 2011-02-01 22:08 .bashrc
[ec2-50-56-84-105.compute-1.amazonaws.com] out: drwx------ 2 ubuntu ubuntu
4096 2011-09-29 20:51 .cache
[ec2-50-56-84-105.compute-1.amazonaws.com] out: -rw-r--r-- 1 ubuntu ubuntu
========================================================================================
1 failed in 1.65 seconds
=========================================================================================
(env26)[hsebastian at puri integration]$  cat test_magic.py
from fabric.api import run, env
import os
import logging


logging.basicConfig(filename='magic.log')

class TestMagic(object):
    def test_magic(self):
        env.key_filename = os.path.join('test.pem')
        env.user = 'ubuntu'
        env.host_string =
'ec2-50-56-84-105.compute-1.amazonaws.com<http://ec2-50-16-84-105.compute-1.amazonaws.com>
'
        output = run('ls -al')
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.idyll.org/pipermail/testing-in-python/attachments/20111206/7fd6d5a3/attachment.htm>


More information about the testing-in-python mailing list