hashicorp / terraform

Terraform enables you to safely and predictably create, change, and improve infrastructure. It is a source-available tool that codifies APIs into declarative configuration files that can be shared amongst team members, treated as code, edited, reviewed, and versioned.
https://www.terraform.io/
Other
42.5k stars 9.52k forks source link

Unable to import `aws_key_pair` #12716

Closed eyalzek closed 7 years ago

eyalzek commented 7 years ago

Terraform Version

v0.8.8

Affected Resource(s)

I'm trying to import an aws_key_pair according to the documentation but terraform is complaining that it doesn't exist:

$ aws ec2 describe-key-pairs
{
    "KeyPairs": [
        {
            "KeyName": "production", 
            "KeyFingerprint": "....."
        }
    ]
}
$ terraform import module.production.aws_key_pair.terraform production
module.production.aws_key_pair.terraform: Importing from ID "production"...
module.production.aws_key_pair.terraform: Import complete!
  Imported aws_key_pair (ID: production)
module.production.aws_key_pair.terraform: Refreshing state... (ID: production)
Error importing: 1 error(s) occurred:

* import module.production.aws_key_pair.terraform (id: production): Terraform detected a resource with this ID doesn't
exist. Please verify the ID is correct. You cannot import non-existent
resources using Terraform import.
artburkart commented 7 years ago

Weird. Do you have any more info you can share? Here's what I just did:

$ ./terraform -version
Terraform v0.8.8

$ aws ec2 --profile personal describe-key-pairs | jq '.KeyPairs[0]'
{
  "KeyFingerprint": ".....",
  "KeyName": "arthur"
}

$ AWS_PROFILE=personal AWS_REGION=us-east-1 ./terraform import module.personal.aws_key_pair.arthur arthur

module.personal.aws_key_pair.arthur: Importing from ID "arthur"...
module.personal.aws_key_pair.arthur: Import complete!
  Imported aws_key_pair (ID: arthur)
module.personal.aws_key_pair.arthur: Refreshing state... (ID: arthur)

Import success! The resources imported are shown above. These are
now in your Terraform state. Import does not currently generate
configuration, so you must do this next. If you do not create configuration
for the above resources, then the next `terraform plan` will mark
them for destruction.

I did notice, however, that if I switch arthur with "arthur", I get this error:

Error importing: 1 error(s) occurred:

* Can't import module.personal.aws_key_pair.arthur, would collide with an existing resource.

Please remove or rename this resource before continuing.
eyalzek commented 7 years ago

Well I changed some names in order to post here, but here is the full output with original names:

$ aws ec2 --profile default describe-key-pairs | jq '.KeyPairs'
[
  {
    "KeyName": "terraform-production",
    "KeyFingerprint": "...."
  },
  {
    "KeyName": "terraform-production-new",
    "KeyFingerprint": "...."
  }
]

This is my env (AWS_REGION was missing before, but it doesn't make a difference):

$ env |grep -i aws
AWS_DEFAULT_REGION=eu-west-1
AWS_SECRET_ACCESS_KEY=....
AWS_REGION=eu-west-1
AWS_ACCESS_KEY_ID=....

I have the old key in the state file, so before renaming it I'm getting this:

$ tf import module.production-eu-west-1.aws_key_pair.terraform terraform-production-new
module.production-eu-west-1.aws_key_pair.terraform: Importing from ID "terraform-production-new"...
module.production-eu-west-1.aws_key_pair.terraform: Import complete!
  Imported aws_key_pair (ID: terraform-production-new)
Error importing: 1 error(s) occurred:

* Can't import module.production-eu-west-1.aws_key_pair.terraform, would collide with an existing resource.

Please remove or rename this resource before continuing.

which I rename:

$ tf state mv module.production-eu-west-1.aws_key_pair.terraform module.production-eu-west-1.aws_key_pair.terraform-old
Moved module.production-eu-west-1.aws_key_pair.terraform to module.production-eu-west-1.aws_key_pair.terraform-old

and then try again:

$ tf import module.production-eu-west-1.aws_key_pair.terraform terraform-production-new
module.production-eu-west-1.aws_key_pair.terraform: Importing from ID "terraform-production-new"...
module.production-eu-west-1.aws_key_pair.terraform: Import complete!
  Imported aws_key_pair (ID: terraform-production-new)
module.production-eu-west-1.aws_key_pair.terraform: Refreshing state... (ID: terraform-production-new)
Error importing: 1 error(s) occurred:

* import module.production-eu-west-1.aws_key_pair.terraform (id: terraform-production-new): Terraform detected a resource with this ID doesn't
exist. Please verify the ID is correct. You cannot import non-existent
resources using Terraform import.

the result is the same when I try to quote terraform-production-new... I tested with a different environment that uses other AWS credentials and it works well (even without specifying the aws region...). I'm suspecting it has something to do with region, even though the environment variables should override everything no? And it still works with the aws cli...

artburkart commented 7 years ago

That's really interesting. I'm going to take a look into the code.

artburkart commented 7 years ago

Right, so the only time I'm able to produce the same error message is when I query for the key pair using the wrong region. I know this is a stupid question, so please bear with me, but do you know for a fact that when you query with awscli, you're querying the same region as when you use terraform? If you can confirm this, then I can start digging into the code to see if there's a weird situation where the region might be getting lost.

TF_LOG=DEBUG tf import module.production-eu-west-1.aws_key_pair.terraform terraform-production-new &> terraform.txt
grep -B5 "Action=DescribeKeyPairs.*" terraform.txt | grep -o eu-west-1
aws ec2 --profile default describe-key-pairs --debug &> awscli.txt
grep "Making request" awscli.txt | grep -o "region.*eu-west-1"

Thank you :)

eyalzek commented 7 years ago

Yeah I think you're right, the first command wasn't returning any output, omitting the second grep though you can see it's using eu-central-1 (I'm using terraform 0.9 btw):

$ grep -B5 "Action=DescribeKeyPairs.*" terraform.txt
2017/03/17 10:41:24 [DEBUG] plugin: tf0.9: Authorization: AWS4-HMAC-SHA256 Credential=<REDACTED>/20170317/eu-central-1/ec2/aws4_request, SignedHeaders=content-length;content-type;host;x-amz-date, Signature=<REDACTED>
2017/03/17 10:41:24 [DEBUG] plugin: tf0.9: Content-Type: application/x-www-form-urlencoded; charset=utf-8
2017/03/17 10:41:24 [DEBUG] plugin: tf0.9: X-Amz-Date: 20170317T094124Z
2017/03/17 10:41:24 [DEBUG] plugin: tf0.9: Accept-Encoding: gzip
2017/03/17 10:41:24 [DEBUG] plugin: tf0.9: 
2017/03/17 10:41:24 [DEBUG] plugin: tf0.9: Action=DescribeKeyPairs&KeyName.1=terraform-production-new&Version=2016-11-15

The awscli command also wasn't returning output, so again, I omitted the second grep (maybe there's difference of version between us) and it looks like it's actually using eu-west-1:

$ grep "Making request" awscli.txt 
2017-03-17 10:43:16,400 - MainThread - botocore.endpoint - DEBUG - Making request for <botocore.model.OperationModel object at 0x7fafac06fa58> (verify_ssl=True) with params: {'url': 'https://ec2.eu-west-1.amazonaws.com/', 'method': 'POST', 'headers': {'User-Agent': 'aws-cli/1.10.1 Python/3.5.2 Linux/4.4.0-62-generic botocore/1.3.23'}, 'body': {'Version': '2015-10-01', 'Action': 'DescribeKeyPairs'}, 'url_path': '/', 'query_string': ''}

Is there a variable I'm missing somewhere or is that a bug?

artburkart commented 7 years ago

What happens if you run AWS_PROFILE=default tf import module.production-eu-west-1.aws_key_pair.terraform terraform-production-new?

eyalzek commented 7 years ago

Same error.. I made sure that eu-west-1 is set in the credentials/config file under default as well...

artburkart commented 7 years ago

I think I have one more question that might help. What does your aws provider look like? When I set mine like this:

provider "aws" {
  region = "eu-west-1"
  profile = "personal"
}

It doesn't matter what I use for environment variables, it always uses eu-west-1. Whether or not this is a bug, I'll have to do some reading to determine. I'll take a look when I'm not at work :P

eyalzek commented 7 years ago

site/main.tf:

provider "aws" {
    region = "${var.region}"
}

and inside production.tf:

module "production-eu-west-1" {
    source = "../site"
    environment = "production"
    region = "eu-west-1"
    ......
artburkart commented 7 years ago

Do you have eu-central-1 specified anywhere? Terraform seems to be pulling it in from somewhere and querying eu-central-1 unexpectedly.

eyalzek commented 7 years ago

Yes! The default for region is set to eu-central-1. I changed it to eu-west-1 for testing purposes and it works. I'm now remembering that on past versions of terraform it used to ask for the value of region when executing an import, which leads me to believe that it's not actually reading module variables and just using the defaults. Could that be?

eyalzek commented 7 years ago

On a similar note, if there's no default value and the variable declaration remains blank, I'm getting the following error (tested on a different environment):

Error importing: 1 error(s) occurred:

* module.ci.provider.aws: 1:3: unknown variable accessed: var.region in:

${var.region}
artburkart commented 7 years ago

@eyalzek - Sorry to leave you hanging on this one. Regarding your last comment, if terraform is able to find a value anywhere to fill the region variable in with, it will use it, so the behavior you described is expected. I believe the "unknown variable accessed" behavior is the same as I've always seen it.

As for your second to last comment, where is the default for region defined? I don't think I understood.

Thanks!

eyalzek commented 7 years ago

My directory structure is as follows:

terraform
├── site
│   ├── main.tf (default variable definitions)
│   └── more modules...
└── production
    ├── production.tf (environment module definition)
    └── terraform.tfstate

the default value for region is in site/main.tf (with the value of eu-central-1) and inside production.tf it is overridden with eu-west-1.

artburkart commented 7 years ago

I think I understand now. I'll try to take a look tonight.

artburkart commented 7 years ago

I've taken another look at this. It does, indeed, seem to be a bug. I've put together a gist that makes it much clearer what is happening. This bug should probably be renamed to something more generic, since the bug impacts all aws resources (possibly all resources?) and not just aws_key_pair resources.

The import succeeds, but the following refresh is failing to pull in the proper region, so the entire import fails, and the terraform.tfstsate is never updated as a result. More interesting, it doesn't matter where you define the aws provider, it still pulls in the region from the module instead of using what has been defined on the provider.

eyalzek commented 7 years ago

Interesting. Feel free to edit the title if you can, otherwise let me know what you think would be a better fit and I'll change it.

ghost commented 4 years ago

I'm going to lock this issue because it has been closed for 30 days ⏳. This helps our maintainers find and focus on the active issues.

If you have found a problem that seems similar to this, please open a new issue and complete the issue template so we can capture all the details necessary to investigate further.