代码之家  ›  专栏  ›  技术社区  ›  ssc

如何在Fabric文件中设置目标主机

  •  107
  • ssc  · 技术社区  · 15 年前

    def deploy_2_dev():
      deploy('dev')
    
    def deploy_2_staging():
      deploy('staging')
    
    def deploy_2_prod():
      deploy('prod')
    
    def deploy(server):
      print 'env.hosts:', env.hosts
      env.hosts = [server]
      print 'env.hosts:', env.hosts
    

    样本输出:

    host:folder user$ fab deploy_2_dev
    env.hosts: []
    env.hosts: ['dev']
    No hosts found. Please specify (single) host string for connection:
    

    当我创建一个 set_hosts() 如中所示的任务 Fabric docs ,env.hosts设置正确。然而,这不是一个可行的选择,也不是一个装饰。在命令行上传递主机最终会产生某种shell脚本来调用fabfile,我更希望只有一个工具能够正确地完成这项工作。

    它在Fabric文档中说“env.hosts只是一个Python列表对象”。从我的观察来看,这根本不是真的。

    有人能解释一下这是怎么回事吗?如何设置要部署到的主机?

    15 回复  |  直到 15 年前
        1
  •  128
  •   Zac    14 年前

    为此,我为每个环境声明一个实际函数。例如:

    def test():
        env.user = 'testuser'
        env.hosts = ['test.server.com']
    
    def prod():
        env.user = 'produser'
        env.hosts = ['prod.server.com']
    
    def deploy():
        ...
    

    fab test deploy
    

    …以及要部署到生产中的以下各项:

    fab prod deploy
    

    这样做的好处是 test prod 函数可以在 任何 工厂功能,而不仅仅是部署。它非常有用。

        2
  •  77
  •   thomie    14 年前

    使用 roledefs

    from fabric.api import env, run
    
    env.roledefs = {
        'test': ['localhost'],
        'dev': ['user@dev.example.com'],
        'staging': ['user@staging.example.com'],
        'production': ['user@production.example.com']
    } 
    
    def deploy():
        run('echo test')
    

    $ fab -R test deploy
    [localhost] Executing task 'deploy'
    ...
    
        3
  •  49
  •   tobych    5 年前

    serverhorror's answer :

    from fabric.api import settings
    
    def mystuff():
        with settings(host_string='192.0.2.78'):
            run("hostname -f")
    
        4
  •  21
  •   GoldenBoy    15 年前

    不能 在内部 一项任务。每个任务执行N次,每个指定的主机执行一次,因此设置基本上不在任务范围内。

    查看上面的代码,您可以简单地执行以下操作:

    @hosts('dev')
    def deploy_dev():
        deploy()
    
    @hosts('staging')
    def deploy_staging():
        deploy()
    
    def deploy():
        # do stuff...
    

    它似乎能达到你的目的。

        5
  •  18
  •   j-a    10 年前

    由于fab1.5,这是一种动态设置主机的方法。

    http://docs.fabfile.org/en/1.7/usage/execution.html#dynamic-hosts

    使用execute动态设置主机列表

    在运行时参数化查找目标主机列表(当使用 角色不够)。execute可以使这变得非常简单,比如 所以:

    from fabric.api import run, execute, task
    
    # For example, code talking to an HTTP API, or a database, or ...
    from mylib import external_datastore
    
    # This is the actual algorithm involved. It does not care about host
    # lists at all.
    def do_work():
        run("something interesting on a host")
    
    # This is the user-facing task invoked on the command line.
    @task
    def deploy(lookup_param):
        # This is the magic you don't get with @hosts or @roles.
        # Even lazy-loading roles require you to declare available roles
        # beforehand. Here, the sky is the limit.
        host_list = external_datastore.query(lookup_param)
        # Put this dynamically generated host list together with the work to be
        # done.
        execute(do_work, hosts=host_list)
    
        6
  •  10
  •   pztrick    12 年前

    与其他一些答案相反,它 可以修改 env 环境 将仅用于使用 fabric.tasks.execute

    from fabric.api import task, roles, run, env
    from fabric.tasks import execute
    
    # Not a task, plain old Python to dynamically retrieve list of hosts
    def get_stressors():
        hosts = []
        # logic ...
        return hosts
    
    @task
    def stress_test():
        # 1) Dynamically generate hosts/roles
        stressors = get_stressors()
        env.roledefs['stressors'] = map(lambda x: x.public_ip, stressors)
    
        # 2) Wrap sub-tasks you want to execute on new env in execute(...)
        execute(stress)
    
        # 3) Note that sub-tasks not nested in execute(...) will use original env
        clean_up()
    
    @roles('stressors')
    def stress():
        # this function will see any changes to env, as it was wrapped in execute(..)
        run('echo "Running stress test..."')
        # ...
    
    @task
    def clean_up():
        # this task will NOT see any dynamic changes to env
    

    不将子任务包装到 execute(...) ,您的模块级别 环境 设置或从 fab 将使用CLI。

        7
  •  9
  •   Martin M.    15 年前

    你需要设置 host_string 例如:

    from fabric.context_managers import settings as _settings
    
    def _get_hardware_node(virtualized):
        return "localhost"
    
    def mystuff(virtualized):
        real_host = _get_hardware_node(virtualized)
        with _settings(
            host_string=real_host):
            run("echo I run on the host %s :: `hostname -f`" % (real_host, ))
    
        8
  •  9
  •   Morgan    14 年前

    绝妙的 正在利用库运行主机列表上的任务。如果您尝试更改任务中的主机列表,则在迭代时本质上是在尝试更改列表。或者,在没有定义主机的情况下,循环一个空列表,在这个空列表中,将列表设置为循环的代码从未执行过。

    fab production deploy
    

    fab staging deploy
    

    其中,暂存和生产类似于您给定的任务,但它们本身并不调用下一个任务。它必须这样工作的原因是,任务必须完成并跳出循环(主机的循环,在env的情况下为None,但此时为一个循环),然后在主机上重新进行循环(现在由前面的任务定义)。

        9
  •  3
  •   mlbright    14 年前

    from fabric.api import *
    
    def _get_hosts():
        hosts = []
        ... populate 'hosts' list ...
        return hosts
    
    env.hosts = _get_hosts()
    
    def your_task():
        ... your task ...
    
        10
  •  3
  •   Vladimir Osintsev    13 年前

    很简单。只需初始化env.host\u字符串变量,以下所有命令都将在此主机上执行。

    from fabric.api import env, run
    
    env.host_string = 'user@exmaple.com'
    
    def foo:
        run("hostname -f")
    
        11
  •  3
  •   Brad Parks    11 年前

    我对fabric完全陌生,但是要让fabric在多个主机上运行相同的命令(例如,在一个命令中部署到多个服务器),您可以运行:

    fab -H staging-server,production-server deploy 
    

    哪里 暂存服务器 生产服务器 是要对其运行部署操作的2台服务器。下面是一个简单的fabfile.py,它将显示OS名称。请注意,fabfile.py应该位于运行fab命令的目录中。

    from fabric.api import *
    
    def deploy():
        run('uname -s')
    

    这至少适用于fabric 1.8.1。

        12
  •  3
  •   athros    11 年前

    因此,要设置主机并使命令在所有主机上运行,必须从以下几点开始:

    def PROD():
        env.hosts = ['10.0.0.1', '10.0.0.2']
    
    def deploy(version='0.0'):
        sudo('deploy %s' % version)
    

    fab PROD deploy:1.5
    

    什么将在PROD函数中列出的所有服务器上运行部署任务,因为它在运行任务之前设置了env.hosts。

        13
  •  2
  •   Andrew B.    15 年前

    您可以分配给 env.hoststring 在执行子任务之前。如果要在多个主机上迭代,请在循环中分配给此全局变量。

    不幸的是,对于你和我来说,织物并不是为这个用例设计的。查看 main 作用于 http://github.com/bitprophet/fabric/blob/master/fabric/main.py 看看它是怎么工作的。

        14
  •  2
  •   Community CDub    8 年前

    下面是另一个“summersault”模式,它支持 fab my_env_1 my_command 用法:

    使用这种模式,我们只需使用字典定义一次环境。 env_factory 基于的键名创建函数 ENVS . 我把 环境 secrets.config.py

    缺点是,如前所述,添加 @task 装饰工威尔 break it

    注:我们使用 def func(k=k): def func(): 在工厂里因为 late binding . 我们得到了正在运行的模块 this solution

    机密.config.py

    ENVS = {
        'my_env_1': {
            'HOSTS': [
                'host_1',
                'host_2',
            ],
            'MY_OTHER_SETTING': 'value_1',
        },
        'my_env_2': {
            'HOSTS': ['host_3'],
            'MY_OTHER_SETTING': 'value_2'
        }
    }
    

    import sys
    from fabric.api import env
    from secrets import config
    
    
    def _set_env(env_name):
        # can easily customize for various use cases
        selected_config = config.ENVS[env_name]
        for k, v in selected_config.items():
            setattr(env, k, v)
    
    
    def _env_factory(env_dict):
        for k in env_dict:
            def func(k=k):
                _set_env(k)
            setattr(sys.modules[__name__], k, func)
    
    
    _env_factory(config.ENVS)
    
    def my_command():
        # do work
    
        15
  •  0
  •   user1180527    13 年前

    使用角色目前被认为是“正确”和“正确”的方法,也是你“应该”做的。

    也就是说,如果你像大多数人一样,你“想要”或“渴望”的是执行“扭曲系统”或在飞行中切换目标系统的能力。

    所以仅用于娱乐目的(!)下面的例子说明了许多人可能会认为是一种冒险的,但却完全令人满意的策略,它是这样的:

    env.remote_hosts       = env.hosts = ['10.0.1.6']
    env.remote_user        = env.user = 'bob'
    env.remote_password    = env.password = 'password1'
    env.remote_host_string = env.host_string
    
    env.local_hosts        = ['127.0.0.1']
    env.local_user         = 'mark'
    env.local_password     = 'password2'
    
    def perform_sumersault():
        env_local_host_string = env.host_string = env.local_user + '@' + env.local_hosts[0]
        env.password = env.local_password
        run("hostname -f")
        env.host_string = env.remote_host_string
        env.remote_password = env.password
        run("hostname -f")
    

    然后运行:

    fab perform_sumersault