Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

New resource: aws_lightsail_instance_public_ports #8611

Merged
merged 10 commits into from
Mar 25, 2021
3 changes: 3 additions & 0 deletions .changelog/8611.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
```release-note:new-resource
aws_lightsail_instance_public_ports
```
1 change: 1 addition & 0 deletions aws/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -818,6 +818,7 @@ func Provider() *schema.Provider {
"aws_licensemanager_license_configuration": resourceAwsLicenseManagerLicenseConfiguration(),
"aws_lightsail_domain": resourceAwsLightsailDomain(),
"aws_lightsail_instance": resourceAwsLightsailInstance(),
"aws_lightsail_instance_public_ports": resourceAwsLightsailInstancePublicPorts(),
"aws_lightsail_key_pair": resourceAwsLightsailKeyPair(),
"aws_lightsail_static_ip": resourceAwsLightsailStaticIp(),
"aws_lightsail_static_ip_attachment": resourceAwsLightsailStaticIpAttachment(),
Expand Down
214 changes: 214 additions & 0 deletions aws/resource_aws_lightsail_instance_public_ports.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,214 @@
package aws

import (
"bytes"
"fmt"
"log"

"github.com/aws/aws-sdk-go/aws"
"github.com/aws/aws-sdk-go/service/lightsail"
"github.com/hashicorp/aws-sdk-go-base/tfawserr"
multierror "github.com/hashicorp/go-multierror"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation"
"github.com/terraform-providers/terraform-provider-aws/aws/internal/hashcode"
)

func resourceAwsLightsailInstancePublicPorts() *schema.Resource {
return &schema.Resource{
Create: resourceAwsLightsailInstancePublicPortsCreate,
Read: resourceAwsLightsailInstancePublicPortsRead,
Delete: resourceAwsLightsailInstancePublicPortsDelete,

Schema: map[string]*schema.Schema{
"instance_name": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
},
"port_info": {
Type: schema.TypeSet,
Required: true,
ForceNew: true,
MinItems: 1,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"from_port": {
Type: schema.TypeInt,
Required: true,
ForceNew: true,
ValidateFunc: validation.IntBetween(0, 65535),
},
"protocol": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
ValidateFunc: validation.StringInSlice(lightsail.NetworkProtocol_Values(), false),
},
"to_port": {
Type: schema.TypeInt,
Required: true,
ForceNew: true,
ValidateFunc: validation.IntBetween(0, 65535),
},
},
},
},
},
}
}

func resourceAwsLightsailInstancePublicPortsCreate(d *schema.ResourceData, meta interface{}) error {
conn := meta.(*AWSClient).lightsailconn

var portInfos []*lightsail.PortInfo
if v, ok := d.GetOk("port_info"); ok && v.(*schema.Set).Len() > 0 {
portInfos = expandLightsailPortInfos(v.(*schema.Set).List())
}

input := &lightsail.PutInstancePublicPortsInput{
InstanceName: aws.String(d.Get("instance_name").(string)),
PortInfos: portInfos,
}

_, err := conn.PutInstancePublicPorts(input)

if err != nil {
return fmt.Errorf("unable to create public ports for instance %s: %w", d.Get("instance_name").(string), err)
}

var buffer bytes.Buffer
for _, portInfo := range portInfos {
buffer.WriteString(fmt.Sprintf("%s-%d-%d\n", aws.StringValue(portInfo.Protocol), aws.Int64Value(portInfo.FromPort), aws.Int64Value(portInfo.ToPort)))
}

d.SetId(fmt.Sprintf("%s-%d", d.Get("instance_name").(string), hashcode.String(buffer.String())))

return resourceAwsLightsailInstancePublicPortsRead(d, meta)
}

func resourceAwsLightsailInstancePublicPortsRead(d *schema.ResourceData, meta interface{}) error {
conn := meta.(*AWSClient).lightsailconn

input := &lightsail.GetInstancePortStatesInput{
InstanceName: aws.String(d.Get("instance_name").(string)),
}

output, err := conn.GetInstancePortStates(input)

if !d.IsNewResource() && tfawserr.ErrCodeEquals(err, "NotFoundException") {
log.Printf("[WARN] Lightsail instance public ports (%s) not found, removing from state", d.Id())
d.SetId("")
return nil
}

if err != nil {
return fmt.Errorf("error reading Lightsail instance public ports (%s): %w", d.Id(), err)
}

if err := d.Set("port_info", flattenLightsailInstancePortStates(output.PortStates)); err != nil {
return fmt.Errorf("error setting port_info: %w", err)
}

return nil
}

func resourceAwsLightsailInstancePublicPortsDelete(d *schema.ResourceData, meta interface{}) error {
conn := meta.(*AWSClient).lightsailconn

var err *multierror.Error

var portInfos []*lightsail.PortInfo
if v, ok := d.GetOk("port_info"); ok && v.(*schema.Set).Len() > 0 {
portInfos = expandLightsailPortInfos(v.(*schema.Set).List())
}

for _, portInfo := range portInfos {
_, portError := conn.CloseInstancePublicPorts(&lightsail.CloseInstancePublicPortsInput{
InstanceName: aws.String(d.Get("instance_name").(string)),
PortInfo: portInfo,
})

if portError != nil {
err = multierror.Append(err, portError)
}
}

if err != nil {
return fmt.Errorf("unable to close public ports for instance %s: %w", d.Get("instance_name").(string), err)
}

return nil
}

func expandLightsailPortInfo(tfMap map[string]interface{}) *lightsail.PortInfo {
if tfMap == nil {
return nil
}

apiObject := &lightsail.PortInfo{
FromPort: aws.Int64((int64)(tfMap["from_port"].(int))),
ToPort: aws.Int64((int64)(tfMap["to_port"].(int))),
Protocol: aws.String(tfMap["protocol"].(string)),
}

return apiObject
}

func expandLightsailPortInfos(tfList []interface{}) []*lightsail.PortInfo {
if len(tfList) == 0 {
return nil
}

var apiObjects []*lightsail.PortInfo

for _, tfMapRaw := range tfList {
tfMap, ok := tfMapRaw.(map[string]interface{})

if !ok {
continue
}

apiObject := expandLightsailPortInfo(tfMap)

if apiObject == nil {
continue
}

apiObjects = append(apiObjects, apiObject)
}

return apiObjects
}

func flattenLightsailInstancePortState(apiObject *lightsail.InstancePortState) map[string]interface{} {
if apiObject == nil {
return nil
}

tfMap := map[string]interface{}{}

tfMap["from_port"] = aws.Int64Value(apiObject.FromPort)
tfMap["to_port"] = aws.Int64Value(apiObject.ToPort)
tfMap["protocol"] = aws.StringValue(apiObject.Protocol)

return tfMap
}

func flattenLightsailInstancePortStates(apiObjects []*lightsail.InstancePortState) []interface{} {
if len(apiObjects) == 0 {
return nil
}

var tfList []interface{}

for _, apiObject := range apiObjects {
if apiObject == nil {
continue
}

tfList = append(tfList, flattenLightsailInstancePortState(apiObject))
}

return tfList
}
Loading