Taskcluster 运行时配置管理
项目描述
tc-admin
库支持管理Taskcluster部署的运行时配置。这意味着根据版本控制的规范创建和维护资源,例如角色、钩子和工作池。
用法
此库作为包含特定于Taskcluster部署(们)的代码和配置的Python应用程序的依赖项使用。该项目应包含一个tc-admin.py
,用于定义应用程序配置。
假设已设置,此工具易于使用
安装应用程序后,运行tc-admin generate
以生成预期的资源集(使用--json
以获取JSON输出)。这将需要设置环境变量TASKCLUSTER_ROOT_URL
,以了解要与之通信的部署。类似地,tc-admin current
将生成当前资源集(可选地使用--json
)。要比较它们,请运行tc-admin diff
。
如果配置包含机密信息,您可能希望传递--without-secrets
选项。此选项跳过管理机密内容,因此不需要访问机密值或Taskcluster凭据来获取机密。
运行tc-admin apply
以应用更改。请注意,只有apply
需要Taskcluster凭据,因此仅在运行此命令时设置TC凭据是一种好习惯。
有关更多有用的选项,请参阅tc-admin <command> --help
。
检查
检查是一种方法,用于确保在Taskcluster部署中满足特定目的的守则。例如,检查是否只有特定的存储库角色有在关键工作池中创建任务的权限可能很重要。检查定义为常规Python测试,并可以访问当前和生成的配置。
如果应用已设置检查,则tc-admin check
将运行这些检查。
库操作快速指南
此工具的操作非常简单:它生成一组预期的Taskcluster资源,从Taskcluster API下载现有资源,并比较它们。资源集合还指定了“管理”资源的集合——这允许删除不再预期的资源,而不会风险删除Taskcluster API中的所有内容。
生成后,资源可以被“修改”。这通常用于根据环境对资源进行少量更改。例如,在预发布环境中,可能需要删除钩子调度。
应用配置
tc-admin
和tc-admin.py
tc-admin应用通过tc-admin.py
进行配置。这是一个Python文件,负责创建和自定义一个AppConfig
对象。
from tcadmin.appconfig import AppConfig
appconfig = AppConfig()
# .. customize
tc-admin
命令在当前目录或由$TC_ADMIN_PY
或命令行参数--tc-admin-py
指定的目录中查找tc-admin.py
。类似于大多数Python模块,当tc-admin.py
执行时,全局__file__
被设置,可以用来确定相对路径。
在执行tc-admin.py
之前,当前工作目录被更改为包含它的目录。这使得相对导入以及加载具有相对路径的文件(例如下面的LocalLoader)成为可能。
程序接口
此库也可以用于程序化。只需直接创建一个AppConfig对象,并使用它调用tcadmin.main.main
from tcadmin.appconfig import AppConfig
from tcadmin.main import main
def boot():
appconfig = AppConfig()
# .. customize
main(appconfig)
if __name__ == "__main__":
boot()
请注意,在这种情况下,当前目录不会自动设置。
AppConfig
AppConfig对象包含一些可以自定义的属性,如下所述。在执行过程中,当前AppConfig对象可以通过AppConfig.current()
访问。这当生成器或修改器在单独的Python模块中定义时非常有用。
生成器
生成器生成预期的Taskcluster资源和定义了管理资源名称。每个生成器是一个异步函数,它接受一个Resources
对象,并期望调用resources.manage
和resources.update
。
生成器通过appconfig.generators.register
注册,最简单的是使用装饰器
@appconfig.generators.register
async def update_resources(resources):
# modify in place ...
在生成机密时,请尊重--with-secrets
选项,并在该选项为false时生成没有值的机密。您还可以使用此选项来确定生成过程是否需要访问机密值。这允许在没有凭据或访问机密值的情况下进行具有--without-secrets
的生成运行。
@appconfig.generators.register
async def update_resources(resources):
# modify in place ...
if appconfig.options.get('--with-secrets'):
secretstore = load_secret_values()
resources.add(Secret(
name="top-secret/cookie-recipe",
secret=secretstore.decrypt('recipes/double-chocolate-chip')))
else:
resources.add(Secret(name="top-secret/cookie-recipe"))
修改器
修改器负责修改一组现有资源。由于资源是不可变的,因此其签名略有不同
@appconfig.modifiers.register
async def modify_resources(resources):
# return new set of resources
return resources.map(..)
修改器按它们注册的顺序依次调用。
回调
回调是来自您应用程序的外部函数,可以在 tc-admin apply
执行过程中的特定时间执行。
before_apply
回调将在创建、更新或删除资源之前运行。after_apply
回调将在资源创建、更新或删除之后运行。
支持的操作包括:
- 创建
- 更新
- 删除
默认情况下,所有操作都被使用。
所有资源都支持回调,并且默认启用。如果您想限制回调只应用于某些资源,您需要使用它们的类(而不是字符串)来指定它们。
您可以将回调声明为:
from tcadmin.resources import Secret
async def my_action(action, resource):
print("Got a callback on", action, resource)
# Will call your function when a secret has been updated or deleted
appconfig.callbacks.add("after_apply", my_action, actions=["update", "delete"], resources=[Secret, ])
命令行选项
应用程序可以添加额外的命令行选项,这些值在资源生成期间可用。
要注册选项,调用 appconfig.options.add
,并带有完整的选项名称和以下任一关键字选项
required
- 如果为 True,则该选项是必需的help
- 在tc-admin generate --help
中显示的帮助字符串default
- 该选项的默认值
要在生成期间检索选项值,请调用 appconfig.options.get(name)
。全部加在一起,那么
appconfig.options.add("--branch", help="configuration branch to read from")
@appconfig.generators.register
async def update_resources(resources):
branch = appconfig.options.get("--branch")
# ...
作为一个特例,--with-secrets
密钥可以通过这个相同的机制获得。
检查
appconfig.check_path
属性提供了相对于当前目录运行的检查的路径 tc-admin check
。此目录是一个“正常”的 pytest 目录。
为了帮助区分检查和测试,请在此目录中包含一个 pytest.ini
[pytest]
python_classes = Check*
python_files = check_*.py
python_functions = check_*
description_prefix
appconfig.description_prefix
属性允许用户自定义描述的前缀。这可以在 tc-admin.py
中自定义,如下所示
from tcadmin.appconfig import AppConfig
appconfig = AppConfig()
appconfig.description_prefix = "YOUR_CUSTOM_PREFIX"
description_prefix 的默认值是 *DO NOT EDIT* - This resource is configured automatically.\n\n
根 URL
对于只适用于单个 Taskcluster 部署的配置的常见情况,请在 tc-admin.py
中指定该部署的根 URL。
from tcadmin.appconfig import AppConfig
appconfig = AppConfig()
appconfig.root_url = "https://taskcluster.example.com"
为了支持更复杂的情况,此值也可以是一个异步可调用对象。它将在处理完 click
选项后调用一次,因此如果需要,可以访问 appconfig.options
。
可以通过异步辅助函数获取当前根 URL
from tcadmin.util.root_url import root_url
async def foo():
print(await root_url())
这将从 AppConfig 获取值,如果没有设置,则从 TASKCLUSTER_ROOT_URL
获取。如果两者都已设置,并且值不匹配,将产生一个错误消息。
加载配置源
大多数使用此库的用例都从一些易于修改的 YAML 文件中加载配置数据。tcadmin.util.config
包提供了一些加载和解析这些文件的支持。所有这些都是完全可选的;使用适合目的的内容。
加载器
首先,定义一个可以从文件加载数据的加载器。
from tcadmin.util.config import LocalLoader
loader = LocalLoader()
LocalLoader 类知道如何从相对于 tc-admin.py
的文件加载配置。它有一个 load
方法,可以加载数据,并可选择将其解析为 YAML。
data = loader.load("data.bin")
aliases = await loader.load("aliases.yml", parse="yaml")
您也可以定义自己的加载器类。只需实现 load_raw
方法,给定一个文件名返回字节即可。
配置
在 Python 中处理 YAML 数据不方便,会引入大量的 [".."]
噪音。通常,配置文件要么是一个顶级数组,要么是一个顶级对象,它具有命名的“段落”配置。ConfigList 和 ConfigDict 类支持这些格式。我们建议与 Python 的 attrs
库一起使用这些。
定义一个从这些类之一继承的类,指定要从中加载的文件名,并具有用于集合中的项的 Item
类。
from tcadmin.util.config import ConfigList
class Workers(ConfigList):
filename = "workers.yml"
@attr.s
class Item:
workerId = attr.ib(type=str)
bigness = attr.ib(type=int, default=1)
然后只需调用 await Workers.load(loader)
来加载一个类似于 workers.yml
的文件
- workerId: small
bigness: 5
- workerId: huge
bigness: 5000
ConfigDict 类类似,但它解析文件,如下所示
small:
bigness: 5
huge:
bigness: 5000
ConfigList从数组元素item
中使用Item(**item)
创建新的Item
实例。ConfigDict从k: item
中使用Item(k, **item)
创建新的Item
实例。这种方法与attrs
兼容,在后一种情况下,k
应该是定义的第一个属性。
如果数组元素或对象值不是YAML对象,请为YAML文件中的数据添加一个名为transform_item
的类方法,以将其转换为Python字典。例如
class Workers(ConfigList):
@classmethod
def transform_item(cls, item):
# given a simple string, assume that is the workerId and apply defaults
if isinstance(item, str):
return {"workerId": item}
return item
...
资源
tcadmin.resources
包包含用于定义Taskcluster资源和集合的类。
from tcadmin.resources import Resources
Resources
类定义了一个资源集合,并跟踪哪些资源被管理。在Taskcluster部署中找到的资源,如果与“managed”模式匹配但未被生成,将在apply
时被删除。该类有以下方法
resources.add(resource)
- 将资源添加到集合中。资源必须是受管理的。resources.update(iterable)
- 将一个包含资源的可迭代对象添加到集合中。所有资源都必须受管理。resources.manage(pattern)
- 将与正则表达式字符串pattern
匹配的资源视为受管理resources.is_managed(id)
- 如果给定的资源被管理,则返回trueresources.filter(pattern)
- 返回一个新的Resources
对象,其中只包含与给定正则表达式字符串匹配的资源resources.map(functor)
- 返回一个新的Resources
对象,其中functor应用于每个资源。这通常用于修饰符。
资源必须是唯一的——tc-admin不能管理具有相同名称的多个钩子,例如。然而,某些资源类型支持合并,其中具有与已存在资源相同标识的资源将被添加到现有资源中。请参阅以下关于角色的说明。
其余的类代表单个资源。每个都由其类型和Taskcluster中资源的唯一标识符组成id
。例如,Hook=release-hooks/beta-release
。资源创建后是不可变的,但可以使用rsrc.evolve(**updates)
进行“进化”(返回新资源)。
具有描述的资源会自动添加“请勿编辑”前缀,以劝阻用户在Taskcluster UI中编辑它们。
钩子
from tcadmin.resources import Hook, Binding
hook = Hook(
hookGroupId=..,
hookId=..,
name=..,
description=..,
owner=..,
emailOnError=..,
schedule=(.., ..),
bindings=(.., ..),
task={..},
triggerSchema={..})
这些字段中的大多数直接对应于Taskcluster的定义。schedule
和bindings
都必须是元组,而不是列表(因为列表是可变的)。schedule
中的项是cron-like字符串。bindings
中的项是Binding(exchange=.., routingKeyPattern=..)
的实例。
秘密
from tcadmin.resources import Secret
secret = Secret(
name=..,
secret=..)
# or, when not managing secret values
secret = Secret(name=..)
使用秘密资源类型管理秘密。虽然Taskcluster支持秘密的过期时间,但此库将这些时间设置为遥远的未来,从而创建非过期秘密
此库非常注意不在其输出中显示秘密值。相反,当不管理秘密值时,它显示<unknown>
,当管理秘密值时,它显示秘密值的散列。散列允许tc-admin diff
显示秘密值已更改,而不透露该秘密的值。散列包括每次运行的散列和秘密的名称,因此即使两个秘密具有相同的值,它们在tc-admin generate
中将显示不同的散列。
角色
from tcadmin.resources import Role
role = Role(
roleId=..,
description=..,
scopes=(.., ..))
与钩子一样,scopes
必须是一个字符串元组(而不是列表)。
如果描述匹配,则可以合并角色。结果角色包含输入角色的作用域的并集。这种功能使得在生成过程的各个部分可能向同一角色添加作用域的情况下管理角色更加容易。
例如
resources.add(Role(roleId="my-role", description="My Role", scopes=["scope1"]))
resources.add(Role(roleId="my-role", description="My Role", scopes=["scope2"]))
这将生成一个具有作用域["scope1", "scope2"]
的单个角色。
客户端
from tcadmin.resources import Client
client = Client(
clientId=..,
description=..,
scopes=(.., ..))
客户端的工作方式与角色类似。与角色一样,作用域
必须是一个字符串的元组(而不是列表)。该库不管理访问令牌:它会从auth.createClient
的响应中丢弃它们。预期项目管理员需要为受管理客户端提供凭证时,将调用auth.resetAccessToken
并使用返回的令牌。
由该库配置的客户端具有一个远期的过期日期。与角色一样,此处管理的客户端“永远有效”。
WorkerPool
from tcadmin.resources import WorkerPool
workerPool = WorkerPool(
workerPoolId=..,
providerId=..,
description=..,
owner=..,
config={..},
emailOnError=..)
此类的所有属性都与Taskcluster定义相匹配。
实用工具
该库提供了一些常用应用程序需求的实用工具。
注意:只有在本README中描述的函数被视为稳定。库中定义的其他函数可能会在没有通知的情况下更改。
作用域
为了帮助编写检查,tc-admin提供了各种作用域相关算法的本地实现。
from tcadmin.util.scopes import satisfies, normalizeScopes, Resolver
satisfies
函数确定作用域满足情况,不进行任何扩展。满足意味着第一个参数包含第二个参数中的所有作用域。
assert satisfies(['balloons:*', 'cake:birthday'], ['baloons:mylar:happy-birthday'])
normalizeScopes
函数规范作用域集,删除冗余作用域并排序。
assert normalizedScopes(['balloons:*', 'balloons:mylar:*']) == ['baloons:*']
最后,Resolver
可以执行作用域扩展。它使用将roleIds映射到作用域列表的字典进行初始化。或者,它可以从Resources
实例使用Resolver.from_resources(resources)
进行初始化。
它的expandScopes
方法的行为与远程调用auth.expandScopes
相同。
resolver = Resolver.from_resources(resources)
assert resolver.expandScopes(['assume:clown:grimaldi']) == ['assume:clown:grimaldi', 'ruffle:full']
aiohttp会话
该库使用aiohttp
与Taskcluster通信,并为了效率而建立单个会话。应用程序可以使用相同的会话进行任何其他HTTP操作。
from tcadmin.util.session import aiohttp_session
async def foo():
# ...
async with aiohttp_session().get(url) as response:
response.raise_for_status()
result = await response.read()
测试和检查可以使用with_aiohttp_session
设置此值
from tcadmin.util.sessions import with_aiohttp_session
import pytest
@pytest.mark.asyncio
@with_aiohttp_session
async def test_something():
# ...
MatchList
MatchList是一系列正则表达式,可以确定给定的字符串是否与这些模式之一匹配。模式从左侧开始,但应使用$
来匹配字符串的末尾。
from tcadmin.util.matchlist import MatchList
ml = MatchList()
ml.add("fo+$")
ml.add("ba+r$")
assert ml.matches("foo")
此功能用于跟踪受管理资源,但可能在其他方面也很有用。
开发
要为开发安装,在虚拟环境
pip install -e [path]
运行flake8和测试
python setup.py flake8
python setup.py test
该库使用Black格式化代码。
pip install black
black tcadmin
发布
要发布
- 更新
setup.py
中的版本并使用git commit -m "vX.Y.Z"
提交更改 git tag vX.Y.z
- 将这些更改推送到
main
./release.sh --real
并在提示时输入您的PyPI凭证(如果您不确定,省略--real
以尝试它针对测试PyPI)- 在https://github.com/taskcluster/tc-admin/releases中找到标记并创建一个新的发布,其中包含更改的简要描述
Docker镜像
要构建和发布tc-admin Docker镜像的新版本,请运行
docker build -t tc-admin:X.Y.Z .
docker push tc-admin:X.Y.Z
项目详细信息
下载文件
下载您平台上的文件。如果您不确定选择哪个,请了解更多关于安装包的信息。
源分布
构建分发
tc_admin-4.0.1.tar.gz的哈希值
算法 | 哈希摘要 | |
---|---|---|
SHA256 | 7f6d4903cf45d412e9d3c0e204bda054238217bf05096fd766bafbc0750e3802 |
|
MD5 | 418ac827f5b81430ade901e92139a739 |
|
BLAKE2b-256 | 93b772e08e6d077567ab39a8729a9905e1e351b9cee78235574b3b787b7f8f1f |
tc_admin-4.0.1-py3-none-any.whl的哈希值
算法 | 哈希摘要 | |
---|---|---|
SHA256 | 22888b3d1856dc9b92b50964c1427c0d42a314ea95c2122f7bd2a32013d85e95 |
|
MD5 | 880590ada026a14270fd7069ab91d983 |
|
BLAKE2b-256 | 758f1fbcb13f90f98dc81d1a3d98af65ddcceac079b19d3b71318dabf10eaea8 |