[英]Does python fabric support dynamic set 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. 我想动态更改env.hosts,因为有时我想首先部署到一台机器,检查是否可以然后部署到许多机器。 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?
目前我需要首先设置env.hosts,如何在一个方法中设置env.hosts而不在脚本启动时设置为global?
Yes you can set env.hosts
dynamically. 是的,您可以动态设置
env.hosts
。 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
. 您可以使用它来链接诸如
fab staging deploy
或fab production deploy
类的任务。
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): 有点迟到了,但是我用ec2这样做了(注意在EC2你不知道ip / hostname可能是什么,一般来说 - 所以你几乎要动态去真正考虑环境/系统如何可能会出现 - 另一种选择是使用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
where get_running_instances and get_running_instances_by_regex are utility functions that make use of boto ( http://code.google.com/p/boto/ ) 其中get_running_instances和get_running_instances_by_regex是使用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
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. 我对动态的想法,或者至少我试图做的是,采用刚刚由
boto
创建的实例DNS名称,并使用fab命令访问该实例。 I couldn't do fab staging deploy
, because the instance doesn't exist at fabfile-editing time. 我无法进行
fab staging deploy
,因为实例在fabfile编辑时不存在 。
Fortunately, fabric
does support a truly dynamic host-assignment with execute . 幸运的是,
fabric
确实支持带有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.
Execute允许您定义要调用的函数以及它应该用于该命令的env.hosts 。 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. 现在我可以做
fab build_box
,它将触发一个创建实例的boto
调用,以及在新实例上运行的另一个fabric
调用 - 无需在编辑时定义实例名。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.