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]: DataZone Environment Profile #38581

Merged
merged 38 commits into from
Aug 12, 2024
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
Show all changes
38 commits
Select commit Hold shift + click to select a range
5c237a6
Added CRUD operations for datazone environment project
ThomasZalewski Jul 26, 2024
4186a24
Passes tests now.
ThomasZalewski Jul 29, 2024
65351ab
CI formatting changes
ThomasZalewski Jul 29, 2024
9d4f14a
Documentation changes
ThomasZalewski Jul 29, 2024
ddd3801
ci formatting
ThomasZalewski Jul 29, 2024
4011076
ci formatting changes
ThomasZalewski Jul 29, 2024
dc9d391
fixed update
ThomasZalewski Jul 29, 2024
407d614
added changelog
ThomasZalewski Jul 29, 2024
b12da91
Update internal/service/datazone/environment_profile.go
ThomasZalewski Jul 29, 2024
7513521
Update internal/service/datazone/environment_profile.go
ThomasZalewski Jul 29, 2024
c8f021b
Update internal/service/datazone/environment_profile_test.go
ThomasZalewski Jul 29, 2024
2f9a3f4
Update internal/service/datazone/environment_profile_test.go
ThomasZalewski Jul 29, 2024
413387e
Update website/docs/r/datazone_environment_profile.html.markdown
ThomasZalewski Jul 29, 2024
afecfe9
Update internal/service/datazone/environment_profile_test.go
ThomasZalewski Jul 29, 2024
fb9a194
Update internal/service/datazone/environment_profile.go
ThomasZalewski Jul 29, 2024
022965f
PR comment changes
ThomasZalewski Jul 29, 2024
1637a4b
Pr fixes
ThomasZalewski Jul 30, 2024
05e8612
Ci formatting change
ThomasZalewski Jul 30, 2024
b932d1a
ci changes
ThomasZalewski Jul 30, 2024
24290f6
exported finder function
ThomasZalewski Aug 1, 2024
ce41328
Updated autoflex uptions
ThomasZalewski Aug 5, 2024
28e41fb
Merge branch 'main' into f/datazone-enviroment-profile-resource
ThomasZalewski Aug 6, 2024
57e1db1
Update service_package_gen.go
ThomasZalewski Aug 6, 2024
0117bc2
Update environment_profile.go
ThomasZalewski Aug 6, 2024
63d7de0
Update .changelog/35603.txt
ThomasZalewski Aug 6, 2024
32df382
Update website/docs/r/datazone_environment_profile.html.markdown
ThomasZalewski Aug 6, 2024
472ce6d
Update website/docs/r/datazone_environment_profile.html.markdown
ThomasZalewski Aug 6, 2024
7ee8b13
Update internal/service/datazone/environment_profile.go
ThomasZalewski Aug 6, 2024
c202ca3
Update website/docs/r/datazone_environment_profile.html.markdown
ThomasZalewski Aug 6, 2024
707c94e
Update internal/service/datazone/environment_profile_test.go
ThomasZalewski Aug 6, 2024
cbbe0fc
Formatting + fixing pr issues
ThomasZalewski Aug 6, 2024
65d3de0
Doc changes
ThomasZalewski Aug 6, 2024
f2c2fb7
Update internal/service/datazone/environment_profile_test.go
ThomasZalewski Aug 6, 2024
cc35ffa
Merge branch 'main' into f/datazone-enviroment-profile-resource
jar-b Aug 12, 2024
8a72625
r/aws_datazone_environment_profile: alphabetize schema, tidy
jar-b Aug 12, 2024
852adb3
r/aws_datazone_environment_profile: tidy import func, tests, docs
jar-b Aug 12, 2024
c233019
r/aws_datazone_environment_profile(test): fix test failures, tidy
jar-b Aug 12, 2024
6e053e4
r/aws_datazone_environment_profile: fix err message actions
jar-b Aug 12, 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
3 changes: 3 additions & 0 deletions .changelog/35603.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
```release-note:new-resource
aws_datazone_environment_blueprint
ThomasZalewski marked this conversation as resolved.
Show resolved Hide resolved
```
361 changes: 361 additions & 0 deletions internal/service/datazone/environment_profile.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,361 @@
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0

