Skip to content

Commit

Permalink
Merge pull request #15829 from pkruk/feature/ds_key_pair
Browse files Browse the repository at this point in the history
Feature/ds key pair
  • Loading branch information
ewbankkit authored Nov 10, 2021
2 parents ca2cb28 + ca339df commit ecf630a
Show file tree
Hide file tree
Showing 9 changed files with 372 additions and 110 deletions.
3 changes: 3 additions & 0 deletions .changelog/15829.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
```release-note:new-data-source
aws_key_pair
```
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
117 changes: 52 additions & 65 deletions internal/service/ec2/key_pair.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
)

Expand All @@ -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,
Expand All @@ -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,
},
},
}
}
Expand All @@ -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)
}
Expand All @@ -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 {
Expand All @@ -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
}

Expand All @@ -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)
}
}

Expand All @@ -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
}
86 changes: 86 additions & 0 deletions internal/service/ec2/key_pair_data_source.go
Original file line number Diff line number Diff line change
@@ -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
}
Loading

0 comments on commit ecf630a

Please sign in to comment.