Terraform позволяет воссоздавать ресурс, когда мы используем блок данных в исходных модулях

Мы сталкиваемся с проблемой зависимостей, когда используем блок данных в исходных модулях terraform. Пример: Предположим, у нас есть VPC, подсеть и Cloudwatch. Если мы вносим незначительные изменения (изменение Retention_days) в Amazon Cloudwatch приводит к воссозданию VPC и подсети. В нашем случае VPC зависит от Cloudwatch (поскольку блок cloud_watch_log_group в VPC (vpc_flow_log) требует имени CloudWatch), а подсеть зависит от VPC (из-за идентификатора vpc, используемого в подсети).

Поэтому всякий раз, когда в Cloudwatch происходят незначительные изменения, он принудительно заменяет vpc-flowlog, из-за чего vpc воссоздан, что приводит к тому, что подсеть также будет воссоздана.

Мы сталкиваемся с этой проблемой, особенно когда используем блок данных для обработки зависимости независимо от какого-либо поставщика.

Пожалуйста, дайте мне знать для получения дополнительной информации по этому вопросу.

Если мы удалим блок данных в исходных модулях, это даст ожидаемый результат. Мы также пытались обновить версии terraform и поставщика, но ничего не решило нашу проблему.

main.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/subnet/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.

Можете ли вы добавить код, который у вас есть, к вопросу?

Marko E 08.04.2024 09:36

Здесь будет полезен минимальный пример.

Chris Doyle 08.04.2024 09:59

Добавлен исходный код. Пожалуйста, дайте мне знать, если потребуется какая-либо дополнительная информация по этому поводу.

Malathi Dhandapani 08.04.2024 11:59

@MalathiDhandapani, не могли бы вы поделиться результатами плана, когда вы меняете параметр дней хранения?

Marko E 08.04.2024 13:04

Добавлены результаты плана. Не могли бы вы проверить и сообщить мне?

Malathi Dhandapani 09.04.2024 08:41
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
5
111
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Вероятно, это из-за depend_on, вам лучше использовать ссылку на выражение, просто используйте, например, вместо данных data_vpc_name, сделайте

module.vpc.vpc_name

то же самое и с облачными часами.

из документов Hashicorp:

Вам следует использовать depend_on в крайнем случае, поскольку это может привести к Терраформируйте, чтобы создавать более консервативные планы, заменяющие ресурсы, чем необходимо. Например, Terraform может обрабатывать больше значений. как неизвестное «(известно после применения)», поскольку неизвестно, какие изменения произойдет на вышестоящем объекте. Это особенно вероятно, когда вы используйте depend_on для модулей.

Вместо depend_on мы рекомендуем использовать ссылки на выражения для подразумевайте зависимости, когда это возможно. Ссылки на выражения позволяют Terraform понять, из какой ценности исходит ссылка, и избегать планирования изменяется, если это конкретное значение не изменилось, даже если другие части вышестоящего объекта запланированы изменения.

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

Другие вопросы по теме

Terraform Cloud SNS SQS подписка на перекрестную учетную запись в другом регионе произошла ошибка операции SNS: ошибка ответа GetSubscriptionAttributes https
Terraform: как передать несколько значений в качестве вывода и сопоставить их с переменными другого модуля
Terraform aws_s3_bucket_lifecycle_configuration не может удалить содержимое папки S3
Проверка правильности команды Terraform Graph конвейера сборки Azure Yaml
Настройки группы безопасности Terraform RDS
Получает ошибку в коде Azure terraform: данный сервер не поддерживает функцию частной конечной точки. пожалуйста, создайте новый сервер с поддержкой частной конечной точки
Пиринг виртуальных сетей и конечные точки служб: как разрешить взаимодействие двух служб приложений Azure
Как создать фильтр terraform для источника данных с подстановочными знаками
EKS — ошибка сервера (запрещено): пространства имен запрещены: пользователь «arn::x/xx» не может перечислить «пространства имен» ресурсов в группе API «» в области кластера
Доступ в Интернет через AWS EC2 без выделенного общедоступного IP-адреса