我正在寻找在多个服务器上执行任务的方法(是的我知道roledefs -R和hosts -H选项)但是我需要一些额外的参数,例如每个主机等不同的用户,我想保持它干净并且整洁,因为我将我的主机作为函数定义(在某处的堆栈上建议),以便有可能在这样的一个上执行任务
def test():
user='root'
env.host='myapp-test.com'
我开始修改env.tasks但事实证明它们是由生成器迭代的,并且通过context_manager访问它们仅用于视图(如fab文档中)。
我想保留我的“类似函数的主机”,所以我最终动态修改env.hosts并编写装饰器,根据当前的env.host更新服务器特定的数据(将来会覆盖默认的任务装饰器)工作代码下面(为了安全起见,我不得不在代码中更改名称希望没有破坏任何功能):
APP_SERVERS= {
'test':{
'envname':'test',
'user':'deploy_user',
'host':'myapp-test.com',
'host_string':'myapp-test.com',
'path':'/opt/myapp/test/',
'www_root':'http://myapp-test.com/',
'retries_before_killing':3,
'retry_sleep':2
},
'staging':{
'envname':'staging',
'user':'deploy_user',
'host':'myapp-staging.com',
'host_string':'myapp-staging.com',
'path':'/opt/myapp/staging/',
'www_root':'http://myapp-staging.com/',
'retries_before_killing':3,
'retry_sleep':2
},
'uat':{
'envname':'uat',
'user':'deploy_user',
'host':'myapp-uat.com',
'host_string':'myapp-uat.com',
'path':'/opt/myapp/uat/',
'www_root':'http://myapp-uat.com/',
'retries_before_killing':3,
'retry_sleep':2
},
'live1':{
'envname':'live1',
'user':'deploy_user',
'host':'myapp-live1.com',
'host_string':'myapp-live1.com',
'path':'/opt/myapp/live1/',
'www_root':'http://myapp-live1.com/',
'retries_before_killing':1,
'retry_sleep':1
},
'live2':{
'envname':'live2',
'user':'deploy_user',
'host':'myapp-live2.com',
'host_string':'myapp-live2.com',
'path':'/opt/myapp/live2/',
'www_root':'http://myapp.com/',
'retries_before_killing':1,
'retry_sleep':1
}
}
TEST_HOSTS = ['test','staging','uat']
LIVE_HOSTS = ['live1','live2']
def test():
env.update(dict(APP_SERVERS['test']))
def staging():
env.update(dict(APP_SERVERS['staging']))
def uat():
env.update(dict(APP_SERVERS['uat']))
def live1():
env.update(dict(APP_SERVERS['live1']))
def live2():
env.update(dict(APP_SERVERS['live2']))
# GROUPS OF SERVERS DEFINITION
def live_servers():
env['hosts'] = [APP_SERVERS[a]['host'] for a in APP_HOSTS]
def test_servers():
env['hosts'] = [APP_SERVERS[a]['host'] for a in APP_HOSTS]
def env_update(func):
def func_wrapper(*args,**kwargs):
if not len(env.hosts):
return func(*args,**kwargs)
else:
env.update(dict(APP_SERVERS[filter(lambda x: APP_SERVERS[x]['host']==env.host,APP_SERVERS)[0]]))
func(*args,**kwargs)
return func_wrapper
@env_update
def pull_commits():
#some_code
run('uptime')
我有可能运行组执行任务fab live_servers pull_commits以及单个fab live1 pull_commits。
我知道可能还有像使用单独服务器的重复任务一样,live1 pull_commits live2 pull_commits但我相信这个结构是为分布式系统编写的,它有不同的应用程序和用户等路径。
所以我的问题是:有更简单的方法吗?喜欢构建到fabric中的东西(还有带额外dict键的roledef对我不起作用)?或者我没有看到一些面料功能? 我想保留这个简单的单/多主机部署命令,如:fab live_servers pull_commits,fab test pull_commits
答案 0 :(得分:0)
不要使用当前的方法,而是考虑使用host_string
作为ARG_SERVERS字典的关键字,然后根据需要在任务中加载信息(包括对结构环境的任何必要更新。进行此调整意味着你也应该能够让角色发挥作用。
例如:
@task
def pull_commits():
hostinfo = ARG_SERVERS[env.host_string]
# ... more code
run(...)
另一个建议是考虑使用ssh配置文件(〜/ .ssh / config)为所有机器定义ssh别名。这会将您的所有host / host_string / username信息放在一个中心位置,并且具有以下优点:您可以引用具有单个有意义名称的主机并简化ARG_SERVERS。
# contents of $HOME/.ssh/config
Host test
HostName myapp-test.com
User deploy-user
Host staging
HostName myapp-staging.com
User deploy-user
Host uat
HostName myapp-uat.com
User deploy-user
Host live1
HostName myapp-live1.com
User deploy-user
Host live2
HostName myapp-live2.com
User deploy-user
根据更传统的结构任务模型,您现在应该可以执行以下操作:
# single host
$ fab -H live1 pull_commits
# multiple hosts
$ fab -H test,staging pull_commits
或角色(根据结构文档)。