这是一个非常Fabric特定问题,但更有经验的python黑客可能能够回答这个问题,即使他们不了解Fabric。
我试图在命令中指定不同的行为,具体取决于它运行的角色,即:
def restart():
if (SERVERTYPE == "APACHE"):
sudo("apache2ctl graceful",pty=True)
elif (SERVERTYPE == "APE"):
sudo("supervisorctl reload",pty=True)
我用这样的函数来攻击它:
def apache():
global SERVERTYPE
SERVERTYPE = "APACHE"
env.hosts = ['xxx.xxx.com']
但这显然不是很优雅,我只是发现了角色,所以我的问题是:
如何确定当前实例属于哪个角色?
env.roledefs = {
'apache': ['xxx.xxx.com'],
'APE': ['yyy.xxx.com'],
}
谢谢!
答案 0 :(得分:18)
对于其他所有有过这个问题的人来说,这是我的解决方案:
关键是找到env.host_string。
这是我用一个命令重启不同类型服务器的方法:
env.roledefs = {
'apache': ['xxx.xxx.com'],
'APE': ['yyy.xxx.com']
}
def apache():
env.roles = ['apache']
...
def restart():
if env.host_string in env.roledefs['apache']:
sudo("apache2ctl graceful", pty=True)
elif env.host_string in env.roledefs['APE']:
sudo ("supervisorctl reload", pty=True)
享受!
答案 1 :(得分:12)
我没有测试它,但可能有效:
def _get_current_role():
for role in env.roledefs.keys():
if env.host_string in env.roledefs[role]:
return role
return None
答案 2 :(得分:6)
env.roles
将为您提供-R标志指定的角色或脚本本身的硬编码。它不包含使用命令行或使用@roles
装饰器为每个任务指定的角色。目前无法获得此类信息。
下一个结构版本(可能是1.9)将为env.effective_roles
属性提供您想要的内容 - 用于当前执行任务的角色。该代码已经合并为master。
查看this issue。
答案 3 :(得分:5)
更新:刚刚检查了the source code,似乎早在1.4.2就已经可以使用了它!
update 2 :使用@roles
装饰器时(1.5.3),这似乎不!它仅在使用-R
命令行标志指定角色时才有效。
对于fabric 1.5.3,当前角色可直接在`fabric.api.env.roles'中使用。例如:
import fabric.api as fab
fab.env.roledefs['staging'] = ['bbs-evolution.ipsw.dt.ept.lu']
fab.env.roledefs['prod'] = ['bbs-arbiter.ipsw.dt.ept.lu']
@fab.task
def testrole():
print fab.env.roles
在控制台上测试输出:
› fab -R staging testrole
[bbs-evolution.ipsw.dt.ept.lu] Executing task 'testrole'
['staging']
Done.
或者:
› fab -R staging,prod testrole
[bbs-evolution.ipsw.dt.ept.lu] Executing task 'testrole'
['staging', 'prod']
[bbs-arbiter.ipsw.dt.ept.lu] Executing task 'testrole'
['staging', 'prod']
Done.
有了这个,我们可以在结构任务中进行简单的in
测试:
@fab.task
def testrole():
if 'prod' in fab.env.roles:
do_production_stuff()
elif 'staging' in fab.env.roles:
do_staging_stuff()
else:
raise ValueError('No valid role specified!')
答案 4 :(得分:0)
在Anaconda2 5.1.0下使用fabric 1.14.0 ...在使用@roles
装饰器时确认问题...特别是在@roles
装饰器与多个参数一起使用的情况下在第一个任务中调用没有@roles
装饰器(或具有不同参数)的另一个任务。根据我的经验,这可能会产生非理论上不匹配主机的影响,具体取决于我发现角色的方式(即role = env.effective_roles[0]
)。
请注意role = env.effective_roles[0]
在简单的情况下效果很好,例如(a)@roles
仅指定一个角色,(b)原始任务不会调用另一个任务。
还请注意命令行上的-R
未覆盖@roles
并且必须使用task:roles=role1
的情况:How to run a @roles-decorated fabric task on only a single host ...也想知道如何将多个角色传递给一个名为roles
的争论...嗯,但我离题了。
也许有更好的方法,但@roles
上的文档让人想要。下一步是在这一点上阅读源代码。
与此同时,我已经破解了以下解决方法......
from fabric.api import env
from fabric.decorators import roles
from fabric.decorators import task
def get_host_roles(env, of=None, die=False):
"""
Get the role(s) for a host at run time
:param env: Fabric env
:param of: tuple/set/list
:param die: boolean
:return: tuple(host, roles) or tuple(host, role)
"""
host = env.host
def valid(role):
return host in env.roledefs[role]:
roles = set(filter(valid, env.roledefs.keys()))
if of:
roles = tuple(roles & set(of)) # set intersection
if len(roles) == 1:
return host, roles[0]
elif die:
e = 'Host "%s" is not in just one of the provided roles: %s!' \
% (host, repr(roles))
raise Exception(e)
return host, roles
_roles = ('role1', 'role2')
@task
@roles(*_roles)
def do_something_with_roles():
host, roles = get_host_roles(env)
# roles is a tuple with all of the roles the host is in.
@task
@roles(*_roles)
def do_something_with_roles_diy():
host, roles = get_host_roles(env, _roles)
# `roles` is a tuple with the set intersection of `_roles` and the
# host's actual roles... so you handle the situation!
if 'role1' in roles:
# do whatever
pass
@task
@roles(*_roles)
def force_single_role():
host, role = get_host_roles(env, _roles, True)
# this usage raises an exception in the instance that the host is not
# exclusively in either 'role1' or 'role2'.
# roles is a string with the role for that host.
希望有所帮助。