terraform无法重命名多个AWS资源

时间:2019-12-13 02:49:05

标签: terraform terraform-provider-aws

我正在遵循this关于地形的出色指南,特别是我目前处于第四部分-How to create reusable infrastructure with Terraform modules。我这里有一个问题-terraform无法从指南重命名资源。我不知道这是我的问题还是错误。如果有错误-在哪里报告?是aws provider错误还是terraform错误?解决方法是什么?

无论如何,这是我的目录结构:

C:\Work\terraform> tree /f
Folder PATH listing for volume OSDisk
Volume serial number is 689E-A096
C:.
│   .gitignore
│
├───backend
│       main.tf
│       terraform.tfstate
│
├───modules
│   └───services
│       └───webserver-cluster
│               main.tf
│               outputs.tf
│               variables.tf
│
└───stage
    └───services
        └───webserver-cluster
                main.tf

后端文件夹包含用于设置S3后端的代码:

C:\Work\terraform\backend> cat .\main.tf
provider "aws" {
  region = "us-east-2"
}

resource "aws_s3_bucket" "terraform_state" {
  bucket = "mark-kharitonov-terraform-up-and-running-state"
  force_destroy = true

  # Enable versioning so we can see the full revision history of our
  # state files
  versioning {
    enabled = true
  }

  # Enable server-side encryption by default
  server_side_encryption_configuration {
    rule {
      apply_server_side_encryption_by_default {
        sse_algorithm = "AES256"
      }
    }
  }
}

resource "aws_dynamodb_table" "terraform_locks" {
  name         = "terraform-up-and-running-locks"
  billing_mode = "PAY_PER_REQUEST"
  hash_key     = "LockID"

  attribute {
    name = "LockID"
    type = "S"
  }
}
C:\Work\terraform\backend> terraform init

Initializing the backend...

Initializing provider plugins...
- Checking for available provider plugins...
- Downloading plugin for provider "aws" (hashicorp/aws) 2.41.0...

...

* provider.aws: version = "~> 2.41"

Terraform has been successfully initialized!

...

C:\Work\terraform\backend> terraform apply

An execution plan has been generated and is shown below.
Resource actions are indicated with the following symbols:
  + create

Terraform will perform the following actions:

  # aws_dynamodb_table.terraform_locks will be created
  + resource "aws_dynamodb_table" "terraform_locks" {
...
      + name             = "terraform-up-and-running-locks"
...
    }

  # aws_s3_bucket.terraform_state will be created
  + resource "aws_s3_bucket" "terraform_state" {
...
      + bucket                      = "mark-kharitonov-terraform-up-and-running-state"
...
    }

Plan: 2 to add, 0 to change, 0 to destroy.

Do you want to perform these actions?
  Terraform will perform the actions described above.
  Only 'yes' will be accepted to approve.

  Enter a value: yes

aws_dynamodb_table.terraform_locks: Creating...
aws_s3_bucket.terraform_state: Creating...
aws_dynamodb_table.terraform_locks: Creation complete after 5s [id=terraform-up-and-running-locks]
aws_s3_bucket.terraform_state: Creation complete after 9s [id=mark-kharitonov-terraform-up-and-running-state]

Apply complete! Resources: 2 added, 0 changed, 0 destroyed.

一切都很好,已经建立了后端。

接下来,有modules文件夹。该指南描述了其内容,但在这里是:

C:\work\terraform\modules\services\webserver-cluster> cat .\variables.tf
variable "server_port" {
  description = "The port the server will use for HTTP requests"
  type        = number
  default     = 8080
}

variable "cluster_name" {
  description = "The name to use for all the cluster resources"
  type        = string
}
C:\work\terraform\modules\services\webserver-cluster> cat .\main.tf
data "aws_availability_zones" "all" {}

resource "aws_launch_configuration" "example" {
  image_id        = "ami-0c55b159cbfafe1f0"
  instance_type   = "t2.micro"
  security_groups = [aws_security_group.instance.id]
  user_data       = <<-EOF
              #!/bin/bash
              echo "Hello, World" > index.html
              nohup busybox httpd -f -p "${var.server_port}" &
              EOF
  lifecycle {
    create_before_destroy = true
  }
}

resource "aws_autoscaling_group" "example" {
  launch_configuration = aws_launch_configuration.example.id
  availability_zones   = data.aws_availability_zones.all.names

  min_size = 2
  max_size = 10

  load_balancers    = [aws_elb.example.name]
  health_check_type = "ELB"

  tag {
    key                 = "Name"
    value               = "${var.cluster_name}-asg"
    propagate_at_launch = true
  }
}

resource "aws_elb" "example" {
  name               = "${var.cluster_name}-clb"
  security_groups    = [aws_security_group.elb.id]
  availability_zones = data.aws_availability_zones.all.names

  health_check {
    target              = "HTTP:${var.server_port}/"
    interval            = 30
    timeout             = 3
    healthy_threshold   = 2
    unhealthy_threshold = 2
  }

  # This adds a listener for incoming HTTP requests.
  listener {
    lb_port           = 80
    lb_protocol       = "http"
    instance_port     = var.server_port
    instance_protocol = "http"
  }
}

resource "aws_security_group" "elb" {
  name = "${var.cluster_name}-elb"

  # Allow all outbound
  egress {
    from_port   = 0
    to_port     = 0
    protocol    = "-1"
    cidr_blocks = ["0.0.0.0/0"]
  }

  # Inbound HTTP from anywhere
  ingress {
    from_port   = 80
    to_port     = 80
    protocol    = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
  }
}

resource "aws_security_group" "instance" {
  name = "${var.cluster_name}-instance"
  ingress {
    from_port   = var.server_port
    to_port     = var.server_port
    protocol    = "tcp"
    cidr_blocks = ["0.0.0.0/0"]
  }
}
C:\work\terraform\modules\services\webserver-cluster> cat .\outputs.tf
output "clb_dns_name" {
  value       = aws_elb.example.dns_name
  description = "The domain name of the load balancer"
}

现在我正在使用该模块在名为webservers-stage的阶段中创建集群:

C:\work\terraform\stage\services\webserver-cluster> terraform init
Initializing modules...
- webserver_cluster in ..\..\..\modules\services\webserver-cluster

Initializing the backend...

Successfully configured the backend "s3"! Terraform will automatically
use this backend unless the backend configuration changes.

Initializing provider plugins...
- Checking for available provider plugins...
- Downloading plugin for provider "aws" (hashicorp/aws) 2.41.0...

...

* provider.aws: version = "~> 2.41"

Terraform has been successfully initialized!

...
C:\work\terraform\stage\services\webserver-cluster> terraform apply
module.webserver_cluster.data.aws_availability_zones.all: Refreshing state...

An execution plan has been generated and is shown below.
Resource actions are indicated with the following symbols:
  + create

Terraform will perform the following actions:

  # module.webserver_cluster.aws_autoscaling_group.example will be created
  + resource "aws_autoscaling_group" "example" {
...
      + tag {
          + key                 = "Name"
          + propagate_at_launch = true
          + value               = "webservers-stage-asg"
        }
    }

  # module.webserver_cluster.aws_elb.example will be created
  + resource "aws_elb" "example" {
...
      + name                        = "webservers-stage-clb"
...
    }

  # module.webserver_cluster.aws_launch_configuration.example will be created
  + resource "aws_launch_configuration" "example" {
...
    }

  # module.webserver_cluster.aws_security_group.elb will be created
  + resource "aws_security_group" "elb" {
...
      + name                   = "webservers-stage-elb"
...
    }

  # module.webserver_cluster.aws_security_group.instance will be created
  + resource "aws_security_group" "instance" {
...
      + name                   = "webservers-stage-instance"
...
    }

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

Do you want to perform these actions?
  Terraform will perform the actions described above.
  Only 'yes' will be accepted to approve.

  Enter a value: yes

module.webserver_cluster.aws_security_group.instance: Creating...
module.webserver_cluster.aws_security_group.elb: Creating...
module.webserver_cluster.aws_security_group.instance: Creation complete after 2s [id=sg-0774ace0accdfd348]
module.webserver_cluster.aws_launch_configuration.example: Creating...
module.webserver_cluster.aws_security_group.elb: Creation complete after 2s [id=sg-00e75aa1f2fc5d9e9]
module.webserver_cluster.aws_elb.example: Creating...
module.webserver_cluster.aws_launch_configuration.example: Creation complete after 1s [id=terraform-20191213010022791900000001]
module.webserver_cluster.aws_elb.example: Creation complete after 4s [id=webservers-stage-clb]
module.webserver_cluster.aws_autoscaling_group.example: Creating...
module.webserver_cluster.aws_autoscaling_group.example: Still creating... [10s elapsed]
module.webserver_cluster.aws_autoscaling_group.example: Still creating... [20s elapsed]
module.webserver_cluster.aws_autoscaling_group.example: Still creating... [30s elapsed]
module.webserver_cluster.aws_autoscaling_group.example: Still creating... [40s elapsed]
module.webserver_cluster.aws_autoscaling_group.example: Creation complete after 41s [id=tf-asg-20191213010027291700000002]

Apply complete! Resources: 5 added, 0 changed, 0 destroyed.
Releasing state lock. This may take a few moments...

太神奇了!群集已启动并正在运行。到目前为止一切顺利。

现在有问题的部分。假设我想修改cluster_name变量的值,以有效地重命名所有资源:

C:\work\terraform\stage\services\webserver-cluster> (cat .\main.tf) -replace 'webservers-stage','webservers-stage2' | Out-File -Encoding ascii .\main.tf
C:\work\terraform\stage\services\webserver-cluster> cat .\main.tf
provider "aws" {
  region = "us-east-2"
}

terraform {
  backend "s3" {
    # Replace this with your bucket name!
    bucket = "mark-kharitonov-terraform-up-and-running-state"
    key    = "stage/services/webserver-cluster/terraform.tfstate"
    region = "us-east-2"
    # Replace this with your DynamoDB table name!
    dynamodb_table = "terraform-up-and-running-locks"
    encrypt        = true
  }
}

module "webserver_cluster" {
  source       = "../../../modules/services/webserver-cluster"
  cluster_name = "webservers-stage2"
}

现在,群集名称为 webservers-stage2 。这是发生了什么:

C:\work\terraform\stage\services\webserver-cluster> terraform.exe apply
module.webserver_cluster.data.aws_availability_zones.all: Refreshing state...
module.webserver_cluster.aws_security_group.elb: Refreshing state... [id=sg-00e75aa1f2fc5d9e9]
module.webserver_cluster.aws_security_group.instance: Refreshing state... [id=sg-0774ace0accdfd348]
module.webserver_cluster.aws_elb.example: Refreshing state... [id=webservers-stage-clb]
module.webserver_cluster.aws_launch_configuration.example: Refreshing state... [id=terraform-20191213010022791900000001]
module.webserver_cluster.aws_autoscaling_group.example: Refreshing state... [id=tf-asg-20191213010027291700000002]

An execution plan has been generated and is shown below.
Resource actions are indicated with the following symbols:
  ~ update in-place
-/+ destroy and then create replacement
+/- create replacement and then destroy

Terraform will perform the following actions:

  # module.webserver_cluster.aws_autoscaling_group.example will be updated in-place
  ~ resource "aws_autoscaling_group" "example" {
        arn                       = "arn:aws:autoscaling:us-east-2:170091157278:autoScalingGroup:5fe93e07-27d2-4d4e-91cc-24ae916ec735:autoScalingGroupName/tf-asg-20191213010027291700000002"
        availability_zones        = [
            "us-east-2a",
            "us-east-2b",
            "us-east-2c",
        ]
        default_cooldown          = 300
        desired_capacity          = 2
        enabled_metrics           = []
        force_delete              = false
        health_check_grace_period = 300
        health_check_type         = "ELB"
        id                        = "tf-asg-20191213010027291700000002"
      ~ launch_configuration      = "terraform-20191213010022791900000001" -> (known after apply)
      ~ load_balancers            = [
          - "webservers-stage-clb",
          + "webservers-stage2-clb",
        ]
        max_instance_lifetime     = 0
        max_size                  = 10
        metrics_granularity       = "1Minute"
        min_size                  = 2
        name                      = "tf-asg-20191213010027291700000002"
        protect_from_scale_in     = false
        service_linked_role_arn   = "arn:aws:iam::170091157278:role/aws-service-role/autoscaling.amazonaws.com/AWSServiceRoleForAutoScaling"
        suspended_processes       = []
        target_group_arns         = []
        termination_policies      = []
        vpc_zone_identifier       = []
        wait_for_capacity_timeout = "10m"

      - tag {
          - key                 = "Name" -> null
          - propagate_at_launch = true -> null
          - value               = "webservers-stage-asg" -> null
        }
      + tag {
          + key                 = "Name"
          + propagate_at_launch = true
          + value               = "webservers-stage2-asg"
        }
    }

  # module.webserver_cluster.aws_elb.example must be replaced
-/+ resource "aws_elb" "example" {
      ~ arn                         = "arn:aws:elasticloadbalancing:us-east-2:170091157278:loadbalancer/webservers-stage-clb" -> (known after apply)
        availability_zones          = [
            "us-east-2a",
            "us-east-2b",
            "us-east-2c",
        ]
        connection_draining         = false
        connection_draining_timeout = 300
        cross_zone_load_balancing   = true
      ~ dns_name                    = "webservers-stage-clb-641972551.us-east-2.elb.amazonaws.com" -> (known after apply)
      ~ id                          = "webservers-stage-clb" -> (known after apply)
        idle_timeout                = 60
      ~ instances                   = [
          - "i-00617fcc06a5ae64f",
          - "i-0ee5eb03f3bf733b0",
        ] -> (known after apply)
      ~ internal                    = false -> (known after apply)
      ~ name                        = "webservers-stage-clb" -> "webservers-stage2-clb" # forces replacement
      ~ security_groups             = [
          - "sg-00e75aa1f2fc5d9e9",
        ] -> (known after apply)
      ~ source_security_group       = "170091157278/webservers-stage-elb" -> (known after apply)
      ~ source_security_group_id    = "sg-00e75aa1f2fc5d9e9" -> (known after apply)
      ~ subnets                     = [
          - "subnet-3e7c2244",
          - "subnet-6569ef29",
          - "subnet-74e8081f",
        ] -> (known after apply)
      - tags                        = {} -> null
      ~ zone_id                     = "Z3AADJGX6KTTL2" -> (known after apply)

        health_check {
            healthy_threshold   = 2
            interval            = 30
            target              = "HTTP:8080/"
            timeout             = 3
            unhealthy_threshold = 2
        }

        listener {
            instance_port     = 8080
            instance_protocol = "http"
            lb_port           = 80
            lb_protocol       = "http"
        }
    }

  # module.webserver_cluster.aws_launch_configuration.example must be replaced
+/- resource "aws_launch_configuration" "example" {
        associate_public_ip_address      = false
      ~ ebs_optimized                    = false -> (known after apply)
        enable_monitoring                = true
      ~ id                               = "terraform-20191213010022791900000001" -> (known after apply)
        image_id                         = "ami-0c55b159cbfafe1f0"
        instance_type                    = "t2.micro"
      + key_name                         = (known after apply)
      ~ name                             = "terraform-20191213010022791900000001" -> (known after apply)
      ~ security_groups                  = [
          - "sg-0774ace0accdfd348",
        ] -> (known after apply) # forces replacement
        user_data                        = "398ce7cb244926b5b22c0dcb00d885ac509c0ee5"
      - vpc_classic_link_security_groups = [] -> null

      + ebs_block_device {
          + delete_on_termination = (known after apply)
          + device_name           = (known after apply)
          + encrypted             = (known after apply)
          + iops                  = (known after apply)
          + no_device             = (known after apply)
          + snapshot_id           = (known after apply)
          + volume_size           = (known after apply)
          + volume_type           = (known after apply)
        }

      + root_block_device {
          + delete_on_termination = (known after apply)
          + encrypted             = (known after apply)
          + iops                  = (known after apply)
          + volume_size           = (known after apply)
          + volume_type           = (known after apply)
        }
    }

  # module.webserver_cluster.aws_security_group.elb must be replaced
-/+ resource "aws_security_group" "elb" {
      ~ arn                    = "arn:aws:ec2:us-east-2:170091157278:security-group/sg-00e75aa1f2fc5d9e9" -> (known after apply)
        description            = "Managed by Terraform"
        egress                 = [
            {
                cidr_blocks      = [
                    "0.0.0.0/0",
                ]
                description      = ""
                from_port        = 0
                ipv6_cidr_blocks = []
                prefix_list_ids  = []
                protocol         = "-1"
                security_groups  = []
                self             = false
                to_port          = 0
            },
        ]
      ~ id                     = "sg-00e75aa1f2fc5d9e9" -> (known after apply)
        ingress                = [
            {
                cidr_blocks      = [
                    "0.0.0.0/0",
                ]
                description      = ""
                from_port        = 80
                ipv6_cidr_blocks = []
                prefix_list_ids  = []
                protocol         = "tcp"
                security_groups  = []
                self             = false
                to_port          = 80
            },
        ]
      ~ name                   = "webservers-stage-elb" -> "webservers-stage2-elb" # forces replacement
      ~ owner_id               = "170091157278" -> (known after apply)
        revoke_rules_on_delete = false
      - tags                   = {} -> null
      ~ vpc_id                 = "vpc-e8a15983" -> (known after apply)
    }

  # module.webserver_cluster.aws_security_group.instance must be replaced
+/- resource "aws_security_group" "instance" {
      ~ arn                    = "arn:aws:ec2:us-east-2:170091157278:security-group/sg-0774ace0accdfd348" -> (known after apply)
        description            = "Managed by Terraform"
      ~ egress                 = [] -> (known after apply)
      ~ id                     = "sg-0774ace0accdfd348" -> (known after apply)
        ingress                = [
            {
                cidr_blocks      = [
                    "0.0.0.0/0",
                ]
                description      = ""
                from_port        = 8080
                ipv6_cidr_blocks = []
                prefix_list_ids  = []
                protocol         = "tcp"
                security_groups  = []
                self             = false
                to_port          = 8080
            },
        ]
      ~ name                   = "webservers-stage-instance" -> "webservers-stage2-instance" # forces replacement
      ~ owner_id               = "170091157278" -> (known after apply)
        revoke_rules_on_delete = false
      - tags                   = {} -> null
      ~ vpc_id                 = "vpc-e8a15983" -> (known after apply)
    }

Plan: 4 to add, 1 to change, 4 to destroy.

Do you want to perform these actions?
  Terraform will perform the actions described above.
  Only 'yes' will be accepted to approve.

  Enter a value: yes

module.webserver_cluster.aws_elb.example: Destroying... [id=webservers-stage-clb]
module.webserver_cluster.aws_security_group.instance: Creating...
module.webserver_cluster.aws_elb.example: Destruction complete after 1s
module.webserver_cluster.aws_security_group.elb: Destroying... [id=sg-00e75aa1f2fc5d9e9]
module.webserver_cluster.aws_security_group.instance: Creation complete after 2s [id=sg-0b3b7c4ceb54ac416]
module.webserver_cluster.aws_launch_configuration.example: Creating...
module.webserver_cluster.aws_launch_configuration.example: Creation complete after 1s [id=terraform-20191213015144456000000001]
module.webserver_cluster.aws_security_group.elb: Still destroying... [id=sg-00e75aa1f2fc5d9e9, 10s elapsed]
module.webserver_cluster.aws_security_group.elb: Still destroying... [id=sg-00e75aa1f2fc5d9e9, 20s elapsed]
module.webserver_cluster.aws_security_group.elb: Destruction complete after 28s
module.webserver_cluster.aws_security_group.elb: Creating...
module.webserver_cluster.aws_security_group.elb: Creation complete after 2s [id=sg-06f4f489b60ba9134]
module.webserver_cluster.aws_elb.example: Creating...
module.webserver_cluster.aws_elb.example: Creation complete after 4s [id=webservers-stage2-clb]
module.webserver_cluster.aws_autoscaling_group.example: Modifying... [id=tf-asg-20191213010027291700000002]
module.webserver_cluster.aws_autoscaling_group.example: Still modifying... [id=tf-asg-20191213010027291700000002, 10s elapsed]
module.webserver_cluster.aws_autoscaling_group.example: Still modifying... [id=tf-asg-20191213010027291700000002, 20s elapsed]
module.webserver_cluster.aws_autoscaling_group.example: Still modifying... [id=tf-asg-20191213010027291700000002, 30s elapsed]
module.webserver_cluster.aws_autoscaling_group.example: Modifications complete after 39s [id=tf-asg-20191213010027291700000002]
module.webserver_cluster.aws_launch_configuration.example: Destroying... [id=terraform-20191213010022791900000001]
module.webserver_cluster.aws_launch_configuration.example: Destruction complete after 0s
module.webserver_cluster.aws_security_group.instance: Destroying... [id=sg-0774ace0accdfd348]
module.webserver_cluster.aws_security_group.instance: Still destroying... [id=sg-0774ace0accdfd348, 10s elapsed]
...
module.webserver_cluster.aws_security_group.instance: Still destroying... [id=sg-0774ace0accdfd348, 10m0s elapsed]

Error: Error deleting security group: DependencyViolation: resource sg-0774ace0accdfd348 has a dependent object
        status code: 400, request id: d8801db8-65c1-4de1-9f7a-107b2cad247f


Releasing state lock. This may take a few moments...

我想念什么?

1 个答案:

答案 0 :(得分:0)

我认为这是因为自动伸缩组已启动附加到安全组的实例。

不幸的是,这是Terraform和基础服务中强制依赖关系的一个已知问题。目前,Terraform中没有解决方法。您可以在terraform-provider-aws回购中看到this open issue

我认为解决此问题的唯一方法是在运行module.webserver_cluster.aws_autoscaling_group.example之前手动污染或破坏terraform apply资源。

要么运行

terraform taint module.webserver_cluster.aws_autoscaling_group.example

terraform destroy -target="module.webserver_cluster.aws_autoscaling_group.example"

然后运行您的terraform apply