是否可以使 fabfile 独立?
我不太喜欢运行外部工具“fab”。如果我设法获得独立的 fabfile,我可以从(Eclipse / Pydev)IDE 中运行该文件,轻松调试它,使用项目配置和路径等。
为什么这不起作用:
from fabric.api import run
def host_type():
run('uname -s')
if __name__ == '__main__':
host_type()
我最终找到了解决方案(这真的很简单!)。
在我的 fabfile 中,我添加了:
from fabric.main import main
if __name__ == '__main__':
import sys
sys.argv = ['fab', '-f', __file__, 'update_server']
main()
我希望这可以帮助人们...
如果我没记错的话,我也无法让 Fabric API 做我想做的事。我决定完全放弃额外的层,直接使用Paramiko(Fabric 使用的底层 SSH 库):
import os
import paramiko
ssh = paramiko.SSHClient()
ssh.load_system_host_keys()
ssh.load_host_keys(os.path.expanduser('~/.ssh/known_hosts'))
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh.connect('hostname.example.com', 22, 'username', 'password')
ssh.save_host_keys(os.path.expanduser('~/.ssh/known_hosts'))
stdin, stdout, stderr = ssh.exec_command('uname -s')
print stdout.read()
虽然涉及更多步骤,但这样做可以让您直接利用 SSH 层,而不是使用subprocess
生成另一个 Python 实例或找出 Fabric API。我有几个项目,包括 web 和控制台,都以这种方式使用 Paramiko,我没有遇到太多麻烦。
Paramiko 被广泛记录。
从1.5.0开始,有一种比乱用 argv 更好的方法。
import fabric.main
def main():
fabric.main.main(fabfile_locations=[__file__])
if __name__ == "__main__":
main()
这也可以用作 setup.py 中的控制台脚本
docs.fabfile.org/en/1.4.0/usage/library.html
“正如那部分提到的,关键是运行、sudo 和其他操作在连接时只在一个地方查找: env.host_string 。所有其他设置主机的机制都由 fab 工具在运行时解释,并且不要作为图书馆运行时没关系。”
当我发现这个时,我正在寻找同样的问题。另外,在查看时我记得提到在 fabfile 中使用时,env 更改不应与 run、sudo 位于相同的 def 中。谁知道在“库”模式下使用时这是否仍然适用。
编辑:这是上述实现的一个例子
from fabric.api import env, run
def main():
run("uname -a")
def setup():
env.host_string = "me@remoteHost"
if __name__ == '__main__':
setup()
main()
# thanks to aaron, extending his code a little more
# here is a little bit more of a graceful solution than running subprocess.call, and specifying multiple hosts
from fabric.api import env, run
def main():
run("uname -a")
def setup():
env.hosts = ['host0','host1']
if __name__ == '__main__':
setup()
for host in env.hosts:
env.host_string = host
main()
我对上面的示例进行了微调,以通过 argv 参数传递给本地命令,并指定一个可选的 default_commands 列表而不是硬编码的命令名称。请注意,文件名必须具有 .py 扩展名,否则 fab 不会将其检测为 fab 文件!
#!/usr/bin/env python
from fabric.api import local
default_commands = ['hello', ]
def hello():
print ('hello world')
def hostname():
local('hostname')
if __name__ == '__main__':
import sys
from fabric.main import main
sys.argv = ['fab', '-f', __file__,] + default_commands + sys.argv[1:]
main()
这不是一个很好的解决方案,但会起作用:
import subprocess
def hello():
print 'Hello'
if __name__ == '__main__':
subprocess.call(['fab', '-f', __file__, 'hello'])
将此添加到您的 fab 文件的底部。
if __name__ == '__main__':
from fabric.main import main
import sys
sys.argv = ['fab', '-f', __file__] + sys.argv[1:]
main()
这是我对Greg 答案的修改版本,它更改了默认行为以显示可用命令,而不是列出大量的结构选项。
if __name__ == '__main__':
# imports for standalone mode only
import sys, fabric.main
# show available commands by default
if not sys.argv[1:]:
sys.argv.append('--list')
fabric.main.main(fabfile_locations=[__file__])
我在运行结构文件上间接找到了解决方案,而不是 fabfile.py 和无密码 ssh
def deploy():
...
if __name__ == '__main__':
from fabric import execute
execute(deploy)
如果您的文件没有.py
扩展名,这种方式也可以工作。