当我们在源模块中使用数据块时,Terraform 会重新创建资源

问题描述 投票:0回答:1

当我们在 terraform 的源模块中使用数据块时,我们遇到了依赖问题。 例子: 考虑我们有 VPC、子网和 Cloudwatch - 如果我们要进行细微更改 Amazon Cloudwatch 中的(更改retention_days)会导致重新创建VPC 和子网。 在我们的例子中,VPC 取决于 Cloudwatch(因为 VPC(vpc_flow_log) 中的 cloud_watch_log_group 块需要 cloudwatch 名称),而子网取决于 VPC(由于子网中使用的 vpc id)。

因此,每当 Cloudwatch 发生微小变化时,它都会强制替换 vpc-flowlog,因为 vpc 是 重新创建,这使得子网也被重新创建。

特别是当我们使用数据块来处理依赖关系时,无论任何提供者如何,我们都会面临这个问题。

请让我知道有关此问题的更多详细信息。

如果我们删除源模块中的数据块,那么它会产生预期的结果。 我们也尝试升级 terraform 和提供程序版本,但没有解决我们的问题。

主.tf

module "cloudwatch" {
  for_each = var.Amazon_CloudWatch
  source   = "./source_modules/cloudwatch"

  cloud_watch_group_name = each.value["cloud_watch_group_name"]
  retention_days         = each.value["retention_days"]
}

module "vpc" {
  for_each = var.AWS_VPC_Virtual_Private_Cloud
  source   = "./source_modules/vpc"

  vpc_name              = each.value["vpc_name"]
  data_cloud_watch_name = each.value["data_cloud_watch_name"]
  vpc_cidr              = each.value["vpc_cidr"]

  depends_on = [module.cloudwatch]
}

module "subnet" {
  for_each = var.AWS_Subnet
  source   = "./source_modules/subnet"

  subnet_cidr   = each.value["subnet_cidr"]
  subnet_name   = each.value["subnet_name"]
  data_vpc_name = each.value["data_vpc_name"]

  depends_on=[module.vpc]
}

source_modules/vpc/main.tf

resource "aws_vpc" "main" {
  cidr_block = var.vpc_cidr

  tags = {
    Name = var.vpc_name
  }
}

resource "aws_iam_role" "example" {
  name               = "example111"
  assume_role_policy = data.aws_iam_policy_document.assume_role.json
}

resource "aws_iam_role_policy" "example" {
  name   = "example111"
  role   = aws_iam_role.example.id
  policy = data.aws_iam_policy_document.example.json
}

resource "aws_flow_log" "example" {
  iam_role_arn    = aws_iam_role.example.arn
  log_destination = data.aws_cloudwatch_log_group.test_clg.arn
  traffic_type    = "ALL"
  vpc_id          = aws_vpc.main.id
}

source_modules/vpc/variables.tf

variable "data_cloud_watch_name" {
  type = string
}

variable "vpc_name" {
  type = string
}

variable "vpc_cidr" {
  type = string
}

source_modules/vpc/data.tf

data "aws_cloudwatch_log_group" "test_clg" {
  name = var.data_cloud_watch_name
}

data "aws_iam_policy_document" "assume_role" {
  statement {
    effect = "Allow"
    principals {
      type        = "Service"
      identifiers = ["vpc-flow-logs.amazonaws.com"]
    }
    
    actions = ["sts:AssumeRole"]
  }
}

data "aws_iam_policy_document" "example" {
  statement {
    effect = "Allow"
    actions = [
      "logs:CreateLogGroup",
      "logs:CreateLogStream",
      "logs:PutLogEvents",
      "logs:DescribeLogGroups",
      "logs:DescribeLogStreams",
    ]
    resources = ["*"]
  }
}

source_modules/子网/main.tf

resource "aws_subnet" "main" {
  vpc_id     = data.aws_vpc.vpcid.id
  cidr_block = var.subnet_cidr
    
  tags = {
    Name = var.subnet_name
  }
}

source_modules/子网/data.tf

data "aws_vpc" "vpcid" {
  tags = {
    Name=var.data_vpc_name
  }
}

source_modules/子网/variables.tf

variable "subnet_cidr" {
  type = string
}
    
variable "subnet_name" {
  type = string
}

variable "data_vpc_name" {
  type = string
}

source_modules/cloudwatch/main.tf

