简体   繁体   English

使用 Terraform 时如何自动生成 inputs.tf 和 outputs.tf 变量?

[英]How can I auto generate inputs.tf and outputs.tf variables when working with Terraform?

Note: Please see the #### UPDATE ### section below.注意:请参阅下面的#### 更新### 部分。 I've heavily modified the question for clarity on what I'm trying to achieve, but added it as an addendum rather than rewrite the question.为了清楚地说明我要实现的目标,我对问题进行了大量修改,但将其添加为附录而不是重写问题。

As my infrastructure grows, adding input variables in my variables.tf files and then syncing those values to output variables in my outputs.tf file is now impossible to do manually.随着我的基础架构的发展,在我的 variables.tf 文件中添加输入变量,然后将这些值同步到我的 outputs.tf 文件中的 output 个变量,现在手动完成是不可能的。 Not only is it taking up a lot of unnecessary time, probably more time is spent going back and fixing the ones that terraform validate told me that I missed by human error.它不仅占用了大量不必要的时间,而且可能花费更多时间返回并修复terraform validate告诉我我因人为错误错过的那些。 This is especially true when building / using modules whose arguments add an additional layer to manage.在构建/使用其 arguments 添加额外层进行管理的模块时尤其如此。

There has to be a better way?一定有更好的方法? Here is what I want to achieve.这就是我想要实现的目标。

Let's say I'm creating an Azure AKS Kube.netes cluster.假设我正在创建一个 Azure AKS Kube.netes 集群。 The Terraform resource is azurerm_kube.netes_cluster. Terraform 资源azurerm_kube.netes_cluster.

