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

route53profiles - r/association, r/resource_association and d/profiles resources added #38172

Merged
merged 30 commits into from
Oct 7, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
30 commits
Select commit Hold shift + click to select a range
26513d3
r/aws_route53profiles_profile
rubenandre Apr 26, 2024
91d0b7b
perform lint fixs and removed skaff tips
rubenandre Apr 26, 2024
a5b844c
add computed arguments to schema and create method
rubenandre Apr 26, 2024
978c6f4
add tags generation; update only for tags and acceptance tests
rubenandre Apr 26, 2024
bfd9fc5
lint fixes; add website documentation
rubenandre Apr 26, 2024
3c36bd6
re-add wrong deleted docs
rubenandre Apr 26, 2024
cd94de4
fix extension
rubenandre Apr 26, 2024
5f36bf5
`r/route53profiles` - `assocation` and `resource_association` resourc…
aristosvo Jun 28, 2024
de5cfd6
make testacc-lint-fix + imports fixed
aristosvo Jun 28, 2024
28f7f9f
docs
aristosvo Jun 28, 2024
2a1fd2e
make gen + literals
aristosvo Jun 28, 2024
0d52b2b
terrafmt docs + small stuff
aristosvo Jun 28, 2024
2f1a73f
fix imports
aristosvo Jun 28, 2024
57e885a
add sweepers
aristosvo Jul 1, 2024
2024ed6
import fmt sweep.go
aristosvo Jul 2, 2024
de37301
docs: release notes
aristosvo Jul 3, 2024
3d35ee5
improve resource_properties (JSON)
aristosvo Jul 3, 2024
6f9a4b2
add d/route53profiles_profiles
aristosvo Jul 3, 2024
e197acd
fixes and improvements
aristosvo Jul 5, 2024
f9bf2ae
use autoflex
aristosvo Aug 23, 2024
1a8f443
Merge branch 'main' into f-aws_route53profiles
Sep 24, 2024
76eff08
Add tags slice generate
Oct 1, 2024
eecad59
Add required input
Oct 1, 2024
a2cb5b4
Changes/fixes to error msgs; rmeove update
Oct 2, 2024
2f9ad54
tags gen
Oct 2, 2024
b421676
Fix tags; add custom tags function for api return discrepancy
Oct 4, 2024
b8e21cc
Add couple more tests to resources
Oct 7, 2024
05b9b57
Docuemntation nits
Oct 7, 2024
a7fd353
linter fixes
Oct 7, 2024
919d31c
More linter fixes
Oct 7, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 15 additions & 0 deletions .changelog/38172.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
```release-note:new-resource
aws_route53profiles_profile
```

```release-note:new-resource
aws_route53profiles_association
```

```release-note:new-resource
aws_route53profiles_resource_association
```

```release-note:new-data-source
aws_route53profiles_profiles
```
302 changes: 302 additions & 0 deletions internal/service/route53profiles/association.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,302 @@
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0

package route53profiles

import (
"context"
"errors"
"time"

"github.com/aws/aws-sdk-go-v2/aws"
"github.com/aws/aws-sdk-go-v2/service/route53profiles"
awstypes "github.com/aws/aws-sdk-go-v2/service/route53profiles/types"
"github.com/hashicorp/terraform-plugin-framework-timeouts/resource/timeouts"
"github.com/hashicorp/terraform-plugin-framework/path"
"github.com/hashicorp/terraform-plugin-framework/resource"
"github.com/hashicorp/terraform-plugin-framework/resource/schema"
"github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier"
"github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier"
"github.com/hashicorp/terraform-plugin-framework/types"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/retry"
"github.com/hashicorp/terraform-provider-aws/internal/create"
"github.com/hashicorp/terraform-provider-aws/internal/enum"
"github.com/hashicorp/terraform-provider-aws/internal/errs"
"github.com/hashicorp/terraform-provider-aws/internal/framework"
"github.com/hashicorp/terraform-provider-aws/internal/framework/flex"
fwtypes "github.com/hashicorp/terraform-provider-aws/internal/framework/types"
"github.com/hashicorp/terraform-provider-aws/internal/tfresource"
"github.com/hashicorp/terraform-provider-aws/names"
)

