Skip to content

Commit 9372a5e

Browse files
authored
Merge pull request #27339 from brittandeyoung/f-aws_lightsail_lb
New Resources: `aws_lightsail_lb` and `aws_lightsail_lb_attachment`
2 parents 2d2308a + d59ab53 commit 9372a5e

File tree

10 files changed

+1083
-4
lines changed

10 files changed

+1083
-4
lines changed

.changelog/27339.txt

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
```release-note:new-resource
2+
aws_lightsail_lb
3+
```
4+
5+
```release-note:new-resource
6+
aws_lightsail_lb_attachment
7+
```

internal/provider/provider.go

+2
Original file line numberDiff line numberDiff line change
@@ -1715,6 +1715,8 @@ func New(_ context.Context) (*schema.Provider, error) {
17151715
"aws_lightsail_instance": lightsail.ResourceInstance(),
17161716
"aws_lightsail_instance_public_ports": lightsail.ResourceInstancePublicPorts(),
17171717
"aws_lightsail_key_pair": lightsail.ResourceKeyPair(),
1718+
"aws_lightsail_lb": lightsail.ResourceLoadBalancer(),
1719+
"aws_lightsail_lb_attachment": lightsail.ResourceLoadBalancerAttachment(),
17181720
"aws_lightsail_static_ip": lightsail.ResourceStaticIP(),
17191721
"aws_lightsail_static_ip_attachment": lightsail.ResourceStaticIPAttachment(),
17201722

internal/service/lightsail/consts.go

+6-4
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
11
package lightsail
22

33
const (
4-
ResCertificate = "Certificate"
5-
ResDatabase = "Database"
6-
ResTags = "Tags"
7-
ResDomainEntry = "Domain Entry"
4+
ResCertificate = "Certificate"
5+
ResDatabase = "Database"
6+
ResTags = "Tags"
7+
ResDomainEntry = "Domain Entry"
8+
ResLoadBalancer = "Load Balancer"
9+
ResLoadBalancerAttachment = "Load Balancer Attachment"
810
)

internal/service/lightsail/find.go

+66
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ package lightsail
22

33
import (
44
"context"
5+
"errors"
56
"strings"
67

78
"github.com/aws/aws-sdk-go/aws"
@@ -155,3 +156,68 @@ func FindDomainEntryById(ctx context.Context, conn *lightsail.Lightsail, id stri
155156

156157
return entry, nil
157158
}
159+
160+
func FindLoadBalancerByName(ctx context.Context, conn *lightsail.Lightsail, name string) (*lightsail.LoadBalancer, error) {
161+
in := &lightsail.GetLoadBalancerInput{LoadBalancerName: aws.String(name)}
162+
out, err := conn.GetLoadBalancerWithContext(ctx, in)
163+
164+
if tfawserr.ErrCodeEquals(err, lightsail.ErrCodeNotFoundException) {
165+
return nil, &resource.NotFoundError{
166+
LastError: err,
167+
LastRequest: in,
168+
}
169+
}
170+
171+
if err != nil {
172+
return nil, err
173+
}
174+
175+
if out == nil || out.LoadBalancer == nil {
176+
return nil, tfresource.NewEmptyResultError(in)
177+
}
178+
179+
lb := out.LoadBalancer
180+
181+
return lb, nil
182+
}
183+
184+
func FindLoadBalancerAttachmentById(ctx context.Context, conn *lightsail.Lightsail, id string) (*string, error) {
185+
id_parts := strings.SplitN(id, ",", -1)
186+
if len(id_parts) != 2 {
187+
return nil, errors.New("invalid load balancer attachment id")
188+
}
189+
190+
lbName := id_parts[0]
191+
iName := id_parts[1]
192+
193+
in := &lightsail.GetLoadBalancerInput{LoadBalancerName: aws.String(lbName)}
194+
out, err := conn.GetLoadBalancerWithContext(ctx, in)
195+
196+
if tfawserr.ErrCodeEquals(err, lightsail.ErrCodeNotFoundException) {
197+
return nil, &resource.NotFoundError{
198+
LastError: err,
199+
LastRequest: in,
200+
}
201+
}
202+
203+
if err != nil {
204+
return nil, err
205+
}
206+
207+
var entry *string
208+
entryExists := false
209+
210+
for _, n := range out.LoadBalancer.InstanceHealthSummary {
211+
if iName == aws.StringValue(n.InstanceName) {
212+
entry = n.InstanceName
213+
entryExists = true
214+
break
215+
}
216+
}
217+
218+
if !entryExists {
219+
return nil, tfresource.NewEmptyResultError(in)
220+
}
221+
222+
return entry, nil
223+
}

internal/service/lightsail/lb.go

+246
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,246 @@
1+
package lightsail
2+
3+
import (
4+
"context"
5+
"errors"
6+
"regexp"
7+
"time"
8+
9+
"github.com/aws/aws-sdk-go/aws"
10+
"github.com/aws/aws-sdk-go/service/lightsail"
11+
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
12+
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
13+
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation"
14+
"github.com/hashicorp/terraform-provider-aws/internal/conns"
15+
"github.com/hashicorp/terraform-provider-aws/internal/create"
16+
tftags "github.com/hashicorp/terraform-provider-aws/internal/tags"
17+
"github.com/hashicorp/terraform-provider-aws/internal/tfresource"
18+
"github.com/hashicorp/terraform-provider-aws/internal/verify"
19+
"github.com/hashicorp/terraform-provider-aws/names"
20+
)
21+
22+
func ResourceLoadBalancer() *schema.Resource {
23+
return &schema.Resource{
24+
CreateWithoutTimeout: resourceLoadBalancerCreate,
25+
ReadWithoutTimeout: resourceLoadBalancerRead,
26+
UpdateWithoutTimeout: resourceLoadBalancerUpdate,
27+
DeleteWithoutTimeout: resourceLoadBalancerDelete,
28+
29+
Importer: &schema.ResourceImporter{
30+
StateContext: schema.ImportStatePassthroughContext,
31+
},
32+
33+
Schema: map[string]*schema.Schema{
34+
"arn": {
35+
Type: schema.TypeString,
36+
Computed: true,
37+
},
38+
"created_at": {
39+
Type: schema.TypeString,
40+
Computed: true,
41+
},
42+
"dns_name": {
43+
Type: schema.TypeString,
44+
Computed: true,
45+
},
46+
"health_check_path": {
47+
Type: schema.TypeString,
48+
Optional: true,
49+
Default: "/",
50+
},
51+
"instance_port": {
52+
Type: schema.TypeInt,
53+
Required: true,
54+
ForceNew: true,
55+
ValidateFunc: validation.IntBetween(0, 65535),
56+
},
57+
"ip_address_type": {
58+
Type: schema.TypeString,
59+
Optional: true,
60+
Default: "dualstack",
61+
ValidateFunc: validation.StringInSlice([]string{
62+
"dualstack",
63+
"ipv4",
64+
}, false),
65+
},
66+
"protocol": {
67+
Type: schema.TypeString,
68+
Computed: true,
69+
},
70+
"public_ports": {
71+
Type: schema.TypeList,
72+
Computed: true,
73+
Elem: &schema.Schema{Type: schema.TypeInt},
74+
},
75+
"name": {
76+
Type: schema.TypeString,
77+
Required: true,
78+
ForceNew: true,
79+
ValidateFunc: validation.All(
80+
validation.StringLenBetween(2, 255),
81+
validation.StringMatch(regexp.MustCompile(`^[a-zA-Z]`), "must begin with an alphabetic character"),
82+
validation.StringMatch(regexp.MustCompile(`^[a-zA-Z0-9_\-.]+[^._\-]$`), "must contain only alphanumeric characters, underscores, hyphens, and dots"),
83+
),
84+
},
85+
"support_code": {
86+
Type: schema.TypeString,
87+
Computed: true,
88+
},
89+
"tags": tftags.TagsSchema(),
90+
"tags_all": tftags.TagsSchemaComputed(),
91+
},
92+
CustomizeDiff: verify.SetTagsDiff,
93+
}
94+
}
95+
96+
func resourceLoadBalancerCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
97+
conn := meta.(*conns.AWSClient).LightsailConn
98+
defaultTagsConfig := meta.(*conns.AWSClient).DefaultTagsConfig
99+
tags := defaultTagsConfig.MergeTags(tftags.New(d.Get("tags").(map[string]interface{})))
100+
101+
in := lightsail.CreateLoadBalancerInput{
102+
HealthCheckPath: aws.String(d.Get("health_check_path").(string)),
103+
InstancePort: aws.Int64(int64(d.Get("instance_port").(int))),
104+
LoadBalancerName: aws.String(d.Get("name").(string)),
105+
}
106+
107+
if len(tags) > 0 {
108+
in.Tags = Tags(tags.IgnoreAWS())
109+
}
110+
111+
out, err := conn.CreateLoadBalancerWithContext(ctx, &in)
112+
113+
if err != nil {
114+
return create.DiagError(names.Lightsail, lightsail.OperationTypeCreateLoadBalancer, ResLoadBalancer, d.Get("name").(string), err)
115+
}
116+
117+
if len(out.Operations) == 0 {
118+
return create.DiagError(names.Lightsail, lightsail.OperationTypeCreateLoadBalancer, ResLoadBalancer, d.Get("name").(string), errors.New("No operations found for Create Load Balancer request"))
119+
}
120+
121+
op := out.Operations[0]
122+
d.SetId(d.Get("name").(string))
123+
124+
err = waitOperation(conn, op.Id)
125+
if err != nil {
126+
return create.DiagError(names.Lightsail, lightsail.OperationTypeCreateLoadBalancer, ResLoadBalancer, d.Get("name").(string), errors.New("Error waiting for Create Load Balancer request operation"))
127+
}
128+
129+
return resourceLoadBalancerRead(ctx, d, meta)
130+
}
131+
132+
func resourceLoadBalancerRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
133+
conn := meta.(*conns.AWSClient).LightsailConn
134+
defaultTagsConfig := meta.(*conns.AWSClient).DefaultTagsConfig
135+
ignoreTagsConfig := meta.(*conns.AWSClient).IgnoreTagsConfig
136+
137+
lb, err := FindLoadBalancerByName(ctx, conn, d.Id())
138+
139+
if !d.IsNewResource() && tfresource.NotFound(err) {
140+
create.LogNotFoundRemoveState(names.Lightsail, create.ErrActionReading, ResLoadBalancer, d.Id())
141+
d.SetId("")
142+
return nil
143+
}
144+
145+
if err != nil {
146+
return create.DiagError(names.Lightsail, create.ErrActionReading, ResLoadBalancer, d.Id(), err)
147+
}
148+
149+
d.Set("arn", lb.Arn)
150+
d.Set("created_at", lb.CreatedAt.Format(time.RFC3339))
151+
d.Set("dns_name", lb.DnsName)
152+
d.Set("health_check_path", lb.HealthCheckPath)
153+
d.Set("instance_port", lb.InstancePort)
154+
d.Set("ip_address_type", lb.IpAddressType)
155+
d.Set("protocol", lb.Protocol)
156+
d.Set("public_ports", lb.PublicPorts)
157+
d.Set("name", lb.Name)
158+
d.Set("support_code", lb.SupportCode)
159+
160+
tags := KeyValueTags(lb.Tags).IgnoreAWS().IgnoreConfig(ignoreTagsConfig)
161+
162+
//lintignore:AWSR002
163+
if err := d.Set("tags", tags.RemoveDefaultConfig(defaultTagsConfig).Map()); err != nil {
164+
return create.DiagError(names.Lightsail, create.ErrActionReading, ResLoadBalancer, d.Id(), err)
165+
}
166+
167+
if err := d.Set("tags_all", tags.Map()); err != nil {
168+
return create.DiagError(names.Lightsail, create.ErrActionReading, ResLoadBalancer, d.Id(), err)
169+
}
170+
171+
return nil
172+
}
173+
174+
func resourceLoadBalancerUpdate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
175+
conn := meta.(*conns.AWSClient).LightsailConn
176+
177+
in := &lightsail.UpdateLoadBalancerAttributeInput{
178+
LoadBalancerName: aws.String(d.Get("name").(string)),
179+
}
180+
181+
if d.HasChange("health_check_path") {
182+
healthCheckIn := in
183+
healthCheckIn.AttributeName = aws.String("HealthCheckPath")
184+
healthCheckIn.AttributeValue = aws.String(d.Get("health_check_path").(string))
185+
186+
out, err := conn.UpdateLoadBalancerAttributeWithContext(ctx, healthCheckIn)
187+
188+
if err != nil {
189+
return create.DiagError(names.Lightsail, lightsail.OperationTypeCreateLoadBalancer, ResLoadBalancer, d.Get("name").(string), err)
190+
}
191+
192+
if len(out.Operations) == 0 {
193+
return create.DiagError(names.Lightsail, lightsail.OperationTypeCreateLoadBalancer, ResLoadBalancer, d.Get("name").(string), errors.New("No operations found for Create Load Balancer request"))
194+
}
195+
196+
op := out.Operations[0]
197+
198+
err = waitOperation(conn, op.Id)
199+
if err != nil {
200+
return create.DiagError(names.Lightsail, lightsail.OperationTypeCreateLoadBalancer, ResLoadBalancer, d.Get("name").(string), errors.New("Error waiting for Create Load Balancer request operation"))
201+
}
202+
}
203+
204+
if d.HasChange("tags") {
205+
o, n := d.GetChange("tags")
206+
207+
if err := UpdateTags(conn, d.Id(), o, n); err != nil {
208+
return create.DiagError(names.Lightsail, create.ErrActionUpdating, ResLoadBalancer, d.Id(), err)
209+
}
210+
}
211+
212+
if d.HasChange("tags_all") {
213+
o, n := d.GetChange("tags_all")
214+
215+
if err := UpdateTags(conn, d.Id(), o, n); err != nil {
216+
return create.DiagError(names.Lightsail, create.ErrActionUpdating, ResLoadBalancer, d.Id(), err)
217+
}
218+
}
219+
220+
return resourceLoadBalancerRead(ctx, d, meta)
221+
}
222+
223+
func resourceLoadBalancerDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
224+
conn := meta.(*conns.AWSClient).LightsailConn
225+
226+
out, err := conn.DeleteLoadBalancerWithContext(ctx, &lightsail.DeleteLoadBalancerInput{
227+
LoadBalancerName: aws.String(d.Id()),
228+
})
229+
230+
if err != nil {
231+
return create.DiagError(names.Lightsail, lightsail.OperationTypeCreateLoadBalancer, ResLoadBalancer, d.Get("name").(string), err)
232+
}
233+
234+
if len(out.Operations) == 0 {
235+
return create.DiagError(names.Lightsail, lightsail.OperationTypeCreateLoadBalancer, ResLoadBalancer, d.Get("name").(string), errors.New("No operations found for Create Load Balancer request"))
236+
}
237+
238+
op := out.Operations[0]
239+
240+
err = waitOperation(conn, op.Id)
241+
if err != nil {
242+
return create.DiagError(names.Lightsail, lightsail.OperationTypeCreateLoadBalancer, ResLoadBalancer, d.Get("name").(string), errors.New("Error waiting for Create Load Balancer request operation"))
243+
}
244+
245+
return nil
246+
}

0 commit comments

Comments
 (0)