Импорт Terraform (0.12.29) работает не так, как ожидалось; импорт выполнен успешно, но в плане показано уничтожение и воссоздание

#amazon-web-services #import #terraform #terraform-provider-aws #terraform0.12

#amazon-web-services #импорт #terraform #terraform-provider-aws #terraform0.12

Вопрос:

Некоторая информация: у нас есть код terraform для создания различных ресурсов AWS. Некоторые из этих ресурсов создаются для каждой учетной записи AWS и, следовательно, структурированы для хранения в account-scope папке в нашем проекте. Это было, когда у нас был только один регион AWS. Теперь наше приложение сделано мультирегиональным, и, следовательно, эти ресурсы должны создаваться для каждого региона для каждой учетной записи AWS.

Для этого мы переместили эти сценарии TF в region-scope папку, которая будет выполняться для каждого региона. Поскольку эти ресурсы больше не являются частью «области действия учетной записи», мы удалили их из состояния Terraform области действия учетной записи. Теперь, когда я пытаюсь импортировать эти ресурсы

Импортировал ресурсы, запустив это из xyz-region-scope каталога:

 terraform import -var-file=config/us-west-2/default.tfvars -var-file=variables.tfvars -var-file=../globals.tfvars -var profile=xyz-stage -var region=us-west-2 -var tfstate_bucket=ab-xyz-stage-tfstate-5b8873b8 -no-color <RESOURCE_NAME> <RESOURCE_ID>
  

Одним из примеров ресурса является:

 RESOURCE_NAME=module.buckets.aws_s3_bucket.cloudtrail_logging_bucket 
RESOURCE_ID="ab-xyz-stage-cloudtrail-logging-72a2c5cd"
  

Я ожидал, что импорт обновит ресурсы в файле состояния terraform на моем локальном компьютере, но созданный файл состояния terraform xyz-region-scope/state/xyz-stage/terraform.tfstate не обновляется.

Проверил импорт с помощью:

 terraform show
  

Запустите план terraform:

 terraform plan -var-file=config/us-west-2/default.tfvars -var-file=variables.tfvars -var-file=../globals.tfvars -var profile=xyz-stage -var region=us-west-2 -var tfstate_bucket=ab-xyz-stage-tfstate-5b8873b8 -no-color
  

Но вывод плана terraform показывает Plan: 6 to add, 0 to change, 5 to destroy. , что эти ресурсы будут уничтожены и воссозданы.

Я не понимаю, почему так, я что-то упускаю и не делаю это правильно?

Пожалуйста, обратите внимание, что мы храним удаленное состояние в корзине S3, но в настоящее время у меня нет файла состояния удаленного TF, созданного в корзине S3 для области региона (хотя у меня есть один для области учетной записи). Я ожидал, что Import..Plan..Apply процесс также создаст его для области области.

РЕДАКТИРОВАТЬ: я вижу файл состояния удаленного TF, созданный в области S3 для региона после запуска импорта. Одно из различий, которое я вижу между этим новым файлом состояния tf с областью видимости из старой учетной записи, заключается в том, что в новом файле нет "depends_on" блока ни под одним из ресурсов resources[] > instances[]

Окружающая среда:

 Local machine: macOS v10.14.6

Terraform v0.12.29
  provider.aws v3.14.1
  provider.null v2.1.2
  provider.random v2.3.1
  provider.template v2.1.2
  


РЕДАКТИРОВАТЬ 2:

Вот мой импорт и план терраформирования:

 terraform import module.buckets.random_id.cloudtrail_bucket_suffix cqLFzQ
terraform import module.buckets.aws_s3_bucket.cloudtrail_logging_bucket "ab-xyz-stage-cloudtrail-logging-72a2c5cd"
terraform import  module.buckets.aws_s3_bucket_policy.cloudtrail_logging_bucket "ab-xyz-stage-cloudtrail-logging-72a2c5cd"
terraform import  module.buckets.module.access_logging_bucket.aws_s3_bucket.default "ab-xyz-stage-access-logging-9d8e94ff"
terraform import  module.buckets.module.access_logging_bucket.random_id.bucket_suffix  nY6U_w
terraform import module.encryption.module.data_key.aws_iam_policy.decrypt "arn:aws:iam::123412341234:policy/ab_data_key_xyz_stage_decrypt"
terraform import module.encryption.module.data_key.aws_iam_policy.encrypt "arn:aws:iam::123412341234:policy/ab_data_key_xyz_stage_encrypt"



mymachine:xyz-region-scope kuldeepjain$ ../scripts/terraform.sh xyz-stage plan -no-color
  set -o posix
  IFS='
    '
   blhome
  BASH_LIB_HOME=/usr/local/lib/mycompany/ab/bash_library/0.0.1-SNAPSHOT
  source /usr/local/lib/mycompany/ab/bash_library/0.0.1-SNAPSHOT/s3/bucket.sh
  main xyz-stage plan -no-color
  '[' 3 -lt 2 ']'
  local env=xyz-stage
  shift
  local command=plan
  shift
   get_region xyz-stage
   local env=xyz-stage
   shift
    aws --profile xyz-stage configure get region
   local region=us-west-2
   '[' -z us-west-2 ']'
   echo us-west-2
  local region=us-west-2
   _get_bucket xyz-stage xyz-stage-tfstate
   local env=xyz-stage
   shift
   local name=xyz-stage-tfstate
   shift
    _get_bucket_list xyz-stage xyz-stage-tfstate
    local env=xyz-stage
    shift
    local name=xyz-stage-tfstate
    shift
    aws --profile xyz-stage --output json s3api list-buckets --query 'Buckets[?contains(Name, `xyz-stage-tfstate`) == `true`].Name'
   local 'bucket_list=[
    "ab-xyz-stage-tfstate-5b8873b8"
]'
    _count_buckets_in_json '[
    "ab-xyz-stage-tfstate-5b8873b8"
]'
    local 'json=[
    "ab-xyz-stage-tfstate-5b8873b8"
]'
    shift
    echo '[
    "ab-xyz-stage-tfstate-5b8873b8"
]'
    jq '. | length'
   local number_of_buckets=1
   '[' 1 == 0 ']'
   '[' 1 -gt 1 ']'
    echo '[
    "ab-xyz-stage-tfstate-5b8873b8"
]'
    jq -r '.[0]'
   local bucket_name=ab-xyz-stage-tfstate-5b8873b8
   echo ab-xyz-stage-tfstate-5b8873b8
  local tfstate_bucket=ab-xyz-stage-tfstate-5b8873b8
   get_config_file xyz-stage us-west-2
   local env=xyz-stage
   shift
   local region=us-west-2
   shift
   local config_file=config/us-west-2/xyz-stage.tfvars
   '[' '!' -f config/us-west-2/xyz-stage.tfvars ']'
   config_file=config/us-west-2/default.tfvars
   echo config/us-west-2/default.tfvars
  local config_file=config/us-west-2/default.tfvars
  export TF_DATA_DIR=state/xyz-stage/
  TF_DATA_DIR=state/xyz-stage/
  terraform get
  terraform plan -var-file=config/us-west-2/default.tfvars -var-file=variables.tfvars -var-file=../globals.tfvars -var profile=xyz-stage -var region=us-west-2 -var tfstate_bucket=ab-xyz-stage-tfstate-5b8873b8 -no-color
Refreshing Terraform state in-memory prior to plan...
The refreshed state will be used to calculate this plan, but will not be
persisted to local or remote state storage.

module.encryption.module.data_key.data.null_data_source.key: Refreshing state...
module.buckets.data.template_file.dependencies: Refreshing state...
module.buckets.module.access_logging_bucket.data.template_file.dependencies: Refreshing state...
module.encryption.module.data_key.data.aws_region.current: Refreshing state...
module.buckets.module.access_logging_bucket.data.aws_caller_identity.current: Refreshing state...
data.aws_caller_identity.current: Refreshing state...
module.buckets.module.access_logging_bucket.data.aws_kms_alias.encryption_key_alias: Refreshing state...
module.buckets.data.aws_caller_identity.current: Refreshing state...
module.encryption.module.data_key.data.aws_caller_identity.current: Refreshing state...
module.encryption.module.data_key.data.aws_kms_alias.default: Refreshing state...
module.buckets.module.access_logging_bucket.data.template_file.encryption_configuration: Refreshing state...
module.encryption.module.data_key.data.aws_iam_policy_document.decrypt: Refreshing state...
module.encryption.module.data_key.data.aws_iam_policy_document.encrypt: Refreshing state...
module.buckets.module.access_logging_bucket.random_id.bucket_suffix: Refreshing state... [id=nY6U_w]
module.encryption.module.data_key.aws_iam_policy.decrypt: Refreshing state... [id=arn:aws:iam::123412341234:policy/ab_data_key_xyz_stage_decrypt]
module.encryption.module.data_key.aws_iam_policy.encrypt: Refreshing state... [id=arn:aws:iam::123412341234:policy/ab_data_key_xyz_stage_encrypt]
module.buckets.module.access_logging_bucket.aws_s3_bucket.default: Refreshing state... [id=ab-xyz-stage-access-logging-9d8e94ff]
module.buckets.random_id.cloudtrail_bucket_suffix: Refreshing state... [id=cqLFzQ]
module.buckets.aws_s3_bucket.cloudtrail_logging_bucket: Refreshing state... [id=ab-xyz-stage-cloudtrail-logging-72a2c5cd]
module.buckets.data.aws_iam_policy_document.restrict_access_cloudtrail: Refreshing state...
module.buckets.aws_s3_bucket_policy.cloudtrail_logging_bucket: Refreshing state... [id=ab-xyz-stage-cloudtrail-logging-72a2c5cd]

------------------------------------------------------------------------

An execution plan has been generated and is shown below.
Resource actions are indicated with the following symbols:
    create
-/  destroy and then create replacement
 <= read (data resources)

Terraform will perform the following actions:

  # module.buckets.data.aws_iam_policy_document.restrict_access_cloudtrail will be read during apply
  # (config refers to values not yet known)
 <= data "aws_iam_policy_document" "restrict_access_cloudtrail"  {
        id   = (known after apply)
        json = (known after apply)

        statement {
            actions   = [
                "s3:GetBucketAcl",
            ]
            effect    = "Allow"
            resources = [
                (known after apply),
            ]
            sid       = "AWSCloudTrailAclCheck"

            principals {
                identifiers = [
                    "cloudtrail.amazonaws.com",
                ]
                type        = "Service"
            }
        }
        statement {
            actions   = [
                "s3:PutObject",
            ]
            effect    = "Allow"
            resources = [
                (known after apply),
            ]
            sid       = "AWSCloudTrailWrite"

            condition {
                test     = "StringEquals"
                values   = [
                    "bucket-owner-full-control",
                ]
                variable = "s3:x-amz-acl"
            }

            principals {
                identifiers = [
                    "cloudtrail.amazonaws.com",
                ]
                type        = "Service"
            }
        }
    }

  # module.buckets.aws_s3_bucket.cloudtrail_logging_bucket must be replaced
-/  resource "aws_s3_bucket" "cloudtrail_logging_bucket" {
        acceleration_status         = (known after apply)
        acl                         = "private"
      ~ arn                         = "arn:aws:s3:::ab-xyz-stage-cloudtrail-logging-72a2c5cd" -> (known after apply)
      ~ bucket                      = "ab-xyz-stage-cloudtrail-logging-72a2c5cd" -> (known after apply) # forces replacement
      ~ bucket_domain_name          = "ab-xyz-stage-cloudtrail-logging-72a2c5cd.s3.amazonaws.com" -> (known after apply)
      ~ bucket_regional_domain_name = "ab-xyz-stage-cloudtrail-logging-72a2c5cd.s3.us-west-2.amazonaws.com" -> (known after apply)
        force_destroy               = false
      ~ hosted_zone_id              = "Z3BJ6K6RIION7M" -> (known after apply)
      ~ id                          = "ab-xyz-stage-cloudtrail-logging-72a2c5cd" -> (known after apply)
      ~ region                      = "us-west-2" -> (known after apply)
      ~ request_payer               = "BucketOwner" -> (known after apply)
        tags                        = {
            "mycompany:finance:accountenvironment"   = "xyz-stage"
            "mycompany:finance:application"          = "ab-platform"
            "mycompany:finance:billablebusinessunit" = "my-dev"
            "name"                                = "Cloudtrail logging bucket"
        }
        website_domain              = (known after apply)
        website_endpoint            = (known after apply)

      ~ lifecycle_rule {
          - abort_incomplete_multipart_upload_days = 0 -> null
            enabled                                = true
          ~ id                                     = "intu-lifecycle-s3-int-tier" -> (known after apply)
          - tags                                   = {} -> null

            transition {
                days          = 32
                storage_class = "INTELLIGENT_TIERING"
            }
        }

      - logging {
          - target_bucket = "ab-xyz-stage-access-logging-9d8e94ff" -> null
          - target_prefix = "logs/cloudtrail-logging/" -> null
        }
        logging {
            target_bucket = (known after apply)
            target_prefix = "logs/cloudtrail-logging/"
        }

      ~ versioning {
          ~ enabled    = false -> (known after apply)
          ~ mfa_delete = false -> (known after apply)
        }
    }

  # module.buckets.aws_s3_bucket_policy.cloudtrail_logging_bucket must be replaced
-/  resource "aws_s3_bucket_policy" "cloudtrail_logging_bucket" {
      ~ bucket = "ab-xyz-stage-cloudtrail-logging-72a2c5cd" -> (known after apply) # forces replacement
      ~ id     = "ab-xyz-stage-cloudtrail-logging-72a2c5cd" -> (known after apply)
      ~ policy = jsonencode(
            {
              - Statement = [
                  - {
                      - Action    = "s3:GetBucketAcl"
                      - Effect    = "Allow"
                      - Principal = {
                          - Service = "cloudtrail.amazonaws.com"
                        }
                      - Resource  = "arn:aws:s3:::ab-xyz-stage-cloudtrail-logging-72a2c5cd"
                      - Sid       = "AWSCloudTrailAclCheck"
                    },
                  - {
                      - Action    = "s3:PutObject"
                      - Condition = {
                          - StringEquals = {
                              - s3:x-amz-acl = "bucket-owner-full-control"
                            }
                        }
                      - Effect    = "Allow"
                      - Principal = {
                          - Service = "cloudtrail.amazonaws.com"
                        }
                      - Resource  = "arn:aws:s3:::ab-xyz-stage-cloudtrail-logging-72a2c5cd/*"
                      - Sid       = "AWSCloudTrailWrite"
                    },
                ]
              - Version   = "2012-10-17"
            }
        ) -> (known after apply)
    }

  # module.buckets.random_id.cloudtrail_bucket_suffix must be replaced
-/  resource "random_id" "cloudtrail_bucket_suffix" {
      ~ b64         = "cqLFzQ" -> (known after apply)
      ~ b64_std     = "cqLFzQ==" -> (known after apply)
      ~ b64_url     = "cqLFzQ" -> (known after apply)
        byte_length = 4
      ~ dec         = "1923270093" -> (known after apply)
      ~ hex         = "72a2c5cd" -> (known after apply)
      ~ id          = "cqLFzQ" -> (known after apply)
        keepers     = {
            "aws_account_id" = "123412341234"
            "env"            = "xyz-stage"
        } # forces replacement
    }

  # module.buckets.module.access_logging_bucket.aws_s3_bucket.default must be replaced
-/  resource "aws_s3_bucket" "default" {
        acceleration_status         = (known after apply)
        acl                         = "log-delivery-write"
      ~ arn                         = "arn:aws:s3:::ab-xyz-stage-access-logging-9d8e94ff" -> (known after apply)
      ~ bucket                      = "ab-xyz-stage-access-logging-9d8e94ff" -> (known after apply) # forces replacement
      ~ bucket_domain_name          = "ab-xyz-stage-access-logging-9d8e94ff.s3.amazonaws.com" -> (known after apply)
      ~ bucket_regional_domain_name = "ab-xyz-stage-access-logging-9d8e94ff.s3.us-west-2.amazonaws.com" -> (known after apply)
        force_destroy               = false
      ~ hosted_zone_id              = "Z3BJ6K6RIION7M" -> (known after apply)
      ~ id                          = "ab-xyz-stage-access-logging-9d8e94ff" -> (known after apply)
      ~ region                      = "us-west-2" -> (known after apply)
      ~ request_payer               = "BucketOwner" -> (known after apply)
        tags                        = {
            "mycompany:finance:accountenvironment"   = "xyz-stage"
            "mycompany:finance:application"          = "ab-platform"
            "mycompany:finance:billablebusinessunit" = "my-dev"
            "name"                                = "Access logging bucket"
        }
        website_domain              = (known after apply)
        website_endpoint            = (known after apply)

      - grant {
          - permissions = [
              - "READ_ACP",
              - "WRITE",
            ] -> null
          - type        = "Group" -> null
          - uri         = "http://acs.amazonaws.com/groups/s3/LogDelivery" -> null
        }
      - grant {
          - id          = "0343271a8c2f184152c171b223945b22ceaf5be5c9b78cf167660600747b5ad8" -> null
          - permissions = [
              - "FULL_CONTROL",
            ] -> null
          - type        = "CanonicalUser" -> null
        }

      - lifecycle_rule {
          - abort_incomplete_multipart_upload_days = 0 -> null
          - enabled                                = true -> null
          - id                                     = "intu-lifecycle-s3-int-tier" -> null
          - tags                                   = {} -> null

          - transition {
              - days          = 32 -> null
              - storage_class = "INTELLIGENT_TIERING" -> null
            }
        }

        logging {
            target_bucket = (known after apply)
            target_prefix = "logs/access-logging/"
        }

      ~ versioning {
          ~ enabled    = false -> (known after apply)
          ~ mfa_delete = false -> (known after apply)
        }
    }

  # module.buckets.module.access_logging_bucket.random_id.bucket_suffix must be replaced
-/  resource "random_id" "bucket_suffix" {
      ~ b64         = "nY6U_w" -> (known after apply)
      ~ b64_std     = "nY6U/w==" -> (known after apply)
      ~ b64_url     = "nY6U_w" -> (known after apply)
        byte_length = 4
      ~ dec         = "2643367167" -> (known after apply)
      ~ hex         = "9d8e94ff" -> (known after apply)
      ~ id          = "nY6U_w" -> (known after apply)
        keepers     = {
            "aws_account_id" = "123412341234"
            "env"            = "xyz-stage"
        } # forces replacement
    }

Plan: 6 to add, 0 to change, 5 to destroy.
  

Фрагмент разницы моего текущего состояния удаленного TF (СЛЕВА) и старой учетной записи (СПРАВА) для cloudtrail_bucket_suffix :

Фрагмент разницы моего текущего состояния удаленного TF (СЛЕВА) и старой учетной записи -область (СПРАВА) для cloudtrail_bucket_suffix

Комментарии:

1. план должен указать вам причину воссоздания. например, какие изменения вызывают их. можете ли вы опубликовать результаты плана?

2. @mariux, спасибо, что проверили это. Я добавил фрагмент моего плана терраформирования. Пожалуйста, дайте мне знать, если вам нужны какие-либо другие подробности.

3. Итак, исходя из вашего комментария, означает ли это, что то, что я импортировал (то есть фактические ресурсы в aws), отличается от того, что представляют мои сценарии terraform?

4. @mariux Также хочу упомянуть, что у меня есть некоторые изменения в коде для обновления TF с версии 0.11 до 0.12.29 .

5. спасибо за добавление, у меня может быть подсказка.. смотрите мой ответ

Ответ №1:

В плане показано различие в имени корзины ( bucket принудительная замена).

Это запускает воссоздание самого корзины и зависимых ресурсов.

Вам нужно перевести имя корзины в стабильное состояние, тогда все остальное также будет стабильным. Поскольку вы используете случайный суффикс для имени корзины, я подозреваю, что вы забыли импортировать это. random_id Ресурс разрешает импорт, подобный этому:

 terraform import module.buckets.random_id.cloudtrail_bucket_suffix cqLFzQ
  

Редактировать:

Однако вам нужно будет удалить keepers , поскольку они запускают замену random_id ресурса. keepers используются для запуска восстановления зависимых ресурсов при изменении других ресурсов.

Я предполагаю, что это не то, что вы хотите для своих сегментов, поскольку определенные вами хранители кажутся стабильными / статичными: account_id и env оба вряд ли изменятся для этого развертывания. Если они вам действительно нужны, вы можете попытаться манипулировать состоянием вручную.

Комментарии:

1. Спасибо Мариуксу. Да, мы используем random_id, и я уже импортировал его. Это: terraform import module.buckets.random_id.cloudtrail_bucket_suffix cqLFzQ

2. Я добавил полный terraform import и terraform plan вывод для справки. Пожалуйста, посмотрите мой обновленный вопрос.

3. извините.. да, пропустил это… смотрите мою обновленную версию.. хранители должны быть удалены .. если они вам действительно нужны, я мог бы попробовать трюк, который мы когда-то использовали для клиента… никогда не пробовал использовать random_id…

4. Я хочу сохранить keepers . Когда вы говорите «трюк», вы имеете в виду обновление текущего файла состояния удаленного TF, чтобы иметь keeepers и т. Д.? Я добавил разницу между текущим удаленным состоянием и тем, что было, когда этот ресурс был частью account-scope . Пожалуйста, проверьте

5. Из-за случайного характера ресурса наша последовательность импорта для другого ресурса не сработала. Поэтому единственный способ, который я вижу здесь, — это манипулировать состоянием вручную и открыть проблему в репозитории поставщика для поддержки импорта хранителей. извините, что здесь нет лучших вариантов.