样本结构(fabfile)共享通用逻辑并允许多个项目/环境

时间:2014-01-22 16:07:00

标签: python deployment capistrano fabric

我是python和fabric的新手。我们目前使用capistrano并设置类似于此的设置:

/api-b2b
  - Capfile (with generic deployment/setup info)
  /int - target host config (like ip, access etc.)
  /prod - target host config (like ip, access etc.)
  /dev - target host config (like ip, access etc.)
/api-b2c
  /int
  /prod
  /dev
/application1
  /int
  /prod
  /dev
/application2
  /int
  /prod
  /dev

我们对使用capistrano处理我们的java应用程序感到不满意 - 结构看起来更好(更简单)。

我到目前为止看到的所有示例fabfiles都“相对简单”,因为它们只处理不同主机的一个应用程序。我希望看到一些代码,其中不同的应用程序/主机由相同的结构文件/基础结构(如继承等)处理,以共享相同的逻辑,用于常见任务,如git处理,目录创建,符号链接等。我希望你得到我的意思。我希望整个逻辑是相同的,只是应用程序配置是不同的(git repo,目标目录)。所有其余的都是相同的应用程序(相同的服务器布局......)

我希望能够输入类似这样的内容

$ cd api-b2b
$ fab env_prod deploy
$ cd api-b2c
$ fab env_prod deploy

$ fab env_prod deploy:app=api=b2b
$ fab env_prod deploy:app=api=b2c

高度赞赏的任何帮助(以及对示例文件的指示)

欢呼声 烫发

1 个答案:

答案 0 :(得分:4)

如果你真的希望在你的结构代码中重用,最强大的方法是重构共性并使其成为python模块。像fabtoolscusine这样的模块就是可以做到的很好的例子。

如果您希望拥有多个项目,有几种方法可以实现这一结果。假设您正在使用fabfile目录(而不是单个fabfile.py),那么您将拥有这样的结构。

/fabfile
  __init__.py
  b2b.py
  b2c.py

假设你有:

# b2b.py / b2c.py
from fabric.api import *

@task
def deploy():
    # b2b/b2c logic
    pass

当您运行fab -l(空__init__.py)时,您会看到:

Available commands:

    b2b.deploy
    b2c.deploy

为了更接近您正在寻找的内容,您可以从参数中动态查找要运行的部署目标:

# __init__.py 
from fabric.api import *
import b2b
import b2c

@task
def deploy(api):
    globals()[api].deploy()

这意味着在命令行中,我可以运行fab deploy:api=b2bfab deploy:api=b2c


编辑1月27日

使用-H-R开关,使用@task@role装饰器,可以在命令行中为要运行的任务指定一个或多个计算机,或者结构环境中的设置(env.hosts和env.roles)。结构文档在execution model上有大量示例,向您显示所有详细信息。

执行此操作的一种方法(可能不是最佳方式,具体取决于您的应用)是dynamically alter基于api和目标环境的主机列表。

# __init__.py
from fabric.api import *
import b2b
import b2c

@task
def deploy(api, target='test'):
    func  = globals()[api].deploy
    hosts = globals()[api].deploy_hosts(target)
    execute(func, hosts=hosts) 

现在b2b.pyb2c.py文件看起来像是:

# b2b.py / b2c.py
@task
def deploy():
    # b2b/b2c logic
    pass

def deploy_hosts(target):
    return {
        'test' : ['localhost'],
        'prod' : ['localhost'],
        'int'  : ['localhost'],
    }[target]