使用 Python 更新 terraform (.tf) 文件

Ami*_*mit 1 python terraform terraform-provider-aws

我正在尝试使用 python 更新 terraform 模板,尽管我在尝试查找模块时遇到了一些问题(例如 PyYAML 来更新 yml 文件)。

我的目标是更新 git 存储库中存在的 terraform 文件,并创建一个拉取请求,合并后将触发管道以实现更改。

示例 .tf 文件:

variable "variable_1" {}
variable "variable_2" {}

locals {
  temp_locals = 0
}

resource "aws_iam_role" "MY_AWS_ACCOUNT" {
  name = "MY_AWS_ACCOUNT"

  assume_role_policy = <<EOF
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Action": "sts:AssumeRole",
      "Condition": {
        "Bool": {
          "aws:MultiFactorAuthPresent": "true"
        }
      },
      "Principal": {
        "AWS": [
          "arn:aws:iam::<AWS_ACCOUNT_ID>:user/user.name1"
        ]
      },
      "Effect": "Allow",
      "Sid": ""
    }
  ]
}
EOF
}

resource "aws_iam_role_policy_attachment" "aws_iam_role_policy_attachment" {
}
Run Code Online (Sandbox Code Playgroud)

想在这个文件中添加 user.name2 的 arn。

Mar*_*ins 7

目前还没有可以支持对现有文件进行手术修改的 Terraform 底层语法 HCL 的 Python 实现,因为这需要保留典型 HCL 解析器不会保留的信息,例如注释和块内参数的顺序。

另一种选择是使用 Terraform 中较少使用的功能Override Files,它允许您编写一个新文件来覆盖现有文件的一部分。这种机制专为这种情况而存在,您希望使用人类编写的文件中的内容,但用机器生成的内容覆盖其中的一部分。

如果您将给定的示例代码作为 example.tf那么您可以将另一个文件放在磁盘上,并example_override.tf.json使用以下内容调用它:

{
  "resource": {
    "aws_iam_role": {
      "MY_AWS_ACCOUNT": {
        "assume_role_policy": "{\n\t\"Version\": \"2012-10-17\",\n\t\"Statement\": [\n\t  {\n\t\t\"Action\": \"sts:AssumeRole\",\n\t\t\"Condition\": {\n\t\t  \"Bool\": {\n\t\t\t\"aws:MultiFactorAuthPresent\": \"true\"\n\t\t  }\n\t\t},\n\t\t\"Principal\": {\n\t\t  \"AWS\": [\n\t\t\t\"arn:aws:iam::<AWS_ACCOUNT_ID>:user/user.name2\"\n\t\t  ]\n\t\t},\n\t\t\"Effect\": \"Allow\",\n\t\t\"Sid\": \"\"\n\t  }\n\t]\n  }"
      }
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

因为这个附加文件使用了Terraform 的替代 JSON 语法,因此很容易从具有可用 JSON 序列化程序的任何语言(包括 Python)生成。Terraform 本身将读取这两个文件,并assume_role_policy从覆盖文件中获取 覆盖基础文件中的相应文件,如合并行为中所述。然后,您可以不修改原始 HCL 文件,避免干扰该文件中面向人的格式设置决策的问题。


HCL 的 Go 实现是规范的,也是 Terraform 自己使用的,有一个包hclwrite,它是一个专门的 API,用于直接修改现有的 HCL 源代码,同时保留所有未修改的令牌及其排序。因此编写的程序Go可能会获得类似于您使用该包所寻找的结果:

{
  "resource": {
    "aws_iam_role": {
      "MY_AWS_ACCOUNT": {
        "assume_role_policy": "{\n\t\"Version\": \"2012-10-17\",\n\t\"Statement\": [\n\t  {\n\t\t\"Action\": \"sts:AssumeRole\",\n\t\t\"Condition\": {\n\t\t  \"Bool\": {\n\t\t\t\"aws:MultiFactorAuthPresent\": \"true\"\n\t\t  }\n\t\t},\n\t\t\"Principal\": {\n\t\t  \"AWS\": [\n\t\t\t\"arn:aws:iam::<AWS_ACCOUNT_ID>:user/user.name2\"\n\t\t  ]\n\t\t},\n\t\t\"Effect\": \"Allow\",\n\t\t\"Sid\": \"\"\n\t  }\n\t]\n  }"
      }
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

但是,该程序的输出确实证明了自动生成主要设计为由人类编写和阅读的语言的局限性之一:

variable "variable_1" {}
variable "variable_2" {}

locals {
  temp_locals = 0
}

resource "aws_iam_role" "MY_AWS_ACCOUNT" {
  name = "MY_AWS_ACCOUNT"

  assume_role_policy = "\n{\n\t\"Version\": \"2012-10-17\",\n\t\"Statement\": [\n\t  {\n\t\t\"Action\": \"sts:AssumeRole\",\n\t\t\"Condition\": {\n\t\t  \"Bool\": {\n\t\t\t\"aws:MultiFactorAuthPresent\": \"true\"\n\t\t  }\n\t\t},\n\t\t\"Principal\": {\n\t\t  \"AWS\": [\n\t\t\t\"arn:aws:iam::<AWS_ACCOUNT_ID>:user/user.name2\"\n\t\t  ]\n\t\t},\n\t\t\"Effect\": \"Allow\",\n\t\t\"Sid\": \"\"\n\t  }\n\t]\n  }\n"
}

resource "aws_iam_role_policy_attachment" "aws_iam_role_policy_attachment" {
}
Run Code Online (Sandbox Code Playgroud)

作为人类,我们可以做出关于如何格式化内容以提高可读性的主观决定,但hclwrite只是默认为此字符串使用引用的字符串形式,在这种情况下,这是人类作者可能不会做出的糟糕选择。