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

Add new service package Support and new resource Case #132

Merged
merged 5 commits into from
Jan 31, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
7 changes: 4 additions & 3 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ require (
github.com/ProtonMail/go-crypto v0.0.0-20230923063757-afb1ddc0824c
github.com/YakDriver/regexache v0.23.0
github.com/aws/aws-sdk-go v1.49.2
github.com/aws/aws-sdk-go-v2 v1.24.0
github.com/aws/aws-sdk-go-v2 v1.24.1
mergenci marked this conversation as resolved.
Show resolved Hide resolved
github.com/aws/aws-sdk-go-v2/config v1.26.1
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.14.10
github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.15.7
Expand Down Expand Up @@ -92,6 +92,7 @@ require (
github.com/aws/aws-sdk-go-v2/service/ssmincidents v1.27.5
github.com/aws/aws-sdk-go-v2/service/ssoadmin v1.23.5
github.com/aws/aws-sdk-go-v2/service/sts v1.26.5
github.com/aws/aws-sdk-go-v2/service/support v1.19.6
github.com/aws/aws-sdk-go-v2/service/swf v1.20.5
github.com/aws/aws-sdk-go-v2/service/timestreamwrite v1.23.6
github.com/aws/aws-sdk-go-v2/service/transcribe v1.34.5
Expand Down Expand Up @@ -148,8 +149,8 @@ require (
github.com/armon/go-radix v1.0.0 // indirect
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.5.4 // indirect
github.com/aws/aws-sdk-go-v2/credentials v1.16.12 // indirect
github.com/aws/aws-sdk-go-v2/internal/configsources v1.2.9 // indirect
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.5.9 // indirect
github.com/aws/aws-sdk-go-v2/internal/configsources v1.2.10 // indirect
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.5.10 // indirect
github.com/aws/aws-sdk-go-v2/internal/ini v1.7.2 // indirect
github.com/aws/aws-sdk-go-v2/internal/v4a v1.2.9 // indirect
github.com/aws/aws-sdk-go-v2/service/dynamodb v1.26.6 // indirect
Expand Down
14 changes: 8 additions & 6 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -24,8 +24,8 @@ github.com/armon/go-radix v1.0.0 h1:F4z6KzEeeQIMeLFa97iZU6vupzoecKdU5TX24SNppXI=
github.com/armon/go-radix v1.0.0/go.mod h1:ufUuZ+zHj4x4TnLV4JWEpy2hxWSpsRywHrMgIH9cCH8=
github.com/aws/aws-sdk-go v1.49.2 h1:+4BEcm1nPCoDbVd+gg8cdxpa1qJfrvnddy12vpEVWjw=
github.com/aws/aws-sdk-go v1.49.2/go.mod h1:LF8svs817+Nz+DmiMQKTO3ubZ/6IaTpq3TjupRn3Eqk=
github.com/aws/aws-sdk-go-v2 v1.24.0 h1:890+mqQ+hTpNuw0gGP6/4akolQkSToDJgHfQE7AwGuk=
github.com/aws/aws-sdk-go-v2 v1.24.0/go.mod h1:LNh45Br1YAkEKaAqvmE1m8FUx6a5b/V0oAKV7of29b4=
github.com/aws/aws-sdk-go-v2 v1.24.1 h1:xAojnj+ktS95YZlDf0zxWBkbFtymPeDP+rvUQIH3uAU=
github.com/aws/aws-sdk-go-v2 v1.24.1/go.mod h1:LNh45Br1YAkEKaAqvmE1m8FUx6a5b/V0oAKV7of29b4=
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.5.4 h1:OCs21ST2LrepDfD3lwlQiOqIGp6JiEUqG84GzTDoyJs=
github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.5.4/go.mod h1:usURWEKSNNAcAZuzRn/9ZYPT8aZQkR7xcCtunK/LkJo=
github.com/aws/aws-sdk-go-v2/config v1.26.1 h1:z6DqMxclFGL3Zfo+4Q0rLnAZ6yVkzCRxhRMsiRQnD1o=
Expand All @@ -36,10 +36,10 @@ github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.14.10 h1:w98BT5w+ao1/r5sUuiH6Jk
github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.14.10/go.mod h1:K2WGI7vUvkIv1HoNbfBA1bvIZ+9kL3YVmWxeKuLQsiw=
github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.15.7 h1:FnLf60PtjXp8ZOzQfhJVsqF0OtYKQZWQfqOLshh8YXg=
github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.15.7/go.mod h1:tDVvl8hyU6E9B8TrnNrZQEVkQlB8hjJwcgpPhgtlnNg=
github.com/aws/aws-sdk-go-v2/internal/configsources v1.2.9 h1:v+HbZaCGmOwnTTVS86Fleq0vPzOd7tnJGbFhP0stNLs=
github.com/aws/aws-sdk-go-v2/internal/configsources v1.2.9/go.mod h1:Xjqy+Nyj7VDLBtCMkQYOw1QYfAEZCVLrfI0ezve8wd4=
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.5.9 h1:N94sVhRACtXyVcjXxrwK1SKFIJrA9pOJ5yu2eSHnmls=
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.5.9/go.mod h1:hqamLz7g1/4EJP+GH5NBhcUMLjW+gKLQabgyz6/7WAU=
github.com/aws/aws-sdk-go-v2/internal/configsources v1.2.10 h1:vF+Zgd9s+H4vOXd5BMaPWykta2a6Ih0AKLq/X6NYKn4=
github.com/aws/aws-sdk-go-v2/internal/configsources v1.2.10/go.mod h1:6BkRjejp/GR4411UGqkX8+wFMbFbqsUIimfK4XjOKR4=
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.5.10 h1:nYPe006ktcqUji8S2mqXf9c/7NdiKriOwMvWQHgYztw=
github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.5.10/go.mod h1:6UV4SZkVvmODfXKql4LCbaZUpF7HO2BX38FgBf9ZOLw=
github.com/aws/aws-sdk-go-v2/internal/ini v1.7.2 h1:GrSw8s0Gs/5zZ0SX+gX4zQjRnRsMJDJ2sLur1gRBhEM=
github.com/aws/aws-sdk-go-v2/internal/ini v1.7.2/go.mod h1:6fQQgfuGmw8Al/3M2IgIllycxV7ZW7WCdVSqfBeUiCY=
github.com/aws/aws-sdk-go-v2/internal/v4a v1.2.9 h1:ugD6qzjYtB7zM5PN/ZIeaAIyefPaD82G8+SJopgvUpw=
Expand Down Expand Up @@ -226,6 +226,8 @@ github.com/aws/aws-sdk-go-v2/service/ssooidc v1.21.5 h1:2k9KmFawS63euAkY4/ixVNsY
github.com/aws/aws-sdk-go-v2/service/ssooidc v1.21.5/go.mod h1:W+nd4wWDVkSUIox9bacmkBP5NMFQeTJ/xqNabpzSR38=
github.com/aws/aws-sdk-go-v2/service/sts v1.26.5 h1:5UYvv8JUvllZsRnfrcMQ+hJ9jNICmcgKPAO1CER25Wg=
github.com/aws/aws-sdk-go-v2/service/sts v1.26.5/go.mod h1:XX5gh4CB7wAs4KhcF46G6C8a2i7eupU19dcAAE+EydU=
github.com/aws/aws-sdk-go-v2/service/support v1.19.6 h1:ZD8OSo915ouOvw9JIjT0pccHwubdLoHmQYjAXIxFA0I=
github.com/aws/aws-sdk-go-v2/service/support v1.19.6/go.mod h1:Mzty8X8zv84IXyvPJ0nI1gZhurnKgrD46J6MRgJsGGk=
github.com/aws/aws-sdk-go-v2/service/swf v1.20.5 h1:9CU3kwRGpUReKubOsmxgG9LfaVpZ1PW/ON+5ZTKu5Gs=
github.com/aws/aws-sdk-go-v2/service/swf v1.20.5/go.mod h1:i01QTdCHqrntRqtNeYmxUSDCcmXERzFCePIcHDjASHE=
github.com/aws/aws-sdk-go-v2/service/timestreamwrite v1.23.6 h1:+7xZRneTlcraXL4+oN2kUlQX9ULh4aIxmcpUoR/faGA=
Expand Down
5 changes: 5 additions & 0 deletions internal/conns/awsclient_gen.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions internal/provider/service_packages_gen.go

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

259 changes: 259 additions & 0 deletions internal/service/support/case.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,259 @@
// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: MPL-2.0

package support

import (
"context"

"github.com/aws/aws-sdk-go-v2/service/support"
awstypes "github.com/aws/aws-sdk-go-v2/service/support/types"
"github.com/aws/aws-sdk-go/aws"
"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/listplanmodifier"
"github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier"
"github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier"
"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"
"github.com/hashicorp/terraform-provider-aws/internal/tfresource"
"github.com/hashicorp/terraform-provider-aws/names"
)

// @FrameworkResource(name="Case")
func newResourceCase(_ context.Context) (resource.ResourceWithConfigure, error) {
return &resourceCase{}, nil
}

const (
ResourceNameCase = "Case"
)

type resourceCase struct {
framework.ResourceWithConfigure
}

func (r *resourceCase) Metadata(_ context.Context, _ resource.MetadataRequest, response *resource.MetadataResponse) {
response.TypeName = "aws_support_case"
}

// Schema returns the schema for this resource.
func (r *resourceCase) Schema(ctx context.Context, request resource.SchemaRequest, response *resource.SchemaResponse) {
response.Schema = schema.Schema{
Attributes: map[string]schema.Attribute{
"case_id": schema.StringAttribute{
Computed: true,
PlanModifiers: []planmodifier.String{
stringplanmodifier.UseStateForUnknown(),
},
},
"category_code": schema.StringAttribute{
Required: true,
Validators: []validator.String{
stringvalidator.LengthAtLeast(1),
},
PlanModifiers: []planmodifier.String{
stringplanmodifier.RequiresReplace(),
},
},
"cc_email_addresses": schema.ListAttribute{
Optional: true,
ElementType: types.StringType,
PlanModifiers: []planmodifier.List{
listplanmodifier.RequiresReplace(),
},
},
"communication_body": schema.StringAttribute{
Required: true,
Validators: []validator.String{
stringvalidator.LengthAtLeast(1),
},
PlanModifiers: []planmodifier.String{
stringplanmodifier.RequiresReplace(),
},
},
"display_id": schema.StringAttribute{
Computed: true,
PlanModifiers: []planmodifier.String{
stringplanmodifier.UseStateForUnknown(),
},
},
"id": framework.IDAttribute(),
"issue_type": schema.StringAttribute{
Optional: true,
},
"language": schema.StringAttribute{
Required: true,
PlanModifiers: []planmodifier.String{
stringplanmodifier.RequiresReplace(),
},
},
"service_code": schema.StringAttribute{
Required: true,
Validators: []validator.String{
stringvalidator.LengthAtLeast(1),
},
PlanModifiers: []planmodifier.String{
stringplanmodifier.RequiresReplace(),
},
},
"severity_code": schema.StringAttribute{
Required: true,
},
"subject": schema.StringAttribute{
Required: true,
PlanModifiers: []planmodifier.String{
stringplanmodifier.RequiresReplace(),
},
},
},
}
}

func (r *resourceCase) Create(ctx context.Context, request resource.CreateRequest, response *resource.CreateResponse) {
var plan resourceCaseData
response.Diagnostics.Append(request.Plan.Get(ctx, &plan)...)
if response.Diagnostics.HasError() {
return
}

conn := r.Meta().SupportClient(ctx)

input := support.CreateCaseInput{
CommunicationBody: flex.StringFromFramework(ctx, plan.CommunicationBody),
Subject: flex.StringFromFramework(ctx, plan.Subject),
CategoryCode: flex.StringFromFramework(ctx, plan.CategoryCode),
CcEmailAddresses: flex.ExpandFrameworkStringValueList(ctx, plan.CCEmailAddresses),
IssueType: flex.StringFromFramework(ctx, plan.IssueType),
Language: flex.StringFromFramework(ctx, plan.Language),
ServiceCode: flex.StringFromFramework(ctx, plan.ServiceCode),
SeverityCode: flex.StringFromFramework(ctx, plan.SeverityCode),
}
output, err := conn.CreateCase(ctx, &input)
if err != nil {
response.Diagnostics.Append(create.DiagErrorFramework(names.Support, create.ErrActionCreating, ResourceNameCase, plan.Subject.String(), err))
return
}

// Create API call returns only Case ID. Get other details as well.
caseDetails, err := findCaseByID(ctx, conn, *output.CaseId)
if err != nil {
response.Diagnostics.Append(create.DiagErrorFramework(names.Support, create.ErrActionChecking, ResourceNameCase, plan.Subject.String(), err))
return
}

state := plan
state.refreshFromOutput(ctx, caseDetails)

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

func (r *resourceCase) Read(ctx context.Context, request resource.ReadRequest, response *resource.ReadResponse) {
var state resourceCaseData
response.Diagnostics.Append(request.State.Get(ctx, &state)...)
if response.Diagnostics.HasError() {
return
}

conn := r.Meta().SupportClient(ctx)

caseDetails, err := findCaseByID(ctx, conn, state.ID.ValueString())
if tfresource.NotFound(err) {
create.LogNotFoundRemoveState(names.Support, create.ErrActionReading, ResourceNameCase, state.ID.ValueString())
response.State.RemoveResource(ctx)
return
}
if err != nil {
response.Diagnostics.Append(create.DiagErrorFramework(names.Support, create.ErrActionReading, ResourceNameCase, state.ID.String(), err))
return
}

state.refreshFromOutput(ctx, caseDetails)
response.Diagnostics.Append(response.State.Set(ctx, &state)...)
}

// Update is a no-op.
func (r *resourceCase) Update(_ context.Context, _ resource.UpdateRequest, _ *resource.UpdateResponse) {
}

// Delete is a no-op, because AWS doesn't provide a deletion API.
func (r *resourceCase) Delete(_ context.Context, _ resource.DeleteRequest, _ *resource.DeleteResponse) {
}

func (r *resourceCase) ImportState(ctx context.Context, request resource.ImportStateRequest, response *resource.ImportStateResponse) {
resource.ImportStatePassthroughID(ctx, path.Root("id"), request, response)
}

func findCaseByID(ctx context.Context, conn *support.Client, caseID string) (*awstypes.CaseDetails, error) {
if caseID == "" {
return nil, &retry.NotFoundError{
Message: "cannot find Case with an empty ID.",
}
}

input := &support.DescribeCasesInput{
CaseIdList: []string{*aws.String(caseID)},
}

output, err := conn.DescribeCases(ctx, input)

if errs.IsA[*awstypes.CaseIdNotFound](err) {
return nil, &retry.NotFoundError{
LastError: err,
LastRequest: input,
}
}

if err != nil {
return nil, err
}

if output == nil || len(output.Cases) == 0 {
return nil, tfresource.NewEmptyResultError(input)
}

if len(output.Cases) > 1 {
return nil, tfresource.NewTooManyResultsError(len(output.Cases), input)
}

return &output.Cases[0], nil
}

type resourceCaseData struct {
CaseID types.String `tfsdk:"case_id"`
CategoryCode types.String `tfsdk:"category_code"`
CCEmailAddresses types.List `tfsdk:"cc_email_addresses"`
CommunicationBody types.String `tfsdk:"communication_body"`
DisplayID types.String `tfsdk:"display_id"`
ID types.String `tfsdk:"id"`
IssueType types.String `tfsdk:"issue_type"`
Language types.String `tfsdk:"language"`
ServiceCode types.String `tfsdk:"service_code"`
SeverityCode types.String `tfsdk:"severity_code"`
Subject types.String `tfsdk:"subject"`
}

func (rd *resourceCaseData) refreshFromOutput(ctx context.Context, out *awstypes.CaseDetails) {
if out == nil {
return
}

rd.CaseID = flex.StringToFramework(ctx, out.CaseId)
rd.ID = rd.CaseID

rd.CategoryCode = flex.StringToFramework(ctx, out.CategoryCode)
rd.CCEmailAddresses = flex.FlattenFrameworkStringValueList(ctx, out.CcEmailAddresses)
rd.DisplayID = flex.StringToFramework(ctx, out.DisplayId)
rd.Language = flex.StringToFramework(ctx, out.Language)
rd.ServiceCode = flex.StringToFramework(ctx, out.ServiceCode)
rd.SeverityCode = flex.StringToFramework(ctx, out.SeverityCode)
rd.Subject = flex.StringToFramework(ctx, out.Subject)
}
Loading
Loading