python Fabric是否支持动态设置env.hosts?

发布于 2025-01-07 20:09:23 字数 109 浏览 0 评论 0原文

我想动态更改 env.hosts,因为有时我想先部署到一台机器,检查是否正常,然后部署到多台机器。 目前我需要先设置 env.hosts,如何在方法中设置 env.hosts,而不是在脚本启动时全局设置?

I want to change the env.hosts dynamically because sometimes I want to deploy to one machine first, check if ok then deploy to many machines.
Currently I need to set env.hosts first, how could I set the env.hosts in a method and not in global at script start?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

终弃我 2025-01-14 20:09:23

是的,您可以动态设置env.hosts。我们使用的一种常见模式是:

from fabric.api import env

def staging():
    env.hosts = ['XXX.XXX.XXX.XXX', ]

def production():
    env.hosts = ['YYY.YYY.YYY.YYY', 'ZZZ.ZZZ.ZZZ.ZZZ', ]

def deploy():
   # Do something...

您可以使用它来链接诸如 fab staging 部署 或 fab production 部署 之类的任务。

Yes you can set env.hosts dynamically. One common pattern we use is:

from fabric.api import env

def staging():
    env.hosts = ['XXX.XXX.XXX.XXX', ]

def production():
    env.hosts = ['YYY.YYY.YYY.YYY', 'ZZZ.ZZZ.ZZZ.ZZZ', ]

def deploy():
   # Do something...

You would use this to chain the tasks such as fab staging deploy or fab production deploy.

橪书 2025-01-14 20:09:23

有点晚了,但我用 ec2 实现了这一点,就像这样(注意在 EC2 中你不知道 ip/主机名可能是什么,一般来说 - 所以你几乎必须动态地真正考虑环境/系统如何可能会出现 - 另一种选择是使用 dyndns,但这仍然有用):

from fabric.api import *
import datetime
import time
import urllib2
import ConfigParser
from platform_util import *

config = ConfigParser.RawConfigParser()

@task
def load_config(configfile=None):
    '''
    ***REQUIRED***  Pass in the configuration to use - usage load_config:</path/to/config.cfg>
    '''
    if configfile != None:
        # Load up our config file
        config.read(configfile)

        # Key/secret needed for aws interaction with boto 
        # (anyone help figure out a better way to do this with sub modules, please don't say classes :-) )
        global aws_key
        global aws_sec

        aws_key = config.get("main","aws_key")
        aws_sec = config.get("main","aws_sec")

         # Stuff for fabric
        env.user                = config.get("main","fabric_ssh_user")
        env.key_filename        = config.get("main","fabric_ssh_key_filename")
        env.parallel            = config.get("main","fabric_default_parallel")

        # Load our role definitions for fabric
        for i in config.sections():
            if i != "main":
                hostlist = []
                if config.get(i,"use-regex") == 'yes':
                    for x in get_running_instances_by_regex(aws_key,aws_sec,config.get(i,"security-group"),config.get(i,"pattern")):
                        hostlist.append(x.private_ip_address)   
                    env.roledefs[i] = hostlist

                else:
                    for x in get_running_instances(aws_key,aws_sec,config.get(i,"security-group")):
                        hostlist.append(x.private_ip_address)   
                    env.roledefs[i] = hostlist

                if config.has_option(i,"base-group"):
                    if config.get(i,"base-group") == 'yes':
                        print "%s is a base group" % i
                        print env.roledefs[i]
#                       env["basegroups"][i] = True