package datazone

import (
"context"
"errors"
"fmt"
"strings"

"github.com/YakDriver/regexache"
"github.com/aws/aws-sdk-go-v2/aws"
"github.com/aws/aws-sdk-go-v2/service/datazone"
awstypes "github.com/aws/aws-sdk-go-v2/service/datazone/types"
"github.com/hashicorp/terraform-plugin-framework-timetypes/timetypes"
"github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator"
"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/setplanmodifier"
"github.com/hashicorp/terraform-plugin-framework/schema/validator"
"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/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_datazone_environment_profile", name="Environment Profile")
func newResourceEnvironmentProfile(_ context.Context) (resource.ResourceWithConfigure, error) {
r := &resourceEnvironmentProfile{}
return r, nil
ThomasZalewski marked this conversation as resolved.
Show resolved Hide resolved
}

const (
ResNameEnvironmentProfile = "Environment Profile"
)

type resourceEnvironmentProfile struct {
framework.ResourceWithConfigure
framework.WithTimeouts
ThomasZalewski marked this conversation as resolved.
Show resolved Hide resolved
}

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

func (r *resourceEnvironmentProfile) Schema(ctx context.Context, req resource.SchemaRequest, resp *resource.SchemaResponse) {
resp.Schema = schema.Schema{
Attributes: map[string]schema.Attribute{
names.AttrAWSAccountID: schema.StringAttribute{
Optional: true,
Computed: true,
Validators: []validator.String{
stringvalidator.RegexMatches(regexache.MustCompile("^\\d{12}$"), "must match ^\\d{12}$"),
},
ThomasZalewski marked this conversation as resolved.
Show resolved Hide resolved
},
"aws_account_region": schema.StringAttribute{
Required: true,
Validators: []validator.String{
stringvalidator.RegexMatches(regexache.MustCompile("^[a-z]{2}-[a-z]{4,10}-\\d$"), "must match ^[a-z]{2}-[a-z]{4,10}-\\d$"),
},
},
"environment_blueprint_identifier": schema.StringAttribute{
Required: true,
Validators: []validator.String{
stringvalidator.RegexMatches(regexache.MustCompile("^[a-zA-Z0-9_-]{1,36}$"), "must match ^[a-zA-Z0-9_-]{1,36}$"),
},
},
names.AttrDescription: schema.StringAttribute{
Optional: true,
Computed: true,
Validators: []validator.String{
stringvalidator.LengthBetween(0, 2048),
},
},
names.AttrID: schema.StringAttribute{
Computed: true,
/*
Validators: []validator.String{
stringvalidator.RegexMatches(regexache.MustCompile("^[a-zA-Z0-9_-]{1,36}$"), "must match ^[a-zA-Z0-9_-]{1,36}$"),
},
*/
},
ThomasZalewski marked this conversation as resolved.
Show resolved Hide resolved
names.AttrName: schema.StringAttribute{
Required: true,
Validators: []validator.String{
stringvalidator.RegexMatches(regexache.MustCompile("^[\\w -]+$"), "must match ^[\\w -]+$"),
stringvalidator.LengthBetween(1, 64),
},
},
"project_identifier": schema.StringAttribute{
Required: true,
Validators: []validator.String{
stringvalidator.RegexMatches(regexache.MustCompile("^[a-zA-Z0-9_-]{1,36}$"), "must match ^[a-zA-Z0-9_-]{1,36}$"),
},
},
names.AttrCreatedAt: schema.StringAttribute{
CustomType: timetypes.RFC3339Type{},
Computed: true,
},
"created_by": schema.StringAttribute{
Computed: true,
},
"domain_identifier": schema.StringAttribute{
Required: true,
},
"updated_at": schema.StringAttribute{
CustomType: timetypes.RFC3339Type{},
Computed: true,
},
},
Blocks: map[string]schema.Block{
"user_parameters": schema.SetNestedBlock{
PlanModifiers: []planmodifier.Set{
setplanmodifier.RequiresReplace(),
setplanmodifier.RequiresReplaceIfConfigured(),
},
CustomType: fwtypes.NewSetNestedObjectTypeOf[dUserParameters](ctx),
NestedObject: schema.NestedBlockObject{
Attributes: map[string]schema.Attribute{
names.AttrName: schema.StringAttribute{
Optional: true,
Computed: false,
ThomasZalewski marked this conversation as resolved.
Show resolved Hide resolved
},
names.AttrValue: schema.StringAttribute{
Optional: true,
Computed: false,
ThomasZalewski marked this conversation as resolved.
Show resolved Hide resolved
},
},
},
},
},
}
}

