Skip to content

Commit 71008b5

Browse files
authored
Merge pull request #43883 from zerj9/lf-tag-expressions
New resource: lf_tag_expression
2 parents 65671ca + 26b2778 commit 71008b5

File tree

7 files changed

+642
-1
lines changed

7 files changed

+642
-1
lines changed

.changelog/43883.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
```release-note:new-resource
2+
aws_lakeformation_lf_tag_expression
3+
```

internal/service/lakeformation/exports_test.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -6,11 +6,12 @@ package lakeformation
66
// exports used for testing only.
77
var (
88
ResourceDataCellsFilter = newDataCellsFilterResource
9+
ResourceLFTagExpression = newLFTagExpressionResource
910
ResourceResourceLFTag = newResourceLFTagResource
1011
ResourceOptIn = newOptInResource
1112

1213
FindDataCellsFilterByID = findDataCellsFilterByID
13-
FindResourceLFTagByID = findResourceLFTagByID
14+
FindLFTagExpression = findLFTagExpression
1415
LFTagParseResourceID = lfTagParseResourceID
1516
FindOptInByID = findOptInByID
1617

internal/service/lakeformation/lakeformation_test.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -84,6 +84,11 @@ func TestAccLakeFormation_serial(t *testing.T) {
8484
"values": testAccLFTag_Values,
8585
"valuesOverFifty": testAccLFTag_Values_overFifty,
8686
},
87+
"LFTagExpression": {
88+
acctest.CtBasic: testAccLFTagExpression_basic,
89+
acctest.CtDisappears: testAccLFTagExpression_disappears,
90+
"update": testAccLFTagExpression_update,
91+
},
8792
"ResourceLFTag": {
8893
acctest.CtBasic: testAccResourceLFTag_basic,
8994
acctest.CtDisappears: testAccResourceLFTag_disappears,
Lines changed: 281 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,281 @@
1+
// Copyright (c) HashiCorp, Inc.
2+
// SPDX-License-Identifier: MPL-2.0
3+
4+
package lakeformation
5+
6+
import (
7+
"context"
8+
9+
"github.com/aws/aws-sdk-go-v2/aws"
10+
"github.com/aws/aws-sdk-go-v2/service/lakeformation"
11+
awstypes "github.com/aws/aws-sdk-go-v2/service/lakeformation/types"
12+
"github.com/hashicorp/terraform-plugin-framework-validators/setvalidator"
13+
"github.com/hashicorp/terraform-plugin-framework/path"
14+
"github.com/hashicorp/terraform-plugin-framework/resource"
15+
"github.com/hashicorp/terraform-plugin-framework/resource/schema"
16+
"github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier"
17+
"github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier"
18+
"github.com/hashicorp/terraform-plugin-framework/schema/validator"
19+
"github.com/hashicorp/terraform-plugin-framework/types"
20+
"github.com/hashicorp/terraform-provider-aws/internal/create"
21+
"github.com/hashicorp/terraform-provider-aws/internal/errs"
22+
"github.com/hashicorp/terraform-provider-aws/internal/errs/fwdiag"
23+
intflex "github.com/hashicorp/terraform-provider-aws/internal/flex"
24+
"github.com/hashicorp/terraform-provider-aws/internal/framework"
25+
fwflex "github.com/hashicorp/terraform-provider-aws/internal/framework/flex"
26+
fwtypes "github.com/hashicorp/terraform-provider-aws/internal/framework/types"
27+
"github.com/hashicorp/terraform-provider-aws/internal/retry"
28+
"github.com/hashicorp/terraform-provider-aws/internal/tfresource"
29+
"github.com/hashicorp/terraform-provider-aws/names"
30+
)
31+
32+
// @FrameworkResource("aws_lakeformation_lf_tag_expression", name="LF Tag Expression")
33+
func newLFTagExpressionResource(_ context.Context) (resource.ResourceWithConfigure, error) {
34+
return &lfTagExpressionResource{}, nil
35+
}
36+
37+
const (
38+
ResNameLFTagExpression = "LF Tag Expression"
39+
)
40+
41+
type lfTagExpressionResource struct {
42+
framework.ResourceWithModel[lfTagExpressionResourceModel]
43+
}
44+
45+
func (r *lfTagExpressionResource) Schema(ctx context.Context, _ resource.SchemaRequest, response *resource.SchemaResponse) {
46+
response.Schema = schema.Schema{
47+
Description: "Manages an AWS Lake Formation Tag Expression.",
48+
Attributes: map[string]schema.Attribute{
49+
names.AttrCatalogID: schema.StringAttribute{
50+
Optional: true,
51+
Computed: true,
52+
Description: "The ID of the Data Catalog.",
53+
PlanModifiers: []planmodifier.String{
54+
stringplanmodifier.UseStateForUnknown(),
55+
stringplanmodifier.RequiresReplaceIfConfigured(),
56+
},
57+
},
58+
names.AttrName: schema.StringAttribute{
59+
Required: true,
60+
PlanModifiers: []planmodifier.String{
61+
stringplanmodifier.RequiresReplace(),
62+
},
63+
Description: "The name of the LF-Tag Expression.",
64+
},
65+
names.AttrDescription: schema.StringAttribute{
66+
Optional: true,
67+
Description: "A description of the LF-Tag Expression.",
68+
},
69+
},
70+
Blocks: map[string]schema.Block{
71+
names.AttrExpression: schema.SetNestedBlock{
72+
CustomType: fwtypes.NewSetNestedObjectTypeOf[expressionLfTag](ctx),
73+
Validators: []validator.Set{
74+
setvalidator.IsRequired(),
75+
},
76+
NestedObject: schema.NestedBlockObject{
77+
Attributes: map[string]schema.Attribute{
78+
"tag_key": schema.StringAttribute{
79+
Required: true,
80+
},
81+
"tag_values": schema.SetAttribute{
82+
ElementType: types.StringType,
83+
Required: true,
84+
},
85+
},
86+
},
87+
},
88+
},
89+
}
90+
}
91+
92+
func (r *lfTagExpressionResource) Create(ctx context.Context, request resource.CreateRequest, response *resource.CreateResponse) {
93+
conn := r.Meta().LakeFormationClient(ctx)
94+
95+
var data lfTagExpressionResourceModel
96+
response.Diagnostics.Append(request.Plan.Get(ctx, &data)...)
97+
if response.Diagnostics.HasError() {
98+
return
99+
}
100+
101+
if data.CatalogId.IsNull() || data.CatalogId.IsUnknown() {
102+
data.CatalogId = fwflex.StringValueToFramework(ctx, r.Meta().AccountID(ctx))
103+
}
104+
105+
input := lakeformation.CreateLFTagExpressionInput{}
106+
response.Diagnostics.Append(fwflex.Expand(ctx, data, &input)...)
107+
if response.Diagnostics.HasError() {
108+
return
109+
}
110+
111+
_, err := conn.CreateLFTagExpression(ctx, &input)
112+
if err != nil {
113+
response.Diagnostics.AddError(
114+
create.ProblemStandardMessage(names.LakeFormation, create.ErrActionCreating, ResNameLFTagExpression, data.Name.String(), err),
115+
err.Error(),
116+
)
117+
return
118+
}
119+
120+
response.Diagnostics.Append(response.State.Set(ctx, data)...)
121+
}
122+
123+
func (r *lfTagExpressionResource) Read(ctx context.Context, request resource.ReadRequest, response *resource.ReadResponse) {
124+
conn := r.Meta().LakeFormationClient(ctx)
125+
126+
var data lfTagExpressionResourceModel
127+
response.Diagnostics.Append(request.State.Get(ctx, &data)...)
128+
if response.Diagnostics.HasError() {
129+
return
130+
}
131+
132+
output, err := findLFTagExpression(ctx, conn, data.Name.ValueString(), data.CatalogId.ValueString())
133+
134+
if retry.NotFound(err) {
135+
response.Diagnostics.Append(fwdiag.NewResourceNotFoundWarningDiagnostic(err))
136+
response.State.RemoveResource(ctx)
137+
return
138+
}
139+
140+
if err != nil {
141+
response.Diagnostics.AddError(
142+
create.ProblemStandardMessage(names.LakeFormation, create.ErrActionReading, ResNameLFTagExpression, data.Name.String(), err),
143+
err.Error(),
144+
)
145+
return
146+
}
147+
148+
response.Diagnostics.Append(fwflex.Flatten(ctx, output, &data)...)
149+
if response.Diagnostics.HasError() {
150+
return
151+
}
152+
153+
response.Diagnostics.Append(response.State.Set(ctx, &data)...)
154+
}
155+
156+
func (r *lfTagExpressionResource) Update(ctx context.Context, request resource.UpdateRequest, response *resource.UpdateResponse) {
157+
conn := r.Meta().LakeFormationClient(ctx)
158+
159+
var plan, state lfTagExpressionResourceModel
160+
response.Diagnostics.Append(request.Plan.Get(ctx, &plan)...)
161+
response.Diagnostics.Append(request.State.Get(ctx, &state)...)
162+
if response.Diagnostics.HasError() {
163+
return
164+
}
165+
166+
diff, d := fwflex.Diff(ctx, plan, state)
167+
response.Diagnostics.Append(d...)
168+
if response.Diagnostics.HasError() {
169+
return
170+
}
171+
172+
if diff.HasChanges() {
173+
var input lakeformation.UpdateLFTagExpressionInput
174+
response.Diagnostics.Append(fwflex.Expand(ctx, plan, &input)...)
175+
if response.Diagnostics.HasError() {
176+
return
177+
}
178+
179+
_, err := conn.UpdateLFTagExpression(ctx, &input)
180+
if err != nil {
181+
response.Diagnostics.AddError(
182+
create.ProblemStandardMessage(names.LakeFormation, create.ErrActionUpdating, ResNameLFTagExpression, plan.Name.String(), err),
183+
err.Error(),
184+
)
185+
return
186+
}
187+
}
188+
189+
response.Diagnostics.Append(response.State.Set(ctx, &plan)...)
190+
}
191+
192+
func (r *lfTagExpressionResource) Delete(ctx context.Context, request resource.DeleteRequest, response *resource.DeleteResponse) {
193+
conn := r.Meta().LakeFormationClient(ctx)
194+
195+
var state lfTagExpressionResourceModel
196+
response.Diagnostics.Append(request.State.Get(ctx, &state)...)
197+
if response.Diagnostics.HasError() {
198+
return
199+
}
200+
201+
input := lakeformation.DeleteLFTagExpressionInput{
202+
CatalogId: state.CatalogId.ValueStringPointer(),
203+
Name: state.Name.ValueStringPointer(),
204+
}
205+
206+
_, err := conn.DeleteLFTagExpression(ctx, &input)
207+
208+
if errs.IsA[*awstypes.EntityNotFoundException](err) {
209+
return
210+
}
211+
212+
if err != nil {
213+
response.Diagnostics.AddError(
214+
create.ProblemStandardMessage(names.LakeFormation, create.ErrActionDeleting, ResNameLFTagExpression, state.Name.String(), err),
215+
err.Error(),
216+
)
217+
return
218+
}
219+
}
220+
221+
const (
222+
lfTagExpressionIDPartCount = 2
223+
)
224+
225+
func (r *lfTagExpressionResource) ImportState(ctx context.Context, request resource.ImportStateRequest, response *resource.ImportStateResponse) {
226+
parts, err := intflex.ExpandResourceId(request.ID, lfTagExpressionIDPartCount, false)
227+
if err != nil {
228+
response.Diagnostics.AddError(
229+
create.ProblemStandardMessage(names.LakeFormation, create.ErrActionImporting, ResNameLFTagExpression, request.ID, err),
230+
err.Error(),
231+
)
232+
return
233+
}
234+
235+
name := parts[0]
236+
catalogId := parts[1]
237+
// Set the parsed values in state
238+
response.Diagnostics.Append(response.State.SetAttribute(ctx, path.Root(names.AttrName), name)...)
239+
response.Diagnostics.Append(response.State.SetAttribute(ctx, path.Root(names.AttrCatalogID), catalogId)...)
240+
if response.Diagnostics.HasError() {
241+
return
242+
}
243+
}
244+
245+
type lfTagExpressionResourceModel struct {
246+
framework.WithRegionModel
247+
CatalogId types.String `tfsdk:"catalog_id"`
248+
Description types.String `tfsdk:"description"`
249+
Name types.String `tfsdk:"name"`
250+
Expression fwtypes.SetNestedObjectValueOf[expressionLfTag] `tfsdk:"expression"`
251+
}
252+
253+
type expressionLfTag struct {
254+
TagKey types.String `tfsdk:"tag_key"`
255+
TagValues fwtypes.SetOfString `tfsdk:"tag_values"`
256+
}
257+
258+
func findLFTagExpression(ctx context.Context, conn *lakeformation.Client, name, catalogId string) (*lakeformation.GetLFTagExpressionOutput, error) {
259+
input := lakeformation.GetLFTagExpressionInput{
260+
CatalogId: aws.String(catalogId),
261+
Name: aws.String(name),
262+
}
263+
264+
output, err := conn.GetLFTagExpression(ctx, &input)
265+
266+
if errs.IsA[*awstypes.EntityNotFoundException](err) {
267+
return nil, &retry.NotFoundError{
268+
LastError: err,
269+
}
270+
}
271+
272+
if err != nil {
273+
return nil, err
274+
}
275+
276+
if output == nil || output.Expression == nil {
277+
return nil, tfresource.NewEmptyResultError(input)
278+
}
279+
280+
return output, nil
281+
}

0 commit comments

Comments
 (0)