Skip to content

Commit

Permalink
d/aws_key_pair: New code structure.
Browse files Browse the repository at this point in the history
Acceptance test output:

% make testacc PKG_NAME=internal/service/ec2 TESTARGS='-run=TestAccEC2KeyPairDataSource_basic'
==> Checking that code complies with gofmt requirements...
TF_ACC=1 go test ./internal/service/ec2/... -v -count 1 -parallel 20 -run=TestAccEC2KeyPairDataSource_basic -timeout 180m
=== RUN   TestAccEC2KeyPairDataSource_basic
=== PAUSE TestAccEC2KeyPairDataSource_basic
=== CONT  TestAccEC2KeyPairDataSource_basic
--- PASS: TestAccEC2KeyPairDataSource_basic (14.10s)
PASS
ok  	github.com/hashicorp/terraform-provider-aws/internal/service/ec2	17.678s
  • Loading branch information
ewbankkit committed Nov 10, 2021
1 parent ea9ffc7 commit 7f099e4
Show file tree
Hide file tree
Showing 6 changed files with 181 additions and 70 deletions.
1 change: 1 addition & 0 deletions internal/provider/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -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(),
Expand Down
1 change: 1 addition & 0 deletions internal/service/ec2/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ const (
ErrCodeGatewayNotAttached = "Gateway.NotAttached"
ErrCodeInvalidAssociationIDNotFound = "InvalidAssociationID.NotFound"
ErrCodeInvalidAttachmentIDNotFound = "InvalidAttachmentID.NotFound"
ErrCodeInvalidKeyPairNotFound = "InvalidKeyPair.NotFound"
ErrCodeInvalidParameter = "InvalidParameter"
ErrCodeInvalidParameterException = "InvalidParameterException"
ErrCodeInvalidParameterValue = "InvalidParameterValue"
Expand Down
56 changes: 56 additions & 0 deletions internal/service/ec2/find.go
Original file line number Diff line number Diff line change
Expand Up @@ -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}),
Expand Down
81 changes: 49 additions & 32 deletions internal/service/ec2/key_pair_data_source.go
Original file line number Diff line number Diff line change
@@ -1,69 +1,86 @@
package aws
package ec2

