24 个版本
0.1.13 | 2024 年 7 月 21 日 |
---|---|
0.1.12 | 2023 年 12 月 11 日 |
0.1.5 | 2023 年 3 月 13 日 |
0.1.4 | 2023 年 2 月 10 日 |
0.0.7 | 2022 年 12 月 31 日 |
#41 在 过程宏
181 每月下载量
在 17 crates 中使用
110KB
2.5K SLoC
Terrars 是一个用于在 Rust 中构建 Terraform 堆栈的工具。这是 CDK 的替代品。
查看示例 在 helloworld.
当前状态:可用,但可能有一些粗糙的边缘和缺少的功能。我可能会继续调整以改善用户体验。
为什么使用这个或 CDK 而不是原始的 Terraform?
- 所有的堆栈最终都会变得复杂到需要完整的编程语言来生成。CDK 和这个工具并不比原始 Terraform 更冗长,所以我总是从一开始就使用它们。
- 在定义您的基础设施时重用代码中的常量和数据结构(JSON 结构、环境变量、端点和反向路由函数)
- 自动补全,通过类型进行编辑时验证
为什么使用这个而不是 CDK?
- 它是 Rust,您已经在使用
- 更强的静态类型安全性 - CDK 在许多情况下忽略了类型,并将必需和可选参数混合在一起
- 预生成的绑定
- 没有复杂的类型层次结构,如作用域、继承等。
- 更少的层 -
cdk
需要terraform
,一个cdk
命令行界面,JavaScript 工具,JavaScript 包目录,以及根据你使用的语言,还需要该语言本身。CDK 生成需要经历一个json spec -> typescript -> generated javascript -> final language
翻译过程。terrars
在生成和运行时都只需要terraform
,并且直接从 JSON 规范转换为 Rust。
为什么不用这个代替 CDK?
- 你需要创建自己的工作流程。你可以创建一个简单的
build.rs
文件,但如果你想创建一个更复杂的包装器,你需要自己编写。
预生成的绑定
基础设施
- hashicorp/aws
- hashicorp/google
- hectorj/googlesiteverification
- digitalocean/digitalocean
- andrewbaxter/fly
其他服务
- cloudflare/cloudflare
- integrations/github
- andrewbaxter/stripe
- backblaze/b2
- kreuzwerker/docker
- dnsimple/dnsimple
本地,软件
- andrewbaxter/dinker - 轻量级 Docker 镜像构建
- andrewbaxter/localrun - 外部构建脚本
- hashicorp/random
- hashicorp/local
- hashicorp/tls
入门
注意:在 helloworld 中有一个完整的工作示例。
-
将
terrars
和预生成的绑定(如 terrars-andrewbaxter-stripe)或自己生成(见下面的 生成)添加到你的项目中。在绑定中启用你想要使用的功能。 -
开发你的代码(例如:
build.rs
)创建一个
Stack
并设置提供商let mut stack = &mut BuildStack{}.build(); BuildProviderStripe { token: STRIPE_TOKEN, }.build(stack);
默认情况下,将使用提供商类型的第一个实例来使用该提供商的资源,因此你不需要绑定它。
然后创建资源
let my_product = BuildProduct { name: "My Product".into(), }.build(stack); let my_price = BuildPrice { ... }.build(stack); my_price.set_product(my_product.id()); ...
最后,输出堆栈
fs::write("mystack.tf.json", &stack.serialize("state.json")?)?;
-
在生成的
mystack.tf.json
文件所在的目录中,像往常一样调用terraform
(
Stack
还具有调用run()
和get_output()
的方法来为你调用terraform
。你必须将terraform
添加到你的路径中。)
生成绑定
虽然有些提供商有一些现成的 crate,但你也可以使用 terrars-generate
在本地为新的提供商生成代码。
-
使用
cargo install terrars
安装生成 CLI -
创建一个配置文件。例如,要使用
hashicorp/aws
,创建一个 json 文件(例如:terrars_aws.json
),其中包含你想要生成的规范{ "provider": "hashicorp/aws", "version": "4.48.0", "include": [ "cognito_user_pool", "cognito_user_pool_client", "cognito_user_pool_domain", "cognito_user_pool_ui_customization", "route53_zone", "route53_record", "aws_acm_certificate", "aws_acm_certificate_validation" ], "dest": "src/bin/mydeploy/tfschema/aws" }
tfschema/aws
必须是一个未使用的目录 - 当你生成代码时,它将被清除。如果include
缺失或为空,则将生成一切(或者,你可以使用exclude
来黑名单资源/数据源)。资源和数据源不包括提供商前缀(在这个例子中是aws_
)。数据源以data_
开头。 -
确保你的
PATH
中有terraform
。运行cargo install terrars
,然后运行terrars-generate terrars_aws.json
。 -
第一次这样做时,创建一个
src/bin/mydeploy/tfschema/mod.rs
文件,以作为生成提供者的根。pub mod aws;
通用用法
定义
存在包含所需参数和大多数方案项(资源、栈、变量、输出等)的 Build*
结构体,并为它们提供 build
方法。如果适用,则 build
方法会在 Stack
中注册项。可以在从 build
返回的值上设置可选参数。
表达式
背景:在 Terraform 中,无论类型如何,所有字段都可以分配一个字符串模板表达式来计算栈应用期间的值。由于所有字符串都可能作为模板,非模板字符串必须转义以避免意外的插值。
terrars
如何处理:在定义资源和调用方法时,String
和 &str
将被视为非模板字符串并适当转义。要避免转义,你可以通过 stack.str_expr
(用于生成一个评估为字符串的表达式)或 stack.expr
(用于其他表达式类型)来生成一个 PrimExpr
对象。要生成表达式体,你可以像往常一样使用 format!()
,但请注意 - 你必须在任何用于新表达式的 PrimExpr
上调用 .raw()
以避免双重转义问题。
如果 Terraform 给你一个有关文本 _TERRARS_SENTINEL*
的错误,这意味着你可能在该值上遗漏了一个 .raw()
调用(某些表达式被双重转义)。
作为一个经验法则
- 从
expression
转换到string
/field
是可以的。表达式将被转换为哨兵值并在写入模板时进行插值。 - 从
string
/field
(没有哨兵值,如字面量等)转换到expression
是可以的。 - 将包含哨兵值的
string
/field
转换到expression
是不好的。哨兵替换将发生两次,并且你会得到损坏的数据。这种情况只能发生在将表达式转换为字符串然后再转换回来时,所以不应该经常发生。
For-each
列表、集合和记录引用都有一个 .map
方法,它负责 Terraform 中的所有不同的 "for" 方法。具体来说
- 调用
.map
并定义一个资源:执行资源级别的 for-each(由于 Terraform 的限制,这不能用于从其他资源派生的列表,因此用途非常有限,你可能只是使用 for 循环) - 调用
.map
并定义一个块元素:执行块级别的 for-each - 调用
.map
并返回一个属性引用:生成一个属性for
表达式
.map
总是生成一个列表引用,但这也适用于设置字段。 .map_rec
与 .map
类似,但结果是一个记录。
原始类型的 Vec 和 map
有两个辅助宏用于生成原始值的 Vec 和 map
primvec![v, ...]
- 创建一个原始值 Vec,如果值不是原始类型,则将其转换为原始类型。用法如下:primvec!["stringone", "stringtwo"]
(比vec!["stringone".into(), "stringtwo".into()]
更简单)。primmap!{"k" = v, ...}
- 创建一个字符串到原始值的 map,如果值不是原始类型,则将其转换为原始类型。与上述类似,执行自动转换。
它的工作原理
Terraform 提供了一种方法以 json 格式输出提供者模式。此工具使用该模式生成与 Terraform 栈文件匹配的输出结构。
表达式/模板字符串/插值/转义
以一个例子为例
format!("{}{}", my_expr, verbatim_string))
此代码需要以某种方式转义模式和对 verbatim_string
,同时保留 my_expr
未转义,并且结果需要被当作“表达式”处理以防止在另一个 format!
或类似的情况下转义。这适用于不仅仅是 format!
,还包括 serde 序列化(json)、其他方法。
目前 Terrars 使用一个简单的(有些脏的)技巧来避免这个问题。所有表达式都放入一个替换表中,并使用一个哨兵字符串(例如 _TERRARS_SENTINEL_99_
)代替。在最终栈 json 序列化期间,字符串被转义,然后原始表达式文本被替换回来,替换哨兵文本。
这样,所有正常的字符串格式化方法都应该保留预期的表达式。
当前限制和警告
-
并非所有 Terraform 功能都已实现
目前我知道的缺失功能只有资源配置。
-
ignore_changes
接受字符串而不是枚举 -
没有变量或输出静态类型检查
我将来会添加一个 derive 宏来自动从结构生成变量/输出。
-
非本地部署方法
我认为这很简单,但我还没有研究。
名称
最初我叫它terrarust
,但后来我觉得这个名字听起来像恐怖分子,所以我决定稳妥起见,把u
和t
这两个字母删掉,它们代表的是虚幻竞技场(Unreal Tournament)。
依赖项
~11-22MB
~333K SLoC