diff --git a/.changelog/15829.txt b/.changelog/15829.txt new file mode 100644 index 00000000000..4137078dc92 --- /dev/null +++ b/.changelog/15829.txt @@ -0,0 +1,3 @@ +```release-note:new-data-source +aws_key_pair +``` \ No newline at end of file diff --git a/internal/provider/provider.go b/internal/provider/provider.go index 545d95836dd..bacf80d6a78 100644 --- a/internal/provider/provider.go +++ b/internal/provider/provider.go @@ -451,6 +451,7 @@ func Provider() *schema.Provider { "aws_instance": ec2.DataSourceInstance(), "aws_instances": ec2.DataSourceInstances(), "aws_internet_gateway": ec2.DataSourceInternetGateway(), + "aws_key_pair": ec2.DataSourceKeyPair(), "aws_launch_template": ec2.DataSourceLaunchTemplate(), "aws_nat_gateway": ec2.DataSourceNatGateway(), "aws_network_acls": ec2.DataSourceNetworkACLs(), diff --git a/internal/service/ec2/errors.go b/internal/service/ec2/errors.go index 0928c4546b5..2912988972a 100644 --- a/internal/service/ec2/errors.go +++ b/internal/service/ec2/errors.go @@ -14,6 +14,7 @@ const ( ErrCodeGatewayNotAttached = "Gateway.NotAttached" ErrCodeInvalidAssociationIDNotFound = "InvalidAssociationID.NotFound" ErrCodeInvalidAttachmentIDNotFound = "InvalidAttachmentID.NotFound" + ErrCodeInvalidKeyPairNotFound = "InvalidKeyPair.NotFound" ErrCodeInvalidParameter = "InvalidParameter" ErrCodeInvalidParameterException = "InvalidParameterException" ErrCodeInvalidParameterValue = "InvalidParameterValue" diff --git a/internal/service/ec2/find.go b/internal/service/ec2/find.go index e12330d2c76..e2800ee55bd 100644 --- a/internal/service/ec2/find.go +++ b/internal/service/ec2/find.go @@ -1062,6 +1062,62 @@ func FindInternetGatewayAttachment(conn *ec2.EC2, internetGatewayID, vpcID strin return attachment, nil } +func FindKeyPair(conn *ec2.EC2, input *ec2.DescribeKeyPairsInput) (*ec2.KeyPairInfo, error) { + output, err := FindKeyPairs(conn, input) + + if err != nil { + return nil, err + } + + if len(output) == 0 || output[0] == nil { + return nil, tfresource.NewEmptyResultError(input) + } + + if count := len(output); count > 1 { + return nil, tfresource.NewTooManyResultsError(count, input) + } + + return output[0], nil +} + +func FindKeyPairs(conn *ec2.EC2, input *ec2.DescribeKeyPairsInput) ([]*ec2.KeyPairInfo, error) { + output, err := conn.DescribeKeyPairs(input) + + if tfawserr.ErrCodeEquals(err, ErrCodeInvalidKeyPairNotFound) { + return nil, &resource.NotFoundError{ + LastError: err, + LastRequest: input, + } + } + + if err != nil { + return nil, err + } + + return output.KeyPairs, nil +} + +func FindKeyPairByName(conn *ec2.EC2, name string) (*ec2.KeyPairInfo, error) { + input := &ec2.DescribeKeyPairsInput{ + KeyNames: aws.StringSlice([]string{name}), + } + + output, err := FindKeyPair(conn, input) + + if err != nil { + return nil, err + } + + // Eventual consistency check. + if aws.StringValue(output.KeyName) != name { + return nil, &resource.NotFoundError{ + LastRequest: input, + } + } + + return output, nil +} + func FindManagedPrefixListByID(conn *ec2.EC2, id string) (*ec2.ManagedPrefixList, error) { input := &ec2.DescribeManagedPrefixListsInput{ PrefixListIds: aws.StringSlice([]string{id}), diff --git a/internal/service/ec2/key_pair.go b/internal/service/ec2/key_pair.go index 6cb05fcbe59..4df8b061c62 100644 --- a/internal/service/ec2/key_pair.go +++ b/internal/service/ec2/key_pair.go @@ -8,12 +8,13 @@ import ( "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/aws/arn" "github.com/aws/aws-sdk-go/service/ec2" - "github.com/hashicorp/aws-sdk-go-base/tfawserr" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" "github.com/hashicorp/terraform-provider-aws/internal/conns" + "github.com/hashicorp/terraform-provider-aws/internal/create" tftags "github.com/hashicorp/terraform-provider-aws/internal/tags" + "github.com/hashicorp/terraform-provider-aws/internal/tfresource" "github.com/hashicorp/terraform-provider-aws/internal/verify" ) @@ -34,20 +35,33 @@ func ResourceKeyPair() *schema.Resource { MigrateState: KeyPairMigrateState, Schema: map[string]*schema.Schema{ + "arn": { + Type: schema.TypeString, + Computed: true, + }, + "fingerprint": { + Type: schema.TypeString, + Computed: true, + }, "key_name": { Type: schema.TypeString, Optional: true, Computed: true, ForceNew: true, - ConflictsWith: []string{"key_name_prefix"}, ValidateFunc: validation.StringLenBetween(0, 255), + ConflictsWith: []string{"key_name_prefix"}, }, "key_name_prefix": { Type: schema.TypeString, Optional: true, + Computed: true, ForceNew: true, - ConflictsWith: []string{"key_name"}, ValidateFunc: validation.StringLenBetween(0, 255-resource.UniqueIDSuffixLength), + ConflictsWith: []string{"key_name"}, + }, + "key_pair_id": { + Type: schema.TypeString, + Computed: true, }, "public_key": { Type: schema.TypeString, @@ -62,20 +76,8 @@ func ResourceKeyPair() *schema.Resource { } }, }, - "fingerprint": { - Type: schema.TypeString, - Computed: true, - }, - "key_pair_id": { - Type: schema.TypeString, - Computed: true, - }, "tags": tftags.TagsSchema(), "tags_all": tftags.TagsSchemaComputed(), - "arn": { - Type: schema.TypeString, - Computed: true, - }, }, } } @@ -85,29 +87,21 @@ func resourceKeyPairCreate(d *schema.ResourceData, meta interface{}) error { defaultTagsConfig := meta.(*conns.AWSClient).DefaultTagsConfig tags := defaultTagsConfig.MergeTags(tftags.New(d.Get("tags").(map[string]interface{}))) - var keyName string - if v, ok := d.GetOk("key_name"); ok { - keyName = v.(string) - } else if v, ok := d.GetOk("key_name_prefix"); ok { - keyName = resource.PrefixedUniqueId(v.(string)) - d.Set("key_name", keyName) - } else { - keyName = resource.UniqueId() - d.Set("key_name", keyName) - } + keyName := create.Name(d.Get("key_name").(string), d.Get("key_name_prefix").(string)) - publicKey := d.Get("public_key").(string) - req := &ec2.ImportKeyPairInput{ + input := &ec2.ImportKeyPairInput{ KeyName: aws.String(keyName), - PublicKeyMaterial: []byte(publicKey), + PublicKeyMaterial: []byte(d.Get("public_key").(string)), TagSpecifications: ec2TagSpecificationsFromKeyValueTags(tags, ec2.ResourceTypeKeyPair), } - resp, err := conn.ImportKeyPair(req) + + output, err := conn.ImportKeyPair(input) + if err != nil { - return fmt.Errorf("Error import KeyPair: %s", err) + return fmt.Errorf("error importing EC2 Key Pair (%s): %w", keyName, err) } - d.SetId(aws.StringValue(resp.KeyName)) + d.SetId(aws.StringValue(output.KeyName)) return resourceKeyPairRead(d, meta) } @@ -117,35 +111,32 @@ func resourceKeyPairRead(d *schema.ResourceData, meta interface{}) error { defaultTagsConfig := meta.(*conns.AWSClient).DefaultTagsConfig ignoreTagsConfig := meta.(*conns.AWSClient).IgnoreTagsConfig - req := &ec2.DescribeKeyPairsInput{ - KeyNames: []*string{aws.String(d.Id())}, - } - resp, err := conn.DescribeKeyPairs(req) - if err != nil { - if tfawserr.ErrMessageContains(err, "InvalidKeyPair.NotFound", "") { - log.Printf("[WARN] Key Pair (%s) not found, removing from state", d.Id()) - d.SetId("") - return nil - } - return fmt.Errorf("Error retrieving KeyPair: %s", err) - } + keyPair, err := FindKeyPairByName(conn, d.Id()) - if len(resp.KeyPairs) == 0 { - log.Printf("[WARN] Key Pair (%s) not found, removing from state", d.Id()) + if !d.IsNewResource() && tfresource.NotFound(err) { + log.Printf("[WARN] EC2 Key Pair (%s) not found, removing from state", d.Id()) d.SetId("") return nil } - kp := resp.KeyPairs[0] - - if aws.StringValue(kp.KeyName) != d.Id() { - return fmt.Errorf("Unable to find key pair within: %#v", resp.KeyPairs) + if err != nil { + return fmt.Errorf("error reading EC2 Key Pair (%s): %w", d.Id(), err) } - d.Set("key_name", kp.KeyName) - d.Set("fingerprint", kp.KeyFingerprint) - d.Set("key_pair_id", kp.KeyPairId) - tags := KeyValueTags(kp.Tags).IgnoreAWS().IgnoreConfig(ignoreTagsConfig) + arn := arn.ARN{ + Partition: meta.(*conns.AWSClient).Partition, + Service: ec2.ServiceName, + Region: meta.(*conns.AWSClient).Region, + AccountID: meta.(*conns.AWSClient).AccountID, + Resource: fmt.Sprintf("key-pair/%s", d.Id()), + }.String() + d.Set("arn", arn) + d.Set("fingerprint", keyPair.KeyFingerprint) + d.Set("key_name", keyPair.KeyName) + d.Set("key_name_prefix", create.NamePrefixFromName(aws.StringValue(keyPair.KeyName))) + d.Set("key_pair_id", keyPair.KeyPairId) + + tags := KeyValueTags(keyPair.Tags).IgnoreAWS().IgnoreConfig(ignoreTagsConfig) //lintignore:AWSR002 if err := d.Set("tags", tags.RemoveDefaultConfig(defaultTagsConfig).Map()); err != nil { @@ -156,16 +147,6 @@ func resourceKeyPairRead(d *schema.ResourceData, meta interface{}) error { return fmt.Errorf("error setting tags_all: %w", err) } - arn := arn.ARN{ - Partition: meta.(*conns.AWSClient).Partition, - Service: ec2.ServiceName, - Region: meta.(*conns.AWSClient).Region, - AccountID: meta.(*conns.AWSClient).AccountID, - Resource: fmt.Sprintf("key-pair/%s", d.Id()), - }.String() - - d.Set("arn", arn) - return nil } @@ -175,7 +156,7 @@ func resourceKeyPairUpdate(d *schema.ResourceData, meta interface{}) error { if d.HasChange("tags_all") { o, n := d.GetChange("tags_all") if err := UpdateTags(conn, d.Get("key_pair_id").(string), o, n); err != nil { - return fmt.Errorf("error adding tags: %s", err) + return fmt.Errorf("error updating tags: %w", err) } } @@ -185,8 +166,14 @@ func resourceKeyPairUpdate(d *schema.ResourceData, meta interface{}) error { func resourceKeyPairDelete(d *schema.ResourceData, meta interface{}) error { conn := meta.(*conns.AWSClient).EC2Conn + log.Printf("[DEBUG] Deleting EC2 Key Pair: %s", d.Id()) _, err := conn.DeleteKeyPair(&ec2.DeleteKeyPairInput{ KeyName: aws.String(d.Id()), }) - return err + + if err != nil { + return fmt.Errorf("error deleting EC2 Key Pair (%s): %w", d.Id(), err) + } + + return nil } diff --git a/internal/service/ec2/key_pair_data_source.go b/internal/service/ec2/key_pair_data_source.go new file mode 100644 index 00000000000..20e15aeae97 --- /dev/null +++ b/internal/service/ec2/key_pair_data_source.go @@ -0,0 +1,86 @@ +package ec2 + +import ( + "fmt" + + "github.com/aws/aws-sdk-go/aws" + "github.com/aws/aws-sdk-go/aws/arn" + "github.com/aws/aws-sdk-go/service/ec2" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/hashicorp/terraform-provider-aws/internal/conns" + tftags "github.com/hashicorp/terraform-provider-aws/internal/tags" + "github.com/hashicorp/terraform-provider-aws/internal/tfresource" +) + +func DataSourceKeyPair() *schema.Resource { + return &schema.Resource{ + Read: dataSourceKeyPairRead, + + Schema: map[string]*schema.Schema{ + "arn": { + Type: schema.TypeString, + Computed: true, + }, + "filter": DataSourceFiltersSchema(), + "fingerprint": { + Type: schema.TypeString, + Computed: true, + }, + "key_name": { + Type: schema.TypeString, + Optional: true, + }, + "key_pair_id": { + Type: schema.TypeString, + Optional: true, + }, + "tags": tftags.TagsSchemaComputed(), + }, + } +} + +func dataSourceKeyPairRead(d *schema.ResourceData, meta interface{}) error { + conn := meta.(*conns.AWSClient).EC2Conn + ignoreTagsConfig := meta.(*conns.AWSClient).IgnoreTagsConfig + + input := &ec2.DescribeKeyPairsInput{} + + if v, ok := d.GetOk("filter"); ok { + input.Filters = BuildFiltersDataSource(v.(*schema.Set)) + } + + if v, ok := d.GetOk("key_name"); ok { + input.KeyNames = aws.StringSlice([]string{v.(string)}) + } + + if v, ok := d.GetOk("key_pair_id"); ok { + input.KeyPairIds = aws.StringSlice([]string{v.(string)}) + } + + keyPair, err := FindKeyPair(conn, input) + + if err != nil { + return tfresource.SingularDataSourceFindError("EC2 Key Pair", err) + } + + d.SetId(aws.StringValue(keyPair.KeyPairId)) + + keyName := aws.StringValue(keyPair.KeyName) + arn := arn.ARN{ + Partition: meta.(*conns.AWSClient).Partition, + Service: ec2.ServiceName, + Region: meta.(*conns.AWSClient).Region, + AccountID: meta.(*conns.AWSClient).AccountID, + Resource: fmt.Sprintf("key-pair/%s", keyName), + }.String() + d.Set("arn", arn) + d.Set("fingerprint", keyPair.KeyFingerprint) + d.Set("key_name", keyName) + d.Set("key_pair_id", keyPair.KeyPairId) + + if err := d.Set("tags", KeyValueTags(keyPair.Tags).IgnoreAWS().IgnoreConfig(ignoreTagsConfig).Map()); err != nil { + return fmt.Errorf("error setting tags: %w", err) + } + + return nil +} diff --git a/internal/service/ec2/key_pair_data_source_test.go b/internal/service/ec2/key_pair_data_source_test.go new file mode 100644 index 00000000000..fa1b1740db5 --- /dev/null +++ b/internal/service/ec2/key_pair_data_source_test.go @@ -0,0 +1,82 @@ +package ec2_test + +import ( + "fmt" + "testing" + + "github.com/aws/aws-sdk-go/service/ec2" + sdkacctest "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-provider-aws/internal/acctest" +) + +func TestAccEC2KeyPairDataSource_basic(t *testing.T) { + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + dataSource1Name := "data.aws_key_pair.by_id" + dataSource2Name := "data.aws_key_pair.by_name" + dataSource3Name := "data.aws_key_pair.by_filter" + resourceName := "aws_key_pair.test" + + publicKey, _, err := sdkacctest.RandSSHKeyPair(acctest.DefaultEmailAddress) + if err != nil { + t.Fatalf("error generating random SSH key: %s", err) + } + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(t) }, + ErrorCheck: acctest.ErrorCheck(t, ec2.EndpointsID), + Providers: acctest.Providers, + Steps: []resource.TestStep{ + { + Config: testAccKeyPairDataSourceConfig(rName, publicKey), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrPair(dataSource1Name, "arn", resourceName, "arn"), + resource.TestCheckResourceAttrPair(dataSource1Name, "fingerprint", resourceName, "fingerprint"), + resource.TestCheckResourceAttrPair(dataSource1Name, "key_name", resourceName, "key_name"), + resource.TestCheckResourceAttrPair(dataSource1Name, "key_pair_id", resourceName, "key_pair_id"), + resource.TestCheckResourceAttrPair(dataSource1Name, "tags.%", resourceName, "tags.%"), + + resource.TestCheckResourceAttrPair(dataSource2Name, "arn", resourceName, "arn"), + resource.TestCheckResourceAttrPair(dataSource2Name, "fingerprint", resourceName, "fingerprint"), + resource.TestCheckResourceAttrPair(dataSource2Name, "key_name", resourceName, "key_name"), + resource.TestCheckResourceAttrPair(dataSource2Name, "key_pair_id", resourceName, "key_pair_id"), + resource.TestCheckResourceAttrPair(dataSource2Name, "tags.%", resourceName, "tags.%"), + + resource.TestCheckResourceAttrPair(dataSource3Name, "arn", resourceName, "arn"), + resource.TestCheckResourceAttrPair(dataSource3Name, "fingerprint", resourceName, "fingerprint"), + resource.TestCheckResourceAttrPair(dataSource3Name, "key_name", resourceName, "key_name"), + resource.TestCheckResourceAttrPair(dataSource3Name, "key_pair_id", resourceName, "key_pair_id"), + resource.TestCheckResourceAttrPair(dataSource3Name, "tags.%", resourceName, "tags.%"), + ), + }, + }, + }) +} + +func testAccKeyPairDataSourceConfig(rName, publicKey string) string { + return fmt.Sprintf(` +data "aws_key_pair" "by_name" { + key_name = aws_key_pair.test.key_name +} + +data "aws_key_pair" "by_id" { + key_pair_id = aws_key_pair.test.key_pair_id +} + +data "aws_key_pair" "by_filter" { + filter { + name = "tag:Name" + values = [aws_key_pair.test.tags["Name"]] + } +} + +resource "aws_key_pair" "test" { + key_name = %[1]q + public_key = %[2]q + + tags = { + Name = %[1]q + } +} +`, rName, publicKey) +} diff --git a/internal/service/ec2/key_pair_test.go b/internal/service/ec2/key_pair_test.go index 7baf595cdbf..5a3ff38f8c5 100644 --- a/internal/service/ec2/key_pair_test.go +++ b/internal/service/ec2/key_pair_test.go @@ -3,18 +3,17 @@ package ec2_test import ( "fmt" "regexp" - "strings" "testing" - "github.com/aws/aws-sdk-go/aws" "github.com/aws/aws-sdk-go/service/ec2" - "github.com/hashicorp/aws-sdk-go-base/tfawserr" sdkacctest "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" "github.com/hashicorp/terraform-provider-aws/internal/acctest" "github.com/hashicorp/terraform-provider-aws/internal/conns" + "github.com/hashicorp/terraform-provider-aws/internal/create" tfec2 "github.com/hashicorp/terraform-provider-aws/internal/service/ec2" + "github.com/hashicorp/terraform-provider-aws/internal/tfresource" ) func TestAccEC2KeyPair_basic(t *testing.T) { @@ -40,6 +39,7 @@ func TestAccEC2KeyPair_basic(t *testing.T) { acctest.CheckResourceAttrRegionalARN(resourceName, "arn", "ec2", fmt.Sprintf("key-pair/%s", rName)), resource.TestMatchResourceAttr(resourceName, "fingerprint", regexp.MustCompile(`[a-f0-9]{2}(:[a-f0-9]{2}){15}`)), resource.TestCheckResourceAttr(resourceName, "key_name", rName), + resource.TestCheckResourceAttr(resourceName, "key_name_prefix", ""), resource.TestCheckResourceAttr(resourceName, "public_key", publicKey), ), }, @@ -104,7 +104,7 @@ func TestAccEC2KeyPair_tags(t *testing.T) { }) } -func TestAccEC2KeyPair_generatedName(t *testing.T) { +func TestAccEC2KeyPair_nameGenerated(t *testing.T) { var keyPair ec2.KeyPairInfo resourceName := "aws_key_pair.test" @@ -120,11 +120,11 @@ func TestAccEC2KeyPair_generatedName(t *testing.T) { CheckDestroy: testAccCheckKeyPairDestroy, Steps: []resource.TestStep{ { - Config: testAccKeyPairConfig_generatedName(publicKey), + Config: testAccKeyPairNameGeneratedConfig(publicKey), Check: resource.ComposeAggregateTestCheckFunc( testAccCheckKeyPairExists(resourceName, &keyPair), - testAccCheckKeyPairKeyNamePrefix(&keyPair, "terraform-"), - resource.TestMatchResourceAttr(resourceName, "key_name", regexp.MustCompile(`^terraform-`)), + create.TestCheckResourceAttrNameGenerated(resourceName, "key_name"), + resource.TestCheckResourceAttr(resourceName, "key_name_prefix", "terraform-"), ), }, { @@ -153,18 +153,18 @@ func TestAccEC2KeyPair_namePrefix(t *testing.T) { CheckDestroy: testAccCheckKeyPairDestroy, Steps: []resource.TestStep{ { - Config: testAccCheckKeyPairPrefixNameConfig(publicKey), + Config: testAccCheckKeyPairNamePrefixConfig("tf-acc-test-prefix-", publicKey), Check: resource.ComposeAggregateTestCheckFunc( testAccCheckKeyPairExists(resourceName, &keyPair), - testAccCheckKeyPairKeyNamePrefix(&keyPair, "baz-"), - resource.TestMatchResourceAttr(resourceName, "key_name", regexp.MustCompile(`^baz-`)), + create.TestCheckResourceAttrNameFromPrefix(resourceName, "key_name", "tf-acc-test-prefix-"), + resource.TestCheckResourceAttr(resourceName, "key_name_prefix", "tf-acc-test-prefix-"), ), }, { ResourceName: resourceName, ImportState: true, ImportStateVerify: true, - ImportStateVerifyIgnore: []string{"key_name_prefix", "public_key"}, + ImportStateVerifyIgnore: []string{"public_key"}, }, }, }) @@ -206,35 +206,23 @@ func testAccCheckKeyPairDestroy(s *terraform.State) error { continue } - // Try to find key pair - resp, err := conn.DescribeKeyPairs(&ec2.DescribeKeyPairsInput{ - KeyNames: []*string{aws.String(rs.Primary.ID)}, - }) - if err == nil { - if len(resp.KeyPairs) > 0 { - return fmt.Errorf("still exist.") - } - return nil + _, err := tfec2.FindKeyPairByName(conn, rs.Primary.ID) + + if tfresource.NotFound(err) { + continue } - if !tfawserr.ErrMessageContains(err, "InvalidKeyPair.NotFound", "") { + if err != nil { return err } + + return fmt.Errorf("EC2 Key Pair %s still exists", rs.Primary.ID) } return nil } -func testAccCheckKeyPairKeyNamePrefix(conf *ec2.KeyPairInfo, namePrefix string) resource.TestCheckFunc { - return func(s *terraform.State) error { - if !strings.HasPrefix(aws.StringValue(conf.KeyName), namePrefix) { - return fmt.Errorf("incorrect key name. expected %s prefix, got %s", namePrefix, aws.StringValue(conf.KeyName)) - } - return nil - } -} - -func testAccCheckKeyPairExists(n string, res *ec2.KeyPairInfo) resource.TestCheckFunc { +func testAccCheckKeyPairExists(n string, v *ec2.KeyPairInfo) resource.TestCheckFunc { return func(s *terraform.State) error { rs, ok := s.RootModule().Resources[n] if !ok { @@ -242,23 +230,18 @@ func testAccCheckKeyPairExists(n string, res *ec2.KeyPairInfo) resource.TestChec } if rs.Primary.ID == "" { - return fmt.Errorf("No KeyPair name is set") + return fmt.Errorf("No EC2 Key Pair ID is set") } conn := acctest.Provider.Meta().(*conns.AWSClient).EC2Conn - resp, err := conn.DescribeKeyPairs(&ec2.DescribeKeyPairsInput{ - KeyNames: []*string{aws.String(rs.Primary.ID)}, - }) + output, err := tfec2.FindKeyPairByName(conn, rs.Primary.ID) + if err != nil { return err } - if len(resp.KeyPairs) != 1 || - aws.StringValue(resp.KeyPairs[0].KeyName) != rs.Primary.ID { - return fmt.Errorf("KeyPair not found") - } - *res = *resp.KeyPairs[0] + *v = *output return nil } @@ -300,7 +283,7 @@ resource "aws_key_pair" "test" { `, rName, publicKey, tagKey1, tagValue1, tagKey2, tagValue2) } -func testAccKeyPairConfig_generatedName(publicKey string) string { +func testAccKeyPairNameGeneratedConfig(publicKey string) string { return fmt.Sprintf(` resource "aws_key_pair" "test" { public_key = %[1]q @@ -308,11 +291,11 @@ resource "aws_key_pair" "test" { `, publicKey) } -func testAccCheckKeyPairPrefixNameConfig(publicKey string) string { +func testAccCheckKeyPairNamePrefixConfig(namePrefix, publicKey string) string { return fmt.Sprintf(` resource "aws_key_pair" "test" { - key_name_prefix = "baz-" - public_key = %[1]q + key_name_prefix = %[1]q + public_key = %[2]q } -`, publicKey) +`, namePrefix, publicKey) } diff --git a/website/docs/d/key_pair.html.markdown b/website/docs/d/key_pair.html.markdown new file mode 100644 index 00000000000..577a47f0b82 --- /dev/null +++ b/website/docs/d/key_pair.html.markdown @@ -0,0 +1,63 @@ +--- +subcategory: "EC2" +layout: "aws" +page_title: "AWS: aws_key_pair" +description: |- + Provides details about a specific EC2 Key Pair. +--- + +# Data Source: aws_key_pair + +Use this data source to get information about a specific EC2 Key Pair. + +## Example Usage + +The following example shows how to get a EC2 Key Pair from its name. + +```terraform +data "aws_key_pair" "example" { + key_name = "test" + filter { + name = "tag:Component" + values = ["web"] + } +} + +output "fingerprint" { + value = data.aws_key_pair.example.fingerprint +} + +output "name" { + value = data.aws_key_pair.example.key_name +} + +output "id" { + value = data.aws_key_pair.example.id +} +``` + +## Argument Reference + +The arguments of this data source act as filters for querying the available +Key Pairs. The given filters must match exactly one Key Pair +whose data will be exported as attributes. + +* `key_id` - (Optional) The Key Pair ID. +* `key_name` - (Optional) The Key Pair name. +* `filter` - (Optional) Custom filter block as described below. + +### filter Configuration Block + +The following arguments are supported by the `filter` configuration block: + +* `name` - (Required) The name of the filter field. Valid values can be found in the [EC2 DescribeKeyPairs API Reference](https://docs.aws.amazon.com/AWSEC2/latest/APIReference/API_DescribeKeyPairs.html). +* `values` - (Required) Set of values that are accepted for the given filter field. Results will be selected if any given value matches. + +## Attributes Reference + +In addition to all arguments above, the following attributes are exported: + +* `id` - ID of the Key Pair. +* `arn` - The ARN of the Key Pair. +* `fingerprint` - The SHA-1 digest of the DER encoded private key. +* `tags` - Any tags assigned to the Key Pair. \ No newline at end of file