// @FrameworkResource("aws_route53profiles_association", name="Association")
func newResourceAssociation(_ context.Context) (resource.ResourceWithConfigure, error) {
r := &resourceAssociation{}

r.SetDefaultCreateTimeout(30 * time.Minute)
r.SetDefaultUpdateTimeout(30 * time.Minute)
r.SetDefaultDeleteTimeout(30 * time.Minute)

return r, nil
}

const (
ResNameAssociation = "Association"
)

type resourceAssociation struct {
framework.ResourceWithConfigure
framework.WithNoUpdate
framework.WithTimeouts
framework.WithImportByID
}

func (r *resourceAssociation) Metadata(_ context.Context, req resource.MetadataRequest, resp *resource.MetadataResponse) {
resp.TypeName = "aws_route53profiles_association"
}

func (r *resourceAssociation) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) {
resp.Schema = schema.Schema{
Attributes: map[string]schema.Attribute{
names.AttrID: framework.IDAttribute(),
names.AttrName: schema.StringAttribute{
Required: true,
PlanModifiers: []planmodifier.String{
stringplanmodifier.RequiresReplace(),
},
},
names.AttrOwnerID: schema.StringAttribute{
Computed: true,
},
"profile_id": schema.StringAttribute{
Required: true,
PlanModifiers: []planmodifier.String{
stringplanmodifier.RequiresReplace(),
},
},
names.AttrResourceID: schema.StringAttribute{
Required: true,
PlanModifiers: []planmodifier.String{
stringplanmodifier.RequiresReplace(),
},
},
names.AttrStatus: schema.StringAttribute{
CustomType: fwtypes.StringEnumType[awstypes.ProfileStatus](),
Computed: true,
},
names.AttrStatusMessage: schema.StringAttribute{
Computed: true,
},
},
Blocks: map[string]schema.Block{
names.AttrTimeouts: timeouts.Block(ctx, timeouts.Opts{
Create: true,
Read: true,
Delete: true,
}),
},
}
}

func (r *resourceAssociation) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) {
conn := r.Meta().Route53ProfilesClient(ctx)

var state associationResourceModel
resp.Diagnostics.Append(req.Plan.Get(ctx, &state)...)
if resp.Diagnostics.HasError() {
return
}

input := &route53profiles.AssociateProfileInput{}
resp.Diagnostics.Append(flex.Expand(ctx, state, input)...)

out, err := conn.AssociateProfile(ctx, input)
if err != nil {
resp.Diagnostics.AddError(
create.ProblemStandardMessage(names.Route53Profiles, create.ErrActionCreating, ResNameAssociation, state.Name.String(), err),
err.Error(),
)
return
}
if out == nil || out.ProfileAssociation == nil {
resp.Diagnostics.AddError(
create.ProblemStandardMessage(names.Route53Profiles, create.ErrActionCreating, ResNameAssociation, state.Name.String(), nil),
errors.New("empty output").Error(),
)
return
}

state.ID = flex.StringToFramework(ctx, out.ProfileAssociation.Id)

createTimeout := r.CreateTimeout(ctx, state.Timeouts)
profileAssociation, err := waitAssociationCreated(ctx, conn, state.ID.ValueString(), createTimeout)
if err != nil {
resp.Diagnostics.AddError(
create.ProblemStandardMessage(names.Route53Profiles, create.ErrActionWaitingForCreation, ResNameAssociation, state.Name.String(), err),
err.Error(),
)
return
}

resp.Diagnostics.Append(flex.Flatten(ctx, profileAssociation, &state)...)
if resp.Diagnostics.HasError() {
return
}

resp.Diagnostics.Append(resp.State.Set(ctx, state)...)
}

func (r *resourceAssociation) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) {
conn := r.Meta().Route53ProfilesClient(ctx)

var state associationResourceModel
resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
if resp.Diagnostics.HasError() {
return
}

out, err := findAssociationByID(ctx, conn, state.ID.ValueString())
if tfresource.NotFound(err) {
resp.State.RemoveResource(ctx)
return
}
if err != nil {
resp.Diagnostics.AddError(
create.ProblemStandardMessage(names.Route53Profiles, create.ErrActionSetting, ResNameAssociation, state.ID.String(), err),
err.Error(),
)
return
}

resp.Diagnostics.Append(flex.Flatten(ctx, out, &state)...)
if resp.Diagnostics.HasError() {
return
}

resp.Diagnostics.Append(resp.State.Set(ctx, &state)...)
}