Only 8 arguments are required to create a base install, but there are almost 250 additional ones.创建基本安装只需要 8 个 arguments,但还有将近 250 个。 They all have default values.它们都有默认值。 Per the documentation page, they also already have fantastic descriptions.根据文档页面,他们也已经有了精彩的描述。 (I'm tired of copying and pasting into my variables { description = "this"} block.) (我厌倦了复制和粘贴到我的variables { description = "this"}块。)

The information is there in the documentation.该信息在文档中。 terraform plan also has knowledge of every single additional one because it of course comes up in the pre-apply plan. terraform plan也了解每一个额外的计划,因为它当然会出现在预申请计划中。 (known after apply) means its optional, but will have a default value. (应用后已知)意味着它是可选的,但会有一个默认值。

In my dream world, I'd run this hypothetical command sequence:在我的梦想世界中,我会运行这个假设的命令序列:

  • terraform plan
  • terraform document <- Here it auto generates every argument as a variables block and inserts it into variables.tf. terraform document <-这里它自动生成每个参数作为变量块并将其插入到 variables.tf 中。 It also auto generates every possible output "out_putable" {} block and inserts it into outputs.tf.它还会自动生成每个可能的output "out_putable" {}块并将其插入到 outputs.tf 中。
  • terraform apply -update-inputs -update-outputs <- Here everything that was optional (known after apply) is now known and it should auto update variables.tf and outputs.tf accordingly. terraform apply -update-inputs -update-outputs <-这里所有可选的(应用后已知的)现在都是已知的,它应该相应地自动更新 variables.tf 和 outputs.tf。 Adding a -update-modules flag lets it take care of that additional layer introduced by using modules.添加一个-update-modules标志可以让它处理通过使用模块引入的附加层。

This feels like a problem that has been addressed before.这感觉像是一个以前已经解决过的问题。 Before I write a custom tool that parses Terraform web docs and the output of terraform show , is there already a way to do this?在我编写一个自定义工具来解析 Terraform web 文档和terraform show的 output 之前,是否已经有办法做到这一点? Terraform-docs is the closest I've come to finding a solution for README.md. Terraform-docs是我找到的最接近 README.md 的解决方案。 If it can do what I need, I haven't figure it out yet.如果它能满足我的需要,我还没有弄清楚。

How can I automate all this?我怎样才能使这一切自动化?

############ UPDATE ############ ############更新############

This article and video is spot-on when it comes to Terraform's evolution in an organization.当谈到 Terraform 在组织中的演变时, 这篇文章和视频恰到好处。 My organization is somewhere between late-stage pattern 3 and early 5. As we decompose our "Terralith" we have inconsistencies among teams (patterns, naming conventions, variable and argument choices etc).我的组织介于后期模式 3 和早期模式 5 之间。当我们分解我们的“Terralith”时,我们在团队之间存在不一致(模式、命名约定、变量和参数选择等)。 These are starting to cause errors in CI/CD forcing a ticket-review process that is slowing things down.这些开始导致 CI/CD 中的错误,迫使一个正在减慢速度的票证审查过程。

All resources have required and optional arguments. But in my organization, we have, for example, additional optional arguments that are required for us.所有资源都有必需和可选的 arguments。但在我的组织中,例如,我们需要额外的可选 arguments。

Scenario: Dev A in Japan creates a resource, forgets an optional variable or two or names them something obscure, etc. Dev B in America is blocked until they can convene and discuss.场景:日本的开发人员 A 创建了一个资源,忘记了一个或两个可选变量或给它们命名了一些晦涩的东西,等等。美国的开发人员 B 被阻止,直到他们可以召集和讨论。 Given time zones, language differences, ticket review, this one issue is now a week or more delayed.考虑到时区、语言差异、票务审查,这一期现在延迟了一周或更长时间。

I need to automate this and create exact consistency so that Dev A starts out with exactly what Dev B would start with or is expecting;我需要自动执行此操作并创建精确的一致性,以便开发人员 A 以开发人员 B 开始或期望的内容开始; and, what CI/CD tests are expecting - templating the initial process, if you will.以及 CI/CD 测试所期望的——如果您愿意,可以对初始过程进行模板化。 In other words, I need to remove the human element of manually creating main.tf , variables.tf , outputs.tf , etc.换句话说,我需要删除手动创建main.tfvariables.tfoutputs.tf等的人为因素。

Here are thoughts on how to achieve this:以下是关于如何实现这一目标的想法:

  • Use Golang to autogenerate the files by querying the API How can I query the API to get a list of all required arguments for a specific resource?使用 Golang 通过查询 API 自动生成文件我如何查询 API 以获得特定资源required的所有 arguments 的列表?

I found that I can query for provider information , but I can't find info to retrieve resource information.我发现我可以查询提供者信息,但是我找不到信息来检索资源信息。 My thinking is when a developer wants to create a new resource, He'll run a go or typescript to generate the manifest files along with expected naming conventions, and populate main.tf, variables.tf, outputs.tf, etc, with exactly what data that everyone is expecting.我的想法是,当开发人员想要创建新资源时,他将运行 go 或 typescript 来生成清单文件以及预期的命名约定,并准确填充 main.tf、variables.tf、outputs.tf 等每个人都期待什么数据。 I'm looking form something like curl registry.terraform.io/providers/hashicorp/azurerm/v2.99/resource_group?required=yes This should show me all required arguments along with descriptions and other info I can use straight from the API.我正在寻找类似curl registry.terraform.io/providers/hashicorp/azurerm/v2.99/resource_group?required=yes这样的表格,这应该会向我显示所有必需的 arguments 以及我可以直接从 API 中使用的描述和其他信息。

  • Use CDKTF to generate an HCL manifest.tf file from JSON How can I use CDKTF to generate an HCL .tf file?使用 CDKTF 从 JSON 生成 HCL manifest.tf 文件如何使用CDKTF 生成 HCL .tf文件? CDKTF is EXACTLY what I'm looking for - except in reverse. CDKTF 正是我正在寻找的东西 - 除了相反。 HCL is seamlessly compatible with JSON. Running cdktf synth creates ./out/cdk.tf.out I'm so close! HCL与JSON无缝兼容。运行cdktf synth创建./out/cdk.tf.out我太接近了! How do I turn that file into main.tf???我如何将该文件转换为 main.tf???

The goal here is to have a master file from which all future manifest files are derived.这里的目标是拥有一个主文件,所有未来的清单文件都从中派生。 Whether we use azurerm_kube.netes_cluster 1 time or 1000 times, I know for certain that every argument, every variable name, every desired output is exactly the same.无论我们使用azurerm_kube.netes_cluster 1 次还是 1000 次,我都可以肯定地知道每个参数、每个变量名、每个所需的 output 都是完全相同的。 If a chance is needed in our desired structure, it will be updated at the JSON level, and CI/CD can ensure those changes are propagated across instances of its use.如果我们想要的结构需要一个机会,它将在 JSON 级别更新,并且 CI/CD 可以确保这些更改在其使用实例中传播。

I know that I can use the cdk.out.tf file as a drop in replacement for a module, but I don't want my team members to have to learn typescript or how to read json. If I can create a templatized JSON file containing exactly what I'm expecting users to start with, and if they can run some command like cdktf convert cdk.tf.out --HCL output-file.tf then I've accomplished my goal.我知道我可以使用cdk.out.tf文件作为模块的替代品,但我不希望我的团队成员必须学习 typescript 或如何阅读 json。如果我可以创建一个模板化的 JSON 文件包含我期望用户开始使用的内容,如果他们可以运行一些命令,如cdktf convert cdk.tf.out --HCL output-file.tf那么我就完成了我的目标。

If cdktf synth can create an HCL JSON file, and cdktf convert can take a manifest.tf file and turn it into HCL JSON, can't it do the exact opposite ?如果cdktf synth可以创建一个 HCL JSON 文件,而cdktf convert可以获取一个 manifest.tf 文件并将其转换为 HCL JSON,它不能做完全相反的事情吗? Turn the HCL JSON file into the human-readable, declarative, manifest.tf file?将 HCL JSON 文件转换为人类可读的声明性 manifest.tf 文件?

Perhaps think of it this way.或许可以这样想。 Terraform has a required file structure for a module if it's to be allowed into the module registry. Terraform 具有模块所需的文件结构,如果它被允许进入模块注册表。 I'm trying to create a similar required structure for each of the resources our organization uses regardless of when and where it's used.我正在尝试为我们组织使用的每个资源创建一个类似的必需结构,而不管它是在何时何地使用的。

If your goal is to derive input variables and output values from resource type schemas then Terraform can provide you with the information to do so.如果您的目标是从资源类型模式派生输入变量和 output 值,那么 Terraform 可以为您提供这样做的信息。

In the working directory of a configuration that already uses the provider whose resource type you want to use, run the following command:在已使用您要使用其资源类型的提供程序的配置的工作目录中,运行以下命令:

terraform providers schema -json

The result contains a JSON description of all of the resource types available in the providers for the current configuration, and for each one the metadata about its attributes, including the type constraint information and descriptions for each one.结果包含JSON 对当前配置提供程序中可用的所有资源类型的描述,以及每个资源类型的有关其属性的元数据,包括类型约束信息和每个资源的描述。

From that you can generate whatever other files you need based on that information.从中您可以根据该信息生成您需要的任何其他文件。


Note that if you are intending to build modules which export the entire surface area (all inputs and all outputs) of a particular resource type the Terraform documentation explicitly recommends against this , suggesting to just use the resource type directly instead since such a module would often not offer sufficient benefit to outweigh the additional complexity and maintenance overhead it implies:请注意,如果您打算构建导出特定资源类型的整个表面积(所有输入和所有输出)的模块, Terraform 文档明确建议不要这样做,建议直接使用资源类型,因为这样的模块通常会没有提供足够的好处来抵消它所暗示的额外复杂性和维护开销:

In principle any combination of resources and other constructs can be factored out into a module, but over-using modules can make your overall Terraform configuration harder to understand and maintain, so we recommend moderation.原则上,资源和其他构造的任何组合都可以分解为一个模块,但过度使用模块会使您的整体 Terraform 配置更难理解和维护,因此我们建议适度。

A good module should raise the level of abstraction by describing a new concept in your architecture that is constructed from resource types offered by providers.一个好的模块应该通过在您的体系结构中描述一个新概念来提高抽象级别,该概念是由提供者提供的资源类型构建的。

For example, aws_instance and aws_elb are both resource types belonging to the AWS provider.例如,aws_instance 和 aws_elb 都是属于 AWS 提供商的资源类型。 You might use a module to represent the higher-level concept " HashiCorp Consul cluster running in AWS" which happens to be constructed from these and other AWS provider resources.您可能会使用一个模块来表示更高级别的概念“在 AWS 中运行的HashiCorp Consul集群”,它恰好是由这些和其他 AWS 提供商资源构建的。

We do not recommend writing modules that are just thin wrappers around single other resource types.我们建议编写只是围绕单个其他资源类型的薄包装器的模块。 If you have trouble finding a name for your module that isn't the same as the main resource type inside it, that may be a sign that your module is not creating any new abstraction and so the module is adding unnecessary complexity.如果您在为您的模块找到一个与其中的主要资源类型不同的名称时遇到困难,这可能表明您的模块没有创建任何新的抽象,因此该模块增加了不必要的复杂性。 Just use the resource type directly in the calling module instead.只需在调用模块中直接使用资源类型即可。

I've got the same question and develop a small bash script to create output definitions based on module code我有同样的问题并开发了一个小的 bash 脚本来创建基于模块代码的 output 定义

This code required the hcledit tool to extract blocks from hcl code此代码需要hcledit工具从 hcl 代码中提取块

#!/usr/bin/env bash

set -o pipefail

_hcledit=$(which hcledit)


for tf_file in $(ls *.tf); do
    cat $tf_file | $_hcledit block list | while read line; do
        block_type="${line%%.*}"
        line="${line#*.}"
        case $block_type in
            locals|output|variable|data) continue; break ;;
            module)
                output_name=$line 
                output_description="Module '$output_name' attributes"
                output_value="$block_type.$output_name"
                ;;
            resource)
                label_kind="${line%.*}"
                label_name="${line#*.}"
                output_name="${label_kind}_${label_name//[\-]/_}"
                output_description="Resource '$label_kind.$label_name' attributes"
                output_value="$label_kind.$label_name"
                ;;
        esac
        
        cat <<-EOT

output "$output_name" {
    description = "$output_description"
    value       = $output_value
}
EOT
    done
done

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM