BUILD 脚本

BUILD 脚本基于 ambot-script,请预先阅读相关文档。BUILD 脚本的运行环境在打包机器上,因此无法使用集群功能。

环境信息

工作目录

build 脚本默认运行目录为 .ambot 目录的父目录

即,一个位于 /opt/something/.ambot/BUILD 的脚本的执行工作目录为 /opt/something,其值保证为绝对路径、且不以 / 结尾。

典型构成

一个典型的 BUILD 脚本包括如下内容

  • 声明自己的 id
  • 添加需要包含的目录(不可修改的 Software、可利用 vars 渲染的 Config)
  • 添加需要包含的 Service

ID 规范

package identifier (即可 pkg-id) 为域名反写,请遵从以下规范

  • 只能含有字母、数字、中横线
  • 公司内部项目以 com.tophant. 开头
    • 特定项目使用 com.tophant.[项目名]. 开头,例如 com.tophant.prs.nta-api
    • 公共项目使用 com.tophant.common. 开头,任何未来可能扩展用途的项目均应当使用 common
  • 第三方项目以相应项目的官方标识符或官网地址反写开头,例如 org.elasticsearch.es
  • 多部分以 . 分隔,应当至少包括三个部分,但不要超过五个部分
    • 例如不要使用 org.elasticsearch
    • 多个部分用于表示层级关系,例如 com.tophant.common.matrix.mh 可以直接认为是 com.tophant.common.matrix 的子项目
  • identifier 最后一个部分为 name,其应当是尽量唯一的,否则在机器上进行筛选等会出问题
    • 因此 name 不能为一个通用概念,而必须可以直接看出这个 package 对应的内容
  • identifier 一旦确定无法修改,相关升级流程等均依靠此决定,因此不要增加 config service 等后缀,因为后期可能会添加其他内容,界时相关名称会对用户导致误导
    • 例如初期 matrix 只包括 config,但不要使用 com.tophant.common.matrix-config 名称,而只使用 com.tophant.common.matrix
    • 在初期只包括 config 时,可以指定 display 参数(默认与 name 保持一致),display 参数应当严格设定为 name (comment) ,即原始名称 + 空格 + 括号内写注释,例如上述例子的 identifier 为 com.tophant.common.matrix,其 name 自动定为 matrix,因此指定 display 时应当为 matrix (config)

所有 identifier 确定后无法修改并且不能产生冲突,不当的 display 可能会使用户产生误解,因此如果需要使用和 identifier 不同的也应当慎重考虑

预定义变量

tag, describe_tag, commit, dirty

打包项目的 git 版本信息,可用于计算版本使用

  • tag: string, 最近一次的 tag
  • describe_tag: string, 当前 tag 的描述信息,即 git describe --tags 的执行结果
  • commit: string, 最近一次提交的 commit id
  • dirty: bool, 最近一次提交后是否还有修改

git_describe

基于上述与定义变量计算而来,逻辑如下

def get_git_describe():
    prefix = describe_tag
    if prefix == "": # 从来没有过 tag
        prefix = commit[:8]
        
    suffix = ""
    if dirty: # 在最后一次后仍然有提交
        suffix = "-dirty"
    
    return prefix + suffix

assert(get_git_describe() == git_describe)

内置函数

package(id: string)

声明 package 信息,必须为 BUILD 脚本的第一条指令

check_version(string) → bool

检查给定的 version 是否合法(符合版本号规范不以 v 开头

version(string)

默认情况下的版本号会基于 tag, describe_ tag, commit, dirty 信息进行综合计算得到,但前提是得到的 describe_tag 是一个标准的 semver 版本信息。

该函数用于提供一个版本号来覆盖默认行为。如果提供的版本号不合法会直接中断脚本执行,可以使用 check_version 来检测 version 是否合法。

对于非标 tag 可以使用 version 指令来指定版本号,当然必须注意的是因 BUILD 脚本被设计为不经常修改,因此 version 所传递的内容必须是利用预定义变量计算出来的,以下是默认行为,可以基于其进行修改

# 在脚本执行前已经预定义好了所需变量
# * tag = v1.0.0
# * describe_tag = v1.0.0-3-abcdef
# * commit = 012345678...abcdef
# * dirty = False
# * git_describe = v1.0.0-3-abcdef
def get_version():    
    describe = git_describe
    if describe.startswith("test_"): # 测试 tag 特殊逻辑
        describe = describe[len("test_"):] + "-test"
    
    if not (describe.startswith("v") or describe.startswith("V")):
        # 非版本号
        return "0.0.0-" + describe

    if check_version(describe[1:]):
        return describe[1:]
    else:
        return "0.0.0-" + describe


package(...)
version(get_version())

# ... 其他逻辑

require_vars(vars: dict<string, string>)

声明这个包安装时依赖的变量列表及类型,如果安装时对应的变量不存在或类型不合法,则会拒绝安装

vars 参数是一个 dict,其 key 为变量名称,value 为变量的类型约束,如果在安装时变量不存在或类型不匹配则会拒绝安装。

变量的名称应当遵守如下约定

  • package 特定配置应当以 package_name.var_name 命名,例如 es 的 hostname 应当命名为 es.hostname
  • 公有配置应当先行在自动化相关项目中记录并讨论审核确定再使用
  • 配置的层级用 . 分隔,任何一层的命名均为以字母开头后接若干字母、数字、下划线、中划线

任何配置名称和类型均应当在对应自动化项目中记录

变量的类型目前仅支持

  • string
  • number
  • bool
  • array
  • object

对于 array 不支持具体检查底层类型,未来可能会支持在 install 脚本中进行检查的能力

add_service(service: str, name?: str, vars?: Dict[str, str])

增加一个 service,service 参数传递的是 service 文件的名称,例如指定了 xx 则会依次搜索 .ambot/services/xx.service, .ambot/xx.service, .ambot/../services/xx.service, .ambot/../xx.service, ,这一搜索路径与工作目录无关。service 参数也可以指定一个相对路径,会基于当前工作目录进行搜索,使用相对路径时必须为全路径,即不能省略末尾的 .service

在 add_service 时,会在匹配到的 .service 文件的同级目录下查找同名但后缀为 .env 的文件,即如果添加了 a.service 则会在该文件的同级查找 a.env,如果找到则将此环境变量文件一同打包。环境变量文件可以使用模板变量,会自动渲染。

如果指定了 name 参数,则会 service 对应的文件、安装名则为 name 指定的

如果指定了 vars 参数,那么 ENV 会进行模板渲染(服务文件不会,因此如需使用请在 Service 中引用环境变量), vars 参数是一个 kv 对象,指示了渲染 ENV 需要什么变量、变量的类型是什么(key 为变量名、value 为类型)

如需了解怎么编写 Service 文件请参考 写给开发看的 Service 文件编写指南

add_mount(mountpoint: string, file_root: string)

增加软件包挂载,mountpoint 是未来在目标机器上进行挂载的路径,必须是绝对路径,file_root 是要打包的目录,应当是基于当前工作目录的相对路径

mountpoint 应当遵循一定的规则

  1. 任何两个包中不能重复
  2. 有一定的可预测性,例如 mount 放到 /opt/[name] 下而 config 放到 /data/[name]/config 下等,可以参考 建议的目录结构

mountpoint 必须保证不重复

add_config(mountpoint: string, file_root: string)

与 add_mount 类似,但是挂载配置文件使用的,并支持模板渲染功能。

add_config() 执行会返回一个 ConfigMutator 对象,其包括一个成员方法 render(file: str, ..., vars: Dict[str, str])

render 的使用方式类似 render("file1", "file2", { "xxx.yyy": "number" })

  • file 指定了 filename 的相对于 config mount root 的路径,可以传递多个
  • vars 则是一个 kv 对象,指示了这个模板渲染需要什么变量、变量的类型是什么(key 为变量名、value 为类型)

add_script(script: string, name: string = '', auto_run: bool = false)

该函数在 v1.6.0-beta.4 或更高版本可用

增加一个 script,script 参数传递的是 script 文件的名称,例如指定了 xx.apy 则会依次搜索 .ambot/scripts/xx.apy, .ambot/xx.apy, .ambot/../scripts/xx.apy, .ambot/../xx.apy, ,这一搜索路径与工作目录无关。script 参数也可以指定一个相对路径,会基于当前工作目录进行搜索。

script 的扩展名必须为 .apy.ash.py.sh,使用其他扩展名会在运行期报错。

如果省略 name 参数,则自动从 script 中提取 name(xx.apy -> xx) ,name 参数(无论是手动指定的还是自动生成的)不可与 package name 相同。