resource "aws_cloudwatch_log_group" "test" {
  name              = var.cloud_watch_group_name
  retention_in_days = var.retention_days
}

source_modules/cloudwatch/variables.tf

variable "cloud_watch_group_name" {
  type = string
}

variable "retention_days" {
  type = number
}
**Terraform Plan Results**
terraform plan 
module.cloudwatch["logging_01"].aws_cloudwatch_log_group.test: Refreshing state... [id=testdataissuecwg1211q]
module.vpc["vpc_01"].aws_vpc.main: Refreshing state... [id=vpc-0dba4643e6f19061a]
module.vpc["vpc_01"].aws_iam_role.example: Refreshing state... [id=stackissue1qw]
module.vpc["vpc_01"].aws_iam_role_policy.example: Refreshing state... [id=stackissue1qw:stackissue1qw]
module.vpc["vpc_01"].aws_flow_log.example: Refreshing state... [id=fl-0bf918ffe07281dd4]
module.subnet["subnet_01"].aws_subnet.main: Refreshing state... [id=subnet-0ec569f1c4cb9ef15]

Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the
following symbols:
  ~ update in-place
-/+ destroy and then create replacement
 <= read (data resources)

Terraform will perform the following actions:

  # module.cloudwatch["logging_01"].aws_cloudwatch_log_group.test will be updated in-place
  ~ resource "aws_cloudwatch_log_group" "test" {
        id                = "testdataissuecwg1211q"
        name              = "testdataissuecwg1211q"
      ~ retention_in_days = 30 -> 60
        tags              = {}
        # (4 unchanged attributes hidden)
    }

  # module.subnet["subnet_01"].data.aws_vpc.vpcid will be read during apply
  # (depends on a resource or a module with changes pending)
 <= data "aws_vpc" "vpcid" {
      + arn                                  = (known after apply)
      + cidr_block                           = (known after apply)
      + cidr_block_associations              = (known after apply)
      + default                              = (known after apply)
      + dhcp_options_id                      = (known after apply)
      + enable_dns_hostnames                 = (known after apply)
      + enable_dns_support                   = (known after apply)
      + enable_network_address_usage_metrics = (known after apply)
      + id                                   = (known after apply)
      + instance_tenancy                     = (known after apply)
      + ipv6_association_id                  = (known after apply)
      + ipv6_cidr_block                      = (known after apply)
      + main_route_table_id                  = (known after apply)
      + owner_id                             = (known after apply)
      + state                                = (known after apply)
      + tags                                 = {
          + "Name" = "testvpc0111"
        }
    }

  # module.subnet["subnet_01"].aws_subnet.main must be replaced
-/+ resource "aws_subnet" "main" {
      ~ arn                                            = "arn:aws:ec2:us-east-1:************:subnet/subnet-0ec569f1c4cb9ef15" -> (known after apply)
      ~ availability_zone                              = "us-east-1c" -> (known after apply)
      ~ availability_zone_id                           = "use1-az4" -> (known after apply)
      - enable_lni_at_device_index                     = 0 -> null
      ~ id                                             = "subnet-0ec569f1c4cb9ef15" -> (known after apply)
      + ipv6_cidr_block_association_id                 = (known after apply)
      - map_customer_owned_ip_on_launch                = false -> null
      ~ owner_id                                       = "************" -> (known after apply)
      ~ private_dns_hostname_type_on_launch            = "ip-name" -> (known after apply)
        tags                                           = {
            "Name" = "testdatasnet1"
        }
      ~ vpc_id                                         = "vpc-0dba4643e6f19061a" # forces replacement -> (known after apply) # 
forces replacement
        # (8 unchanged attributes hidden)
    }

  # module.vpc["vpc_01"].data.aws_cloudwatch_log_group.test_clg will be read during apply
  # (depends on a resource or a module with changes pending)
 <= data "aws_cloudwatch_log_group" "test_clg" {
      + arn               = (known after apply)
      + creation_time     = (known after apply)
      + id                = (known after apply)
      + kms_key_id        = (known after apply)
      + log_group_class   = (known after apply)
      + name              = "testdataissuecwg1211q"
      + retention_in_days = (known after apply)
      + tags              = (known after apply)
    }

  # module.vpc["vpc_01"].data.aws_iam_policy_document.assume_role will be read during apply
  # (depends on a resource or a module with changes pending)
 <= data "aws_iam_policy_document" "assume_role" {
      + id   = (known after apply)
      + json = (known after apply)

      + statement {
          + actions = [
              + "sts:AssumeRole",
            ]
          + effect  = "Allow"

          + principals {
              + identifiers = [
                  + "vpc-flow-logs.amazonaws.com",
                ]
              + type        = "Service"
            }
        }
    }

  # module.vpc["vpc_01"].data.aws_iam_policy_document.example will be read during apply
  # (depends on a resource or a module with changes pending)
 <= data "aws_iam_policy_document" "example" {
      + id   = (known after apply)
      + json = (known after apply)

      + statement {
          + actions   = [
              + "logs:CreateLogGroup",
              + "logs:CreateLogStream",
              + "logs:DescribeLogGroups",
              + "logs:DescribeLogStreams",
              + "logs:PutLogEvents",
            ]
          + effect    = "Allow"
          + resources = [
              + "*",
            ]
        }
    }

  # module.vpc["vpc_01"].aws_flow_log.example must be replaced
