Fabric:为每个任务传递不同的参数?

时间:2017-06-26 14:40:36

标签: python fabric

我有以下CSV:

ip, arg1, arg2
1.2.3.4, foo, bar
1.3.4.5, baz, bub

我正在尝试执行:

  1. 对于CSV中的每一行:ssh进入ip specificed,
  2. 使用arg1为该行执行apt-get等命令
  3. 执行将对该行使用arg2的自定义命令
  4. Fabric有execute(do_work, hosts=host_list)但我无法为此指定正确的上下文。到目前为止,我已经在一起攻击了一些东西:

    from fabric.api import env, execute
    
    arguments = {}
    
    
    def _deploy():
      print env.host_string, arguments[env.host_string]
    
    
    def deploy():
      global arguments
      arguments['1.2.3.4'] = ('foo', 'bar')
      arguments['2.3.4.5'] = ('baz', 'bub')
      execute(_deploy, hosts=arguments.keys())
    

    打印出来:

    [1.2.3.4] Executing task '_deploy'
    1.2.3.4 ('foo', 'bar')
    [2.3.4.5] Executing task '_deploy'
    2.3.4.5 ('baz', 'bub')
    

    目前,这并没有破坏任何东西。有没有更好的方法,甚至更好的lib我这样做?

    注意:我不是paramiko的粉丝,因为它太低了。

2 个答案:

答案 0 :(得分:0)

这是织物中不时出现的边缘情况。我可以向您展示我过去使用的策略,但我会从更安全的策略变化开始。

env词典旨在存储可供其他任务使用的环境数据。任何应该在任务之间共享但不能作为参数传递的数据都可以在这里,所以我将更改你的代码以保持env中的参数:

from fabric.api import env, execute, task

def _deploy():
    print env.host_string, env.arguments[env.host_string]

@task
def deploy():
    env.arguments = {}
    env.arguments['1.2.3.4'] = ('foo', 'bar')
    env.arguments['2.3.4.5'] = ('baz', 'bub')
    execute(_deploy, hosts=env.arguments.keys())

第二个策略是我过去用来执行这样的工作的策略,它涉及将所有参数作为主机字符串的一部分传递,并让任务负责将其解析为可用数据。它使您无法在全球范围内传递大型字典,并且您的用例可能会有效:

hosts.csv

1.2.3.4, foo, bar
1.3.4.5, baz, bub
1.4.5.6, complex-args, maybe with spaces

fabfile.py

from fabric.api import env, execute, run, settings, task

def _parse_args(argument_string):
    # you should really use the csv module here to split properly (escapes, etc)
    args = argument_string.split(', ')
    if len(args) != 3:
        raise ValueError("Only the host and 2 arguments are allowed")
    return args

def _deploy():
    host, arg1, arg2 = _parse_args(env.host_string)
    with settings(host_string=host):
        # run("apt-get '{}'".format(arg1))
        # run("service '{}' restart".format(arg2)
        print "[{}] apt-get '{}'".format(env.host_string, arg1)
        print "[{}] service '{}' restart".format(env.host_string, arg2)

@task
def deploy():
    with open('hosts.csv') as f:
        hosts = [ line.strip() for line in f ]
    execute(_deploy, hosts=hosts)

以下是您使用此策略看到的输出:

$ fab deploy
[1.2.3.4, foo, bar] Executing task '_deploy'
[1.2.3.4] apt-get 'foo'
[1.2.3.4] service 'bar' restart
[1.3.4.5, baz, bub] Executing task '_deploy'
[1.3.4.5] apt-get 'baz'
[1.3.4.5] service 'bub' restart
[1.4.5.6, complex-args, maybe with spaces] Executing task '_deploy'
[1.4.5.6] apt-get 'complex-args'
[1.4.5.6] service 'maybe with spaces' restart

Done.

答案 1 :(得分:0)

不优雅本身,但这是我解决的解决方案:

def special_echo(matrix):
  key = 'ubuntu@' + env.host
  name = matrix[key]
  run('echo %s `hostname --ip-address`' % name)

A = {}
A['ubuntu@54.219.171.62'] = 'first'
A['ubuntu@52.53.149.140'] = 'second'
A['ubuntu@54.183.255.58'] = 'third'

execute(special_echo, A, hosts=A.keys())

结果:

[ubuntu@54.219.171.62] Executing task 'special_echo'
[ubuntu@54.219.171.62] run: echo first `hostname --ip-address`
[ubuntu@54.219.171.62] out: first 172.31.1.234
[ubuntu@54.219.171.62] out:

[ubuntu@54.183.255.58] Executing task 'special_echo'
[ubuntu@54.183.255.58] run: echo third `hostname --ip-address`
[ubuntu@54.183.255.58] out: third 172.31.15.36
[ubuntu@54.183.255.58] out:

[ubuntu@52.53.149.140] Executing task 'special_echo'
[ubuntu@52.53.149.140] run: echo second `hostname --ip-address`
[ubuntu@52.53.149.140] out: second 172.31.8.138
[ubuntu@52.53.149.140] out: