From 6d08463cfda892e757f77ae533a956c5b4b7b5d8 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Wed, 20 Feb 2019 12:34:53 -0500 Subject: [PATCH 1/2] Add 'aws_ec2_client_vpn_endpoint.tags' attribute. --- aws/resource_aws_ec2_client_vpn_endpoint.go | 19 ++- ...source_aws_ec2_client_vpn_endpoint_test.go | 137 ++++++++++++++++++ aws/tags.go | 14 ++ .../r/ec2_client_vpn_endpoint.html.markdown | 5 +- 4 files changed, 171 insertions(+), 4 deletions(-) diff --git a/aws/resource_aws_ec2_client_vpn_endpoint.go b/aws/resource_aws_ec2_client_vpn_endpoint.go index dc0b5694a2b..b80f794730b 100644 --- a/aws/resource_aws_ec2_client_vpn_endpoint.go +++ b/aws/resource_aws_ec2_client_vpn_endpoint.go @@ -108,6 +108,7 @@ func resourceAwsEc2ClientVpnEndpoint() *schema.Resource { Type: schema.TypeString, Computed: true, }, + "tags": tagsSchema(), }, } } @@ -119,6 +120,7 @@ func resourceAwsEc2ClientVpnEndpointCreate(d *schema.ResourceData, meta interfac ClientCidrBlock: aws.String(d.Get("client_cidr_block").(string)), ServerCertificateArn: aws.String(d.Get("server_certificate_arn").(string)), TransportProtocol: aws.String(d.Get("transport_protocol").(string)), + TagSpecifications: tagSpecificationsFromMap(d.Get("tags").(map[string]interface{}), ec2.ResourceTypeClientVpnEndpoint), } if v, ok := d.GetOk("description"); ok { @@ -235,6 +237,11 @@ func resourceAwsEc2ClientVpnEndpointRead(d *schema.ResourceData, meta interface{ return err } + err = d.Set("tags", tagsToMap(result.ClientVpnEndpoints[0].Tags)) + if err != nil { + return err + } + return nil } @@ -254,6 +261,8 @@ func resourceAwsEc2ClientVpnEndpointDelete(d *schema.ResourceData, meta interfac func resourceAwsEc2ClientVpnEndpointUpdate(d *schema.ResourceData, meta interface{}) error { conn := meta.(*AWSClient).ec2conn + d.Partial(true) + req := &ec2.ModifyClientVpnEndpointInput{ ClientVpnEndpointId: aws.String(d.Id()), } @@ -304,11 +313,17 @@ func resourceAwsEc2ClientVpnEndpointUpdate(d *schema.ResourceData, meta interfac } } - _, err := conn.ModifyClientVpnEndpoint(req) - if err != nil { + if _, err := conn.ModifyClientVpnEndpoint(req); err != nil { return fmt.Errorf("Error modifying Client VPN endpoint: %s", err) } + if err := setTags(conn, d); err != nil { + return err + } else { + d.SetPartial("tags") + } + + d.Partial(false) return resourceAwsEc2ClientVpnEndpointRead(d, meta) } diff --git a/aws/resource_aws_ec2_client_vpn_endpoint_test.go b/aws/resource_aws_ec2_client_vpn_endpoint_test.go index 99caba0ede5..17f2f1940da 100644 --- a/aws/resource_aws_ec2_client_vpn_endpoint_test.go +++ b/aws/resource_aws_ec2_client_vpn_endpoint_test.go @@ -126,6 +126,42 @@ func TestAccAwsEc2ClientVpnEndpoint_withDNSServers(t *testing.T) { }) } +func TestAccAwsEc2ClientVpnEndpoint_tags(t *testing.T) { + resourceName := "aws_ec2_client_vpn_endpoint.test" + rStr := acctest.RandString(5) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProvidersWithTLS, + CheckDestroy: testAccCheckAwsEc2ClientVpnEndpointDestroy, + Steps: []resource.TestStep{ + { + Config: testAccEc2ClientVpnEndpointConfig_tags(rStr), + Check: resource.ComposeTestCheckFunc( + testAccCheckAwsEc2ClientVpnEndpointExists(resourceName), + resource.TestCheckResourceAttr(resourceName, "tags.%", "2"), + resource.TestCheckResourceAttr(resourceName, "tags.Usage", "original"), + ), + }, + { + Config: testAccEc2ClientVpnEndpointConfig_tagsChanged(rStr), + Check: resource.ComposeTestCheckFunc( + testAccCheckAwsEc2ClientVpnEndpointExists(resourceName), + resource.TestCheckResourceAttr(resourceName, "tags.%", "1"), + resource.TestCheckResourceAttr(resourceName, "tags.Usage", "changed"), + ), + }, + { + Config: testAccEc2ClientVpnEndpointConfig(rStr), + Check: resource.ComposeTestCheckFunc( + testAccCheckAwsEc2ClientVpnEndpointExists(resourceName), + resource.TestCheckResourceAttr(resourceName, "tags.%", "0"), + ), + }, + }, + }) +} + func testAccCheckAwsEc2ClientVpnEndpointDestroy(s *terraform.State) error { conn := testAccProvider.Meta().(*AWSClient).ec2conn @@ -383,3 +419,104 @@ resource "aws_ec2_client_vpn_endpoint" "test" { } `, rName) } + +func testAccEc2ClientVpnEndpointConfig_tags(rName string) string { + return fmt.Sprintf(` +resource "tls_private_key" "example" { + algorithm = "RSA" +} + +resource "tls_self_signed_cert" "example" { + key_algorithm = "RSA" + private_key_pem = "${tls_private_key.example.private_key_pem}" + + subject { + common_name = "example.com" + organization = "ACME Examples, Inc" + } + + validity_period_hours = 12 + + allowed_uses = [ + "key_encipherment", + "digital_signature", + "server_auth", + ] +} + +resource "aws_acm_certificate" "cert" { + private_key = "${tls_private_key.example.private_key_pem}" + certificate_body = "${tls_self_signed_cert.example.cert_pem}" +} + +resource "aws_ec2_client_vpn_endpoint" "test" { + description = "terraform-testacc-clientvpn-%s" + server_certificate_arn = "${aws_acm_certificate.cert.arn}" + client_cidr_block = "10.0.0.0/16" + + authentication_options { + type = "certificate-authentication" + root_certificate_chain_arn = "${aws_acm_certificate.cert.arn}" + } + + connection_log_options { + enabled = false + } + + tags = { + Environment = "production" + Usage = "original" + } +} +`, rName) +} + +func testAccEc2ClientVpnEndpointConfig_tagsChanged(rName string) string { + return fmt.Sprintf(` +resource "tls_private_key" "example" { + algorithm = "RSA" +} + +resource "tls_self_signed_cert" "example" { + key_algorithm = "RSA" + private_key_pem = "${tls_private_key.example.private_key_pem}" + + subject { + common_name = "example.com" + organization = "ACME Examples, Inc" + } + + validity_period_hours = 12 + + allowed_uses = [ + "key_encipherment", + "digital_signature", + "server_auth", + ] +} + +resource "aws_acm_certificate" "cert" { + private_key = "${tls_private_key.example.private_key_pem}" + certificate_body = "${tls_self_signed_cert.example.cert_pem}" +} + +resource "aws_ec2_client_vpn_endpoint" "test" { + description = "terraform-testacc-clientvpn-%s" + server_certificate_arn = "${aws_acm_certificate.cert.arn}" + client_cidr_block = "10.0.0.0/16" + + authentication_options { + type = "certificate-authentication" + root_certificate_chain_arn = "${aws_acm_certificate.cert.arn}" + } + + connection_log_options { + enabled = false + } + + tags = { + Usage = "changed" + } +} +`, rName) +} diff --git a/aws/tags.go b/aws/tags.go index 05851126846..29c02c76dcc 100644 --- a/aws/tags.go +++ b/aws/tags.go @@ -476,3 +476,17 @@ func tagsMapToRaw(m map[string]string) map[string]interface{} { return raw } + +// tagSpecificationsFromMap returns the tag specifications for the given map of data and resource type. +func tagSpecificationsFromMap(m map[string]interface{}, t string) []*ec2.TagSpecification { + if len(m) == 0 { + return nil + } + + return []*ec2.TagSpecification{ + { + ResourceType: aws.String(t), + Tags: tagsFromMap(m), + }, + } +} diff --git a/website/docs/r/ec2_client_vpn_endpoint.html.markdown b/website/docs/r/ec2_client_vpn_endpoint.html.markdown index 452e62154dc..9f052069100 100644 --- a/website/docs/r/ec2_client_vpn_endpoint.html.markdown +++ b/website/docs/r/ec2_client_vpn_endpoint.html.markdown @@ -8,7 +8,7 @@ description: |- # aws_ec2_client_vpn_endpoint -Provides an AWS Client VPN endpoint for OpenVPN clients. For more information on usage, please see the +Provides an AWS Client VPN endpoint for OpenVPN clients. For more information on usage, please see the [AWS Client VPN Administrator's Guide](https://docs.aws.amazon.com/vpn/latest/clientvpn-admin/what-is.html). ## Example Usage @@ -43,6 +43,7 @@ The following arguments are supported: * `transport_protocol` - (Optional) The transport protocol to be used by the VPN session. Default value is `udp`. * `authentication_options` - (Required) Information about the authentication method to be used to authenticate clients. * `connection_log_options` - (Required) Information about the client connection logging options. +* `tags` - (Optional) A mapping of tags to assign to the resource. ### `authentication_options` Argument Reference @@ -64,7 +65,7 @@ One of the following arguments must be supplied: In addition to all arguments above, the following attributes are exported: -* `id` - The ID of the Client VPN endpoint. +* `id` - The ID of the Client VPN endpoint. * `dns_name` - The DNS name to be used by clients when establishing their VPN session. * `status` - The current state of the Client VPN endpoint. From 7feacd23b4e919d1d77712b8c0a7a1b667a5a943 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Mon, 4 Mar 2019 12:53:29 -0500 Subject: [PATCH 2/2] Changes after code review. --- aws/resource_aws_ec2_client_vpn_endpoint.go | 11 +++++------ aws/tags.go | 4 ++-- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/aws/resource_aws_ec2_client_vpn_endpoint.go b/aws/resource_aws_ec2_client_vpn_endpoint.go index b80f794730b..dbfab48cac4 100644 --- a/aws/resource_aws_ec2_client_vpn_endpoint.go +++ b/aws/resource_aws_ec2_client_vpn_endpoint.go @@ -120,7 +120,7 @@ func resourceAwsEc2ClientVpnEndpointCreate(d *schema.ResourceData, meta interfac ClientCidrBlock: aws.String(d.Get("client_cidr_block").(string)), ServerCertificateArn: aws.String(d.Get("server_certificate_arn").(string)), TransportProtocol: aws.String(d.Get("transport_protocol").(string)), - TagSpecifications: tagSpecificationsFromMap(d.Get("tags").(map[string]interface{}), ec2.ResourceTypeClientVpnEndpoint), + TagSpecifications: ec2TagSpecificationsFromMap(d.Get("tags").(map[string]interface{}), ec2.ResourceTypeClientVpnEndpoint), } if v, ok := d.GetOk("description"); ok { @@ -229,17 +229,17 @@ func resourceAwsEc2ClientVpnEndpointRead(d *schema.ResourceData, meta interface{ err = d.Set("authentication_options", flattenAuthOptsConfig(result.ClientVpnEndpoints[0].AuthenticationOptions)) if err != nil { - return err + return fmt.Errorf("error setting authentication_options: %s", err) } err = d.Set("connection_log_options", flattenConnLoggingConfig(result.ClientVpnEndpoints[0].ConnectionLogOptions)) if err != nil { - return err + return fmt.Errorf("error setting connection_log_options: %s", err) } err = d.Set("tags", tagsToMap(result.ClientVpnEndpoints[0].Tags)) if err != nil { - return err + return fmt.Errorf("error setting tags: %s", err) } return nil @@ -319,9 +319,8 @@ func resourceAwsEc2ClientVpnEndpointUpdate(d *schema.ResourceData, meta interfac if err := setTags(conn, d); err != nil { return err - } else { - d.SetPartial("tags") } + d.SetPartial("tags") d.Partial(false) return resourceAwsEc2ClientVpnEndpointRead(d, meta) diff --git a/aws/tags.go b/aws/tags.go index 29c02c76dcc..41dcddc8bd1 100644 --- a/aws/tags.go +++ b/aws/tags.go @@ -477,8 +477,8 @@ func tagsMapToRaw(m map[string]string) map[string]interface{} { return raw } -// tagSpecificationsFromMap returns the tag specifications for the given map of data and resource type. -func tagSpecificationsFromMap(m map[string]interface{}, t string) []*ec2.TagSpecification { +// ec2TagSpecificationsFromMap returns the tag specifications for the given map of data m and resource type t. +func ec2TagSpecificationsFromMap(m map[string]interface{}, t string) []*ec2.TagSpecification { if len(m) == 0 { return nil }