其中 get_running_instances 和 get_running_instances_by_regex 是利用 boto 的实用程序函数(http://code.google.com/p/boto/)

例如:

import logging
import re
from boto.ec2.connection import EC2Connection
from boto.ec2.securitygroup import SecurityGroup
from boto.ec2.instance import Instance
from boto.s3.key import Key

########################################
# B-O-F get_instances
########################################
def get_instances(access_key=None, secret_key=None, security_group=None):
    '''
    Get all instances. Only within a security group if specified., doesnt' matter their state (running/stopped/etc)
    '''
    logging.debug('get_instances()')
    conn = EC2Connection(aws_access_key_id=access_key, aws_secret_access_key=secret_key)

    if security_group:
        sg = SecurityGroup(connection=conn, name=security_group)
        instances = sg.instances()
        return instances
    else:
        instances = conn.get_all_instances()
        return instances

这是我的配置的示例:

# Config file for fabric toolset
#
#  This specific configuration is for <whatever> related hosts
#  
#
[main]
aws_key = <key>
aws_sec = <secret>
fabric_ssh_user = <your_user>
fabric_ssh_key_filename = /path/to/your/.ssh/<whatever>.pem
fabric_default_parallel = 1

#
# Groupings - Fabric knows them as roledefs (check env dict)
#

# Production groupings
[app-prod]
security-group = app-prod
use-regex = no
pattern = 

[db-prod]
security-group = db-prod
use-regex = no
pattern = 

[db-prod-masters]
security-group = db-prod
use-regex = yes
pattern = mysql-[d-s]01

Kind of late to the party, but I achieved this with ec2 like so (note in EC2 you do not know what the ip/hostname may be, generally speaking - so you almost have to go dynamic to really account for how the environment/systems could come up - another option would be to use dyndns, but then this would still be useful):

from fabric.api import *
import datetime
import time
import urllib2
import ConfigParser
from platform_util import *

config = ConfigParser.RawConfigParser()

@task
def load_config(configfile=None):
    '''
    ***REQUIRED***  Pass in the configuration to use - usage load_config:</path/to/config.cfg>
    '''
    if configfile != None:
        # Load up our config file
        config.read(configfile)

        # Key/secret needed for aws interaction with boto 
        # (anyone help figure out a better way to do this with sub modules, please don't say classes :-) )
        global aws_key
        global aws_sec

        aws_key = config.get("main","aws_key")
        aws_sec = config.get("main","aws_sec")

         # Stuff for fabric
        env.user                = config.get("main","fabric_ssh_user")
        env.key_filename        = config.get("main","fabric_ssh_key_filename")
        env.parallel            = config.get("main","fabric_default_parallel")

        # Load our role definitions for fabric
        for i in config.sections():
            if i != "main":
                hostlist = []
                if config.get(i,"use-regex") == 'yes':
                    for x in get_running_instances_by_regex(aws_key,aws_sec,config.get(i,"security-group"),config.get(i,"pattern")):
                        hostlist.append(x.private_ip_address)   
                    env.roledefs[i] = hostlist

                else:
                    for x in get_running_instances(aws_key,aws_sec,config.get(i,"security-group")):
                        hostlist.append(x.private_ip_address)   
                    env.roledefs[i] = hostlist

                if config.has_option(i,"base-group"):
                    if config.get(i,"base-group") == 'yes':
                        print "%s is a base group" % i
                        print env.roledefs[i]
#                       env["basegroups"][i] = True

where get_running_instances and get_running_instances_by_regex are utility functions that make use of boto (http://code.google.com/p/boto/)

ex:

import logging
import re
from boto.ec2.connection import EC2Connection
from boto.ec2.securitygroup import SecurityGroup
from boto.ec2.instance import Instance
from boto.s3.key import Key

########################################
# B-O-F get_instances
########################################
def get_instances(access_key=None, secret_key=None, security_group=None):
    '''
    Get all instances. Only within a security group if specified., doesnt' matter their state (running/stopped/etc)
    '''
    logging.debug('get_instances()')
    conn = EC2Connection(aws_access_key_id=access_key, aws_secret_access_key=secret_key)

    if security_group:
        sg = SecurityGroup(connection=conn, name=security_group)
        instances = sg.instances()
        return instances
    else:
        instances = conn.get_all_instances()
        return instances

Here is a sample of what my config looked like:

# Config file for fabric toolset
#
#  This specific configuration is for <whatever> related hosts
#  
#
[main]
aws_key = <key>
aws_sec = <secret>
fabric_ssh_user = <your_user>
fabric_ssh_key_filename = /path/to/your/.ssh/<whatever>.pem
fabric_default_parallel = 1

#
# Groupings - Fabric knows them as roledefs (check env dict)
#

# Production groupings
[app-prod]
security-group = app-prod
use-regex = no
pattern = 

[db-prod]
security-group = db-prod
use-regex = no
pattern = 

[db-prod-masters]
security-group = db-prod
use-regex = yes
pattern = mysql-[d-s]01
烟花肆意 2025-01-14 20:09:23

老问题的又一个新答案。 :) 但我最近发现自己试图动态设置主机,并且确实不同意主要答案。我的动态想法,或者至少是我试图做的,是获取一个刚刚由 boto 创建的实例 DNS 名称,并使用 fab 访问该实例命令。我无法进行 fab staging 部署 ,因为该实例在 fabfile 编辑时不存在 。

幸运的是,fabric 确实支持真正的动态主机分配 执行。 (当然,第一次提出问题时这可能不存在,但现在它存在了)。 执行允许您定义要调用的函数以及该命令应使用的env.hosts。例如:

def create_EC2_box(data=fab_base_data):
    conn = boto.ec2.connect_to_region(region)
    reservations = conn.run_instances(image_id=image_id, ...)
    ...
    return instance.public_dns_name

def _ping_box():
    run('uname -a')
    run('tail /var/log/cloud-init-output.log')

def build_box():
    box_name = create_EC2_box(fab_base_data)
    new_hosts = [box_name]
    # new_hosts = ['ec2-54-152-152-123.compute-1.amazonaws.com'] # testing
    execute(_ping_box, hosts=new_hosts)

现在我可以执行 fab build_box,它将触发一个用于创建实例的 boto 调用,以及另一个在其上运行的 fabric 调用新实例 - 无需在编辑时定义实例名称。

Yet another new answer to an old question. :) But I just recently found myself attempting to dynamically set hosts, and really have to disagree with the main answer. My idea of dynamic, or at least what I was attempting to do, was take an instance DNS-name that was just created by boto, and access that instance with a fab command. I couldn't do fab staging deploy, because the instance doesn't exist at fabfile-editing time.

Fortunately, fabric does support a truly dynamic host-assignment with execute. (It's possible this didn't exist when the question was first asked, of course, but now it does). Execute allows you to define both a function to be called, and the env.hosts it should use for that command. For example:

def create_EC2_box(data=fab_base_data):
    conn = boto.ec2.connect_to_region(region)
    reservations = conn.run_instances(image_id=image_id, ...)
    ...
    return instance.public_dns_name

def _ping_box():
    run('uname -a')
    run('tail /var/log/cloud-init-output.log')

def build_box():
    box_name = create_EC2_box(fab_base_data)
    new_hosts = [box_name]
    # new_hosts = ['ec2-54-152-152-123.compute-1.amazonaws.com'] # testing
    execute(_ping_box, hosts=new_hosts)

Now I can do fab build_box, and it will fire one boto call that creates an instance, and another fabric call that runs on the new instance - without having to define the instance-name at edit-time.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文