func (r *resourceAssociation) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) {
conn := r.Meta().Route53ProfilesClient(ctx)

var state associationResourceModel
resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
if resp.Diagnostics.HasError() {
return
}

in := &route53profiles.DisassociateProfileInput{
ProfileId: state.ProfileID.ValueStringPointer(),
ResourceId: state.ResourceID.ValueStringPointer(),
}

_, err := conn.DisassociateProfile(ctx, in)
if err != nil {
if errs.IsA[*awstypes.ResourceNotFoundException](err) {
return
}
resp.Diagnostics.AddError(
create.ProblemStandardMessage(names.Route53Profiles, create.ErrActionDeleting, ResNameAssociation, state.ID.String(), err),
err.Error(),
)
return
}

deleteTimeout := r.DeleteTimeout(ctx, state.Timeouts)
_, err = waitAssociationDeleted(ctx, conn, state.ID.ValueString(), deleteTimeout)
if err != nil {
resp.Diagnostics.AddError(
create.ProblemStandardMessage(names.Route53Profiles, create.ErrActionWaitingForDeletion, ResNameAssociation, state.ID.String(), err),
err.Error(),
)
return
}
}

func (r *resourceAssociation) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) {
resource.ImportStatePassthroughID(ctx, path.Root(names.AttrID), req, resp)
}

func waitAssociationCreated(ctx context.Context, conn *route53profiles.Client, id string, timeout time.Duration) (*awstypes.ProfileAssociation, error) {
stateConf := &retry.StateChangeConf{
Pending: enum.Slice(awstypes.ProfileStatusCreating),
Target: enum.Slice(awstypes.ProfileStatusComplete),
Refresh: statusAssociation(ctx, conn, id),
Timeout: timeout,
NotFoundChecks: 20,
ContinuousTargetOccurence: 2,
}

outputRaw, err := stateConf.WaitForStateContext(ctx)
if out, ok := outputRaw.(*awstypes.ProfileAssociation); ok {
return out, err
}

return nil, err
}

func waitAssociationDeleted(ctx context.Context, conn *route53profiles.Client, id string, timeout time.Duration) (*awstypes.ProfileAssociation, error) {
stateConf := &retry.StateChangeConf{
Pending: enum.Slice(awstypes.ProfileStatusDeleting),
Target: []string{},
Refresh: statusAssociation(ctx, conn, id),
Timeout: timeout,
}

outputRaw, err := stateConf.WaitForStateContext(ctx)
if out, ok := outputRaw.(*awstypes.ProfileAssociation); ok {
return out, err
}

return nil, err
}

func statusAssociation(ctx context.Context, conn *route53profiles.Client, id string) retry.StateRefreshFunc {
return func() (interface{}, string, error) {
out, err := findAssociationByID(ctx, conn, id)
if tfresource.NotFound(err) {
return nil, "", nil
}

if err != nil {
return nil, "", err
}

return out, string(out.Status), nil
}
}

func findAssociationByID(ctx context.Context, conn *route53profiles.Client, id string) (*awstypes.ProfileAssociation, error) {
in := &route53profiles.GetProfileAssociationInput{
ProfileAssociationId: aws.String(id),
}

out, err := conn.GetProfileAssociation(ctx, in)
if err != nil {
if errs.IsA[*awstypes.ResourceNotFoundException](err) {
return nil, &retry.NotFoundError{
LastError: err,
LastRequest: in,
}
}

return nil, err
}

if out == nil || out.ProfileAssociation == nil {
return nil, tfresource.NewEmptyResultError(in)
}

return out.ProfileAssociation, nil
}

type associationResourceModel struct {
ID types.String `tfsdk:"id"`
ResourceID types.String `tfsdk:"resource_id"`
ProfileID types.String `tfsdk:"profile_id"`
Name types.String `tfsdk:"name"`
OwnerId types.String `tfsdk:"owner_id"`
Status fwtypes.StringEnum[awstypes.ProfileStatus] `tfsdk:"status"`
StatusMessage types.String `tfsdk:"status_message"`
Timeouts timeouts.Value `tfsdk:"timeouts"`
}
Loading
Loading