织物设置问题()

Issue with Fabric settings()

运行 最新版本的 Fabric (1.11.1) (Paramiko (1.16.0), Python (2.7.11)) 我得到了最奇怪的错误,我做了一点尝试一下的概念证明。

from fabric.api import run, sudo, task
from fabric.context_managers import settings


@task
def test():
    print('regular run')
    run('whoami')

    print('regular sudo')
    sudo('whoami')

    print('sudo with user arg')
    sudo('whoami', user='www-data')

    with settings(user='www-data'):
        print('run inside settings')
        run('whoami')

输出:

$ fab -f test.py -H vagrant@127.0.0.1:2222 test
[vagrant@127.0.0.1:2222] Executing task 'test'
regular run
[vagrant@127.0.0.1:2222] run: whoami
[vagrant@127.0.0.1:2222] out: vagrant        # <--- good
[vagrant@127.0.0.1:2222] out: 

regular sudo
[vagrant@127.0.0.1:2222] sudo: whoami
[vagrant@127.0.0.1:2222] out: root           # <--- good
[vagrant@127.0.0.1:2222] out: 

sudo with user arg
[vagrant@127.0.0.1:2222] sudo: whoami
[vagrant@127.0.0.1:2222] out: www-data       # <--- good
[vagrant@127.0.0.1:2222] out: 

run inside settings
[vagrant@127.0.0.1:2222] run: whoami
[vagrant@127.0.0.1:2222] out: vagrant        # <--- WHAT THE HECK!? this used to work
[vagrant@127.0.0.1:2222] out: 


Done.

有什么变化吗?或者我只是做错了什么?

另一个 Fabric 问题,事实证明,如果您做一些可爱的事情,例如:-H vagrant@127.0.0.1:2222 在内部它不会将其分解为您所期望的:env.user = 'vagrant'; env.host = '127.0.0.1'; env.port = '2222' 但它只是将其保留在 host_string所以...呃,这是世界上最丑陋的黑客:

from fabric.api import run, sudo, task, env
from fabric.context_managers import settings as _settings


def settings(*args, **kwargs):
    """
    Helper function because Fabric's setting() is broken

    Checks to see if there is a '@' in the host_string and if there is, it 
    will then append it to the host_string since that will be how it changes 
    users. Otherwise if the host_string is not being used, it will use the 
    default "swap user" functionality
    """
    if 'user' in kwargs and '@' in env.host_string:
        kwargs['host_string'] = '{}@{}'.format(
            kwargs.pop('user'),
            env.host_string.split('@')[1]
        )
    return _settings(*args, **kwargs)


@task
def test():
    print('regular run')
    run('whoami')
    print('regular sudo')
    sudo('whoami')

    print('sudo with user arg')
    sudo('whoami', user='www-data')
    with settings(user='www-data'):
        print('run inside settings')
        run('whoami')

这有助于保持代码的公平性 "clean" 并且不会到处都是一堆 with settings(host_string='www-data@' + env.host_string.split('@')[1]):,如果你定义 fabric 命令时才意识到它们会中断:fab .. --user=vagrant --host=127.0.0.1 --port=2222.此解决方案适用于以下内容:

fab -f test.py --user=vagrant --host=127.0.0.1 --port=2222 test

fab -f test.py -H vagrant@127.0.0.1:2222 test


旧解

from fabric.api import run, sudo, task, env
from fabric.context_managers import settings


@task
def test():
    print('regular run')
    run('whoami')
    print('regular sudo')
    sudo('whoami')

    print('sudo with user arg')
    sudo('whoami', user='www-data')
    with settings(host_string='www-data@' + env.host_string.split('@')[1]):
        print('run inside settings')
        run('whoami')

输出:

$ fab -f test.py -H vagrant@127.0.0.1:2222 test
[vagrant@127.0.0.1:2222] Executing task 'test'
regular run
[vagrant@127.0.0.1:2222] run: whoami
[vagrant@127.0.0.1:2222] out: vagrant        # <--- good
[vagrant@127.0.0.1:2222] out: 

regular sudo
[vagrant@127.0.0.1:2222] sudo: whoami
[vagrant@127.0.0.1:2222] out: root           # <--- good
[vagrant@127.0.0.1:2222] out: 

sudo with user arg
[vagrant@127.0.0.1:2222] sudo: whoami
[vagrant@127.0.0.1:2222] out: www-data       # <--- good
[vagrant@127.0.0.1:2222] out: 

run inside settings
[vagrant@127.0.0.1:2222] run: whoami
[vagrant@127.0.0.1:2222] out: www-data       # <--- good
[vagrant@127.0.0.1:2222] out: 


Done.

如果有人知道解决这个问题的好方法,请告诉我,我洗耳恭听!