func (r *resourceEnvironmentProfile) Create(ctx context.Context, req resource.CreateRequest, resp *resource.CreateResponse) {
conn := r.Meta().DataZoneClient(ctx)
var plan dEnvProfile
resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...)
if resp.Diagnostics.HasError() {
return
}

in := &datazone.CreateEnvironmentProfileInput{}
resp.Diagnostics.Append(flex.Expand(ctx, &plan, in)...)
if resp.Diagnostics.HasError() {
return
}
in.Name = plan.Name.ValueStringPointer()
in.EnvironmentBlueprintIdentifier = plan.EnvironmentBlueprintIdentifier.ValueStringPointer()
in.AwsAccountId = plan.AwsAccountId.ValueStringPointer()
jar-b marked this conversation as resolved.
Show resolved Hide resolved

out, err := conn.CreateEnvironmentProfile(ctx, in)
if err != nil {
resp.Diagnostics.AddError(
create.ProblemStandardMessage(names.DataZone, create.ErrActionCreating, ResNameEnvironmentProfile, plan.Name.String(), err),
err.Error(),
)
return
}
if out == nil {
resp.Diagnostics.AddError(
create.ProblemStandardMessage(names.DataZone, create.ErrActionCreating, ResNameEnvironmentProfile, plan.Name.String(), nil),
errors.New("empty output").Error(),
)
return
}

plan.AwsAccountId = flex.StringToFramework(ctx, out.AwsAccountId)
plan.AwsAccountRegion = flex.StringToFramework(ctx, out.AwsAccountRegion)
plan.CreatedAt = flex.TimeToFramework(ctx, out.CreatedAt)
plan.CreatedBy = flex.StringToFramework(ctx, out.CreatedBy)
plan.Description = flex.StringToFramework(ctx, out.Description)
plan.DomainIdentifier = flex.StringToFramework(ctx, out.DomainId)
plan.EnvironmentBlueprintIdentifier = flex.StringToFramework(ctx, out.EnvironmentBlueprintId)
plan.Id = flex.StringToFramework(ctx, out.Id)
plan.Name = flex.StringToFramework(ctx, out.Name)
plan.ProjectIdentifier = flex.StringToFramework(ctx, out.ProjectId)
plan.UpdatedAt = flex.TimeToFramework(ctx, out.UpdatedAt)
ThomasZalewski marked this conversation as resolved.
Show resolved Hide resolved

if resp.Diagnostics.HasError() {
return
}
resp.Diagnostics.Append(resp.State.Set(ctx, &plan)...)
}

func (r *resourceEnvironmentProfile) Read(ctx context.Context, req resource.ReadRequest, resp *resource.ReadResponse) {
conn := r.Meta().DataZoneClient(ctx)
o := flex.AutoFlexOptions{}
o.AddIgnoredField("user_parameters")

// TIP: -- 2. Fetch the state
ThomasZalewski marked this conversation as resolved.
Show resolved Hide resolved
var state dEnvProfile
resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
if resp.Diagnostics.HasError() {
return
}

out, err := findEnvironmentProfileByID(ctx, conn, state.Id.ValueString(), state.DomainIdentifier.ValueString())
if tfresource.NotFound(err) {
resp.State.RemoveResource(ctx)
return
}
if err != nil {
resp.Diagnostics.AddError(
create.ProblemStandardMessage(names.DataZone, create.ErrActionSetting, ResNameEnvironmentProfile, state.Id.String(), err),
jar-b marked this conversation as resolved.
Show resolved Hide resolved
err.Error(),
)
return
}

state.AwsAccountId = flex.StringToFramework(ctx, out.AwsAccountId)
state.AwsAccountRegion = flex.StringToFramework(ctx, out.AwsAccountRegion)
state.CreatedAt = flex.TimeToFramework(ctx, out.CreatedAt)
state.CreatedBy = flex.StringToFramework(ctx, out.CreatedBy)
state.Description = flex.StringToFramework(ctx, out.Description)
state.DomainIdentifier = flex.StringToFramework(ctx, out.DomainId)
state.EnvironmentBlueprintIdentifier = flex.StringToFramework(ctx, out.EnvironmentBlueprintId)
state.Id = flex.StringToFramework(ctx, out.Id)
state.Name = flex.StringToFramework(ctx, out.Name)
state.ProjectIdentifier = flex.StringToFramework(ctx, out.ProjectId)
state.UpdatedAt = flex.TimeToFramework(ctx, out.UpdatedAt)
ThomasZalewski marked this conversation as resolved.
Show resolved Hide resolved

if resp.Diagnostics.HasError() {
return
}
resp.Diagnostics.Append(resp.State.Set(ctx, &state)...)
}

func (r *resourceEnvironmentProfile) Update(ctx context.Context, req resource.UpdateRequest, resp *resource.UpdateResponse) {
conn := r.Meta().DataZoneClient(ctx)

var plan, state dEnvProfile
resp.Diagnostics.Append(req.Plan.Get(ctx, &plan)...)
resp.Diagnostics.Append(req.State.Get(ctx, &state)...)
if resp.Diagnostics.HasError() {
return
}
if plan.EnvironmentBlueprintIdentifier.Equal(state.EnvironmentBlueprintIdentifier) &&
plan.ProjectIdentifier.Equal(state.ProjectIdentifier) && plan.DomainIdentifier.Equal(state.DomainIdentifier) {
jar-b marked this conversation as resolved.
Show resolved Hide resolved
in := &datazone.UpdateEnvironmentProfileInput{}

resp.Diagnostics.Append(flex.Expand(ctx, plan, in)...)
if resp.Diagnostics.HasError() {
return
}
in.Identifier = state.Id.ValueStringPointer()
out, err := conn.UpdateEnvironmentProfile(ctx, in)
if err != nil {
resp.Diagnostics.AddError(
create.ProblemStandardMessage(names.DataZone, create.ErrActionSetting, ResNameEnvironmentProfile, state.Id.ValueString(), err),
jar-b marked this conversation as resolved.
Show resolved Hide resolved
err.Error(),
)
return
}
state.AwsAccountId = flex.StringToFramework(ctx, out.AwsAccountId)
state.AwsAccountRegion = flex.StringToFramework(ctx, out.AwsAccountRegion)
state.CreatedAt = flex.TimeToFramework(ctx, out.CreatedAt)
state.CreatedBy = flex.StringToFramework(ctx, out.CreatedBy)
state.Description = flex.StringToFramework(ctx, out.Description)
state.DomainIdentifier = flex.StringToFramework(ctx, out.DomainId)
state.EnvironmentBlueprintIdentifier = flex.StringToFramework(ctx, out.EnvironmentBlueprintId)
state.Id = flex.StringToFramework(ctx, out.Id)
state.Name = flex.StringToFramework(ctx, out.Name)
state.ProjectIdentifier = flex.StringToFramework(ctx, out.ProjectId)
state.UpdatedAt = flex.TimeToFramework(ctx, out.UpdatedAt)
ThomasZalewski marked this conversation as resolved.
Show resolved Hide resolved

if resp.Diagnostics.HasError() {
return
}
}
resp.Diagnostics.Append(resp.State.Set(ctx, &state)...)
}

func (r *resourceEnvironmentProfile) Delete(ctx context.Context, req resource.DeleteRequest, resp *resource.DeleteResponse) {
conn := r.Meta().DataZoneClient(ctx)
var state dEnvProfile
resp.Diagnostics.Append(req.State.Get(ctx, &state)...)

_, err := conn.DeleteEnvironmentProfile(ctx, &datazone.DeleteEnvironmentProfileInput{
DomainIdentifier: state.DomainIdentifier.ValueStringPointer(),
Identifier: state.Id.ValueStringPointer(),
})

if err != nil && !errs.IsA[*awstypes.ResourceNotFoundException](err) {
resp.Diagnostics.AddError(
create.ProblemStandardMessage(names.DataZone, create.ErrActionSetting, ResNameEnvironmentProfile, state.Id.ValueString(), err),
jar-b marked this conversation as resolved.
Show resolved Hide resolved
err.Error(),
)
return
}
}

func (r *resourceEnvironmentProfile) ImportState(ctx context.Context, req resource.ImportStateRequest, resp *resource.ImportStateResponse) {
parts := strings.Split(req.ID, ":")
jar-b marked this conversation as resolved.
Show resolved Hide resolved

if len(parts) != 4 {
resp.Diagnostics.AddError("Resource Import Invalid ID", fmt.Sprintf(`Unexpected format for import ID (%s), use: "DomainIdentifier:Id"`, req.ID))
}
jar-b marked this conversation as resolved.
Show resolved Hide resolved
resp.Diagnostics.Append(resp.State.SetAttribute(ctx, path.Root("domain_identifier"), parts[0])...)
resp.Diagnostics.Append(resp.State.SetAttribute(ctx, path.Root(names.AttrID), parts[1])...)
resp.Diagnostics.Append(resp.State.SetAttribute(ctx, path.Root("environment_blueprint_identifier"), parts[2])...)
resp.Diagnostics.Append(resp.State.SetAttribute(ctx, path.Root("project_identifier"), parts[3])...)
}

func findEnvironmentProfileByID(ctx context.Context, conn *datazone.Client, id string, domain_id string) (*datazone.GetEnvironmentProfileOutput, error) {
in := &datazone.GetEnvironmentProfileInput{
Identifier: aws.String(id),
DomainIdentifier: aws.String(domain_id),
}

out, err := conn.GetEnvironmentProfile(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 {
return nil, tfresource.NewEmptyResultError(in)
}

return out, nil
}

type dEnvProfile struct {
ThomasZalewski marked this conversation as resolved.
Show resolved Hide resolved
// entered and or computed
AwsAccountId types.String `tfsdk:"aws_account_id"`
AwsAccountRegion types.String `tfsdk:"aws_account_region"`
Description types.String `tfsdk:"description"`
Id types.String `tfsdk:"id"`
EnvironmentBlueprintIdentifier types.String `tfsdk:"environment_blueprint_identifier"`
UserParameters fwtypes.SetNestedObjectValueOf[dUserParameters] `tfsdk:"user_parameters"`

Name types.String `tfsdk:"name"`
ProjectIdentifier types.String `tfsdk:"project_identifier"`

// computed
CreatedAt timetypes.RFC3339 `tfsdk:"created_at"`
CreatedBy types.String `tfsdk:"created_by"`
DomainIdentifier types.String `tfsdk:"domain_identifier"`
UpdatedAt timetypes.RFC3339 `tfsdk:"updated_at"`
}

type dUserParameters struct {
ThomasZalewski marked this conversation as resolved.
Show resolved Hide resolved
// entered
Name types.String `tfsdk:"name"`
Value types.String `tfsdk:"value"`
}
Loading
Loading