import (
"errors"
"fmt"
"log"

"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 dataSourceAwsKeyPair() *schema.Resource {
func DataSourceKeyPair() *schema.Resource {
return &schema.Resource{
Read: dataSourceAwsKeyPairRead,
Read: dataSourceKeyPairRead,

Schema: map[string]*schema.Schema{
"key_name": {
"arn": {
Type: schema.TypeString,
Required: true,
Computed: true,
},
"filter": DataSourceFiltersSchema(),
"fingerprint": {
Type: schema.TypeString,
Computed: true,
},
"filter": dataSourceFiltersSchema(),
"key_name": {
Type: schema.TypeString,
Optional: true,
},
"key_pair_id": {
Type: schema.TypeString,
Optional: true,
},
"tags": tftags.TagsSchemaComputed(),
},
}
}

func dataSourceAwsKeyPairRead(d *schema.ResourceData, meta interface{}) error {
conn := meta.(*AWSClient).ec2conn
func dataSourceKeyPairRead(d *schema.ResourceData, meta interface{}) error {
conn := meta.(*conns.AWSClient).EC2Conn
ignoreTagsConfig := meta.(*conns.AWSClient).IgnoreTagsConfig

params := &ec2.DescribeKeyPairsInput{}
filters, filtersOk := d.GetOk("filter")
if filtersOk {
params.Filters = buildAwsDataSourceFilters(filters.(*schema.Set))
}

keyName := d.Get("key_name").(string)
input := &ec2.DescribeKeyPairsInput{}

params.KeyNames = []*string{
aws.String(keyName),
if v, ok := d.GetOk("filter"); ok {
input.Filters = BuildFiltersDataSource(v.(*schema.Set))
}

log.Printf("[DEBUG] Reading key pair: %s", keyName)
resp, err := conn.DescribeKeyPairs(params)
if err != nil {
return fmt.Errorf("error describing EC2 Key Pairs: %w", err)
if v, ok := d.GetOk("key_name"); ok {
input.KeyNames = aws.StringSlice([]string{v.(string)})
}

if resp == nil || len(resp.KeyPairs) == 0 {
return errors.New("no matching Key Pair found")
if v, ok := d.GetOk("key_pair_id"); ok {
input.KeyPairIds = aws.StringSlice([]string{v.(string)})
}

filteredKeyPair := resp.KeyPairs
keyPair, err := FindKeyPair(conn, input)

if len(filteredKeyPair) > 1 {
return fmt.Errorf("Your query returned more than one result. Please try a more " +
"specific search criteria")
if err != nil {
return tfresource.SingularDataSourceFindError("EC2 Key Pair", err)
}

keyPair := filteredKeyPair[0]
log.Printf("[DEBUG] aws_key_pair - Single key pair found: %s", *keyPair.KeyName)
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.SetId(aws.StringValue(keyPair.KeyPairId))
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
}
77 changes: 56 additions & 21 deletions internal/service/ec2/key_pair_data_source_test.go
Original file line number Diff line number Diff line change
@@ -1,47 +1,82 @@
package aws
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 TestAccDataSourceAwsKeyPair_basic(t *testing.T) {
keyName, publicKey := "testKey", "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQD3F6tyPEFEzV0LX3X8BsXdMsQz1x2cEikKDEY0aIj41qgxMCP/iteneqXSIFZBp5vizPvaoIR3Um9xK7PGoW8giupGn+EPuxIA4cDM4vzOqOkiMPhz5XK0whEjkVzTo4+S0puvDZuwIsdiW9mxhJc7tgBNL0cYlWSYVkz4G/fslNfRPW5mYAM49f4fhtxPb5ok4Q2Lg9dPKVHO/Bgeu5woMc7RY0p1ej6D4CKFE6lymSDJpW0YHX/wqE9+cfEauh7xZcG0q9t2ta6F6fmX0agvpFyZo8aFbXeUBr7osSCJNgvavWbM/06niWrOvYX2xwWdhXmXSrbX8ZbabVohBK41 email@example.com"
resourceName := "data.aws_key_pair.default"
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() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckVolumeDestroy,
PreCheck: func() { acctest.PreCheck(t) },
ErrorCheck: acctest.ErrorCheck(t, ec2.EndpointsID),
Providers: acctest.Providers,
Steps: []resource.TestStep{
{
Config: testAccDataSourceAwsKeyPairConfig(keyName, publicKey),
Config: testAccKeyPairDataSourceConfig(rName, publicKey),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr(resourceName, "key_name", keyName),
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 testAccDataSourceAwsKeyPairConfig(keyName, publicKey string) string {
func testAccKeyPairDataSourceConfig(rName, publicKey string) string {
return fmt.Sprintf(`
data "aws_region" "current" {}
resource "aws_key_pair" "default" {
data "aws_key_pair" "by_name" {
key_name = aws_key_pair.test.key_name
}
key_name = "%s"
public_key = "%s"
data "aws_key_pair" "by_id" {
key_pair_id = aws_key_pair.test.key_pair_id
}
tags = {
TestIdentifierSet = "testAccDataSourceAwsKeyPair"
data "aws_key_pair" "by_filter" {
filter {
name = "tag:Name"
values = [aws_key_pair.test.tags["Name"]]
}
}
data "aws_key_pair" "default" {
key_name = aws_key_pair.default.key_name
}
resource "aws_key_pair" "test" {
key_name = %[1]q
public_key = %[2]q
`, keyName, publicKey)
tags = {
Name = %[1]q
}
}
`, rName, publicKey)
}
35 changes: 18 additions & 17 deletions website/docs/d/key_pair.html.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -3,21 +3,18 @@ subcategory: "EC2"
layout: "aws"
page_title: "AWS: aws_key_pair"
description: |-
Provides details about a specific EC2 Key Pair
Provides details about a specific EC2 Key Pair.
---

# Data Source: aws_key_pair

`aws_key_pair` provides details about a specific EC2 Key Pair.

This data source allows to find a EC2 Key Pair given name and certain search criteria.
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.


```hcl
```terraform
data "aws_key_pair" "example" {
key_name = "test"
filter {
Expand All @@ -42,21 +39,25 @@ output "id" {
## Argument Reference

The arguments of this data source act as filters for querying the available
Key Pairs. The given filter must match exactly one Key Pairs.

* `key_name` - (Required) The Key Pair name.
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.

## Attributes Reference
### filter Configuration Block

The following arguments are supported by the `filter` configuration block:

All of the argument attributes except `filter` blocks are also exported as
result attributes. This data source will complete the data by populating
any fields that are not included in the configuration with the data for
the selected Key Pair.
* `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.

The following attributes are additionally exported:
## Attributes Reference

* `id` - Amazon Resource Name (ARN) of Key Pair
* `fingerprint` - The SHA-1 digest of the DER encoded private key..
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.

0 comments on commit 7f099e4

Please sign in to comment.