V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
推荐学习书目
Learn Python the Hard Way
Python Sites
PyPI - Python Package Index
http://diveintopython.org/toc/index.html
Pocoo
值得关注的项目
PyPy
Celery
Jinja2
Read the Docs
gevent
pyenv
virtualenv
Stackless Python
Beautiful Soup
结巴中文分词
Green Unicorn
Sentry
Shovel
Pyflakes
pytest
Python 编程
pep8 Checker
Styles
PEP 8
Google Python Style Guide
Code Style from The Hitchhiker's Guide
firejoke
V2EX  ›  Python

最近总在用 fabric,踩了一些坑, 分享一个实用函数

  •  
  •   firejoke · 2019-04-30 18:27:28 +08:00 · 2014 次点击
    这是一个创建于 1820 天前的主题,其中的信息可能已经有所发展或是发生改变。

    最近一直在做的一个东西, 很多地方需要用到 shell 命令,
    同样的命令既要在本地运行, 也要放到远程,并获取远程的输出结果
    如果每个地方都要判断是在本地还是远程然后再去分别实例不同的对象,
    所以写了一个函数, 尽量减少一下重复代码

    def cmd_method(host, port=22, user=None, pwd=None):
        """
        执行远程或本地命令
        r = r"(?i)y\|n|\[y/d/n\]|\[y/n\]|y/n"
        watcher = Responder(pattern=r, response='y\n')
        Responder 对象可以通过正则匹配对 stdout 做分析, 如果匹配到了,就向 stdin 写入 response
        完成命令的反复交互
        :param host: 主机 ip, 本地可以用 'localhost' or '127.0.0.1'
        :param port: ssh 的端口
        :param user: 登陆远程主机的用户
        :param pwd: 远程登陆的密码
        :return: 正常输出和错误输出: (stdout, stderr)
        """
    
        from fabric import Connection
        from invoke import run, Responder
        from paramiko import AuthenticationException
        from paramiko.ssh_exception import NoValidConnectionsError, SSHException
    
        def local(command, interactive):
            watcher = Responder(
                    pattern=interactive['pattern'],
                    response=interactive['response']) if interactive else None
            res = run(command, watchers=[watcher], warn=True, hide=True)
            res = res.stdout.encode('utf8'), res.stderr.encode('utf8')
            return res
    
        def remote(command, interactive):
            if not ip_check(host):
                return 'host ip error'
            with Connection(host=host, port=port, user=user,
                            connect_kwargs={'password': pwd},
                            connect_timeout=10) as c:
                watcher = Responder(
                        pattern=interactive['pattern'],
                        response=interactive['response']) if interactive else []
                res = c.run(command, watchers=[watcher], warn=True, hide=True)
                res = res.stdout.encode('utf8'), res.stderr.encode('utf8')
                return res
        if host and host in ('localhost' or '127.0.0.1'):
            return local
        elif host and port and user and pwd:
            with Connection(host=host, port=port, user=user,
                            connect_kwargs={'password': pwd},
                            connect_timeout=10) as c:
                try:
                    # 测试参数可用
                    c.run('hostname', hide=True)
                except (AuthenticationException, NoValidConnectionsError,
                        SSHException) as e:
                    return e.__str__()
            return remote
        else:
            return 'args error'
    

    因为 fabric 的 Connection 的 run 方法也是继承自 invoke, 所以参数作用基本都是一样的
    我最常用的是 warn 和 hide 还有 watchers
    warn 默认为 False, 默认情况下会因为 shell 命令的错误输出而抛错, 也就是直接抛出 stderr
    如果设为 True, 就会将 shell 命令的错误输出写到 Result 对象的 stderr 内

    hide 也是默认为 False, 默认情况下将远程的输出信息在当前命令行输出, 为 True 时, 则不会, 但不论是什么, 都不会影响 Result 对象的 stdout 和 stderr 结果, 还可以只隐藏 stdout 或 stderr

    watchers 参数, 传入的是一个包含诺干 Responder 实例的列表
    当需要运行交互式的命令时, 可以用 Responder 对象来匹配输出, 并写入输入, 做自动化部署时很实用

    还有一个 pty 参数, 这个参数, 默认是设为 True, 找文档时候发现很多人都是设为 True, 但在我踩过很多坑后,
    我发现当设为 True 时, 有时标准输出(stdout)和错误输出(stderr)会混乱, 不方便后面的逻辑判断, 所以最好别动

    还有 out_stream 和 err_stream, 可以将输出导到一个 write 模式打开的类 file 对象, 方便做记录

    第 1 条附言  ·  2020-02-25 16:52:51 +08:00

    回看帖子, 发现一个低级bug...

    if host and host in ('localhost' or '127.0.0.1'):
    

    应该是:

    if host and host in ('localhost', '127.0.0.1'):
    
    目前尚无回复
    关于   ·   帮助文档   ·   博客   ·   API   ·   FAQ   ·   我们的愿景   ·   实用小工具   ·   1074 人在线   最高记录 6543   ·     Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 · 24ms · UTC 19:00 · PVG 03:00 · LAX 12:00 · JFK 15:00
    Developed with CodeLauncher
    ♥ Do have faith in what you're doing.