-/+ resource "aws_flow_log" "example" {
      ~ arn                      = "arn:aws:ec2:us-east-1:************:vpc-flow-log/fl-0bf918ffe07281dd4" -> (known after apply)
      ~ id                       = "fl-0bf918ffe07281dd4" -> (known after apply)
      ~ log_destination          = "arn:aws:logs:us-east-1:************:log-group:testdataissuecwg1211q" # forces replacement -> (known after apply) # forces replacement
      ~ log_format               = "${version} ${account-id} ${interface-id} ${srcaddr} ${dstaddr} ${srcport} ${dstport} ${protocol} ${packets} ${bytes} ${start} ${end} ${action} ${log-status}" -> (known after apply)
      ~ log_group_name           = "testdataissuecwg1211q" -> (known after apply)
      - tags                     = {} -> null
      ~ tags_all                 = {} -> (known after apply)
        # (5 unchanged attributes hidden)
    }

  # module.vpc["vpc_01"].aws_iam_role.example will be updated in-place
  ~ resource "aws_iam_role" "example" {
      ~ assume_role_policy    = jsonencode(
            {
              - Statement = [
                  - {
                      - Action    = "sts:AssumeRole"
                      - Effect    = "Allow"
                      - Principal = {
                          - Service = "vpc-flow-logs.amazonaws.com"
                        }
                    },
                ]
              - Version   = "2012-10-17"
            }
        ) -> (known after apply)
        id                    = "stackissue1qw"
        name                  = "stackissue1qw"
        tags                  = {}
        # (8 unchanged attributes hidden)

        # (1 unchanged block hidden)
    }

  # module.vpc["vpc_01"].aws_iam_role_policy.example will be updated in-place
  ~ resource "aws_iam_role_policy" "example" {
        id     = "stackissue1qw:stackissue1qw"
        name   = "stackissue1qw"
      ~ policy = jsonencode(
            {
              - Statement = [
                  - {
                      - Action   = [
                          - "logs:PutLogEvents",
                          - "logs:DescribeLogStreams",
                          - "logs:DescribeLogGroups",
                          - "logs:CreateLogStream",
                          - "logs:CreateLogGroup",
                        ]
                      - Effect   = "Allow"
                      - Resource = "*"
                    },
                ]
              - Version   = "2012-10-17"
            }
        ) -> (known after apply)
        # (1 unchanged attribute hidden)
    }

Plan: 2 to add, 3 to change, 2 to destroy.
amazon-web-services terraform terraform-provider-aws
1个回答
0
投票

可能是depends_on的原因,你最好使用表达式引用,只需使用 example 代替数据 data_vpc_name 即可

module.vpc.vpc_name

云手表也一样。

来自 Hashicorp 文档:

您应该使用depends_on作为最后的手段,因为它可能会导致 Terraform 创建更保守的计划来取代更多 资源超出必要。例如,Terraform 可能会处理更多值 为未知“(应用后已知)”,因为不确定发生了什么变化 将发生在上游对象上。当您 对模块使用depends_on。

我们建议使用表达式引用来代替depends_on 尽可能暗示依赖关系。表达式引用让 Terraform 了解参考值源自哪个值并避免计划 如果该特定值没有改变,即使其他部分也没有改变 上游对象已计划更改。

https://developer.hashicorp.com/terraform/language/meta-arguments/depends_on

© www.soinside.com 2019 - 2024. All rights reserved.