diff --git a/.changelog/37152.txt b/.changelog/37152.txt new file mode 100644 index 00000000000..87ba726e3a6 --- /dev/null +++ b/.changelog/37152.txt @@ -0,0 +1,7 @@ +```release-note:enhancement +resource/aws_iot_authorizer: Add `tags` argument +``` + +```release-note:bug +resource/aws_iot_provisioning_template: Fix `pre_provisioning_hook` update operation +``` \ No newline at end of file diff --git a/go.mod b/go.mod index 5a96bb53465..56ca2060543 100644 --- a/go.mod +++ b/go.mod @@ -106,6 +106,7 @@ require ( github.com/aws/aws-sdk-go-v2/service/glacier v1.24.1 github.com/aws/aws-sdk-go-v2/service/globalaccelerator v1.26.1 github.com/aws/aws-sdk-go-v2/service/grafana v1.24.1 + github.com/aws/aws-sdk-go-v2/service/greengrass v1.25.1 github.com/aws/aws-sdk-go-v2/service/groundstation v1.29.1 github.com/aws/aws-sdk-go-v2/service/guardduty v1.45.1 github.com/aws/aws-sdk-go-v2/service/healthlake v1.26.1 @@ -113,6 +114,9 @@ require ( github.com/aws/aws-sdk-go-v2/service/identitystore v1.25.1 github.com/aws/aws-sdk-go-v2/service/inspector2 v1.28.1 github.com/aws/aws-sdk-go-v2/service/internetmonitor v1.16.1 + github.com/aws/aws-sdk-go-v2/service/iot v1.55.1 + github.com/aws/aws-sdk-go-v2/service/iotanalytics v1.24.1 + github.com/aws/aws-sdk-go-v2/service/iotevents v1.25.1 github.com/aws/aws-sdk-go-v2/service/ivschat v1.14.1 github.com/aws/aws-sdk-go-v2/service/kafka v1.35.1 github.com/aws/aws-sdk-go-v2/service/kendra v1.52.1 diff --git a/go.sum b/go.sum index e162ffb88f2..60cf313a4e0 100644 --- a/go.sum +++ b/go.sum @@ -232,6 +232,8 @@ github.com/aws/aws-sdk-go-v2/service/globalaccelerator v1.26.1 h1:ZF//0v9qJttmSj github.com/aws/aws-sdk-go-v2/service/globalaccelerator v1.26.1/go.mod h1:bWwtuxoMnUPJAn7EjLscm0ddKzf++mnjCUF8J/gjxsA= github.com/aws/aws-sdk-go-v2/service/grafana v1.24.1 h1:9arpyvo+AHuSlfwd0B4+99mSauANa+ca4UR04TXpMC8= github.com/aws/aws-sdk-go-v2/service/grafana v1.24.1/go.mod h1:w3Do1roFlHxKtjWkjSwevSX4Vbia2CpZ32rfBa38xJs= +github.com/aws/aws-sdk-go-v2/service/greengrass v1.25.1 h1:Fw4hUGV/H7uJUf+h/ZkwXHDUrCeRzy6T8JvzsM5J1yE= +github.com/aws/aws-sdk-go-v2/service/greengrass v1.25.1/go.mod h1:sdnAwxQLduSCSlpqfPY8XSfcPNzT9uMG+h7+AmgPQ1w= github.com/aws/aws-sdk-go-v2/service/groundstation v1.29.1 h1:b7NYx+Wns7iVGWCoVDlYeJhmBvzYBrtCqbIkDxOrHE8= github.com/aws/aws-sdk-go-v2/service/groundstation v1.29.1/go.mod h1:AJdJPFZ2QWkkVn/zt+y9KcVTZiMCWQCgDyMRjxr6Rww= github.com/aws/aws-sdk-go-v2/service/guardduty v1.45.1 h1:+YYUnMwh5C8JIKCdwMjcamNqbId+vidg4Dri2Z+VSKA= @@ -256,6 +258,12 @@ github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.17.13 h1:Eq2THzHt6P41m github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.17.13/go.mod h1:FgwTca6puegxgCInYwGjmd4tB9195Dd6LCuA+8MjpWw= github.com/aws/aws-sdk-go-v2/service/internetmonitor v1.16.1 h1:k/RKod+whF8SajBLtMbonnASqDH7cdcaV+dV4Y+Iy14= github.com/aws/aws-sdk-go-v2/service/internetmonitor v1.16.1/go.mod h1:XPMC1HSRRPuwRPyJxEOdmXDMwSzwuLRgJxWvruqOb1E= +github.com/aws/aws-sdk-go-v2/service/iot v1.55.1 h1:vtcrAu71ib/I1HZMNT/Kse/EHOnoxsG72sqlkuCn7mE= +github.com/aws/aws-sdk-go-v2/service/iot v1.55.1/go.mod h1:teEXCZKFcHzIeb3lp18Rg1UQNB1dFSza6xlnPySBUsE= +github.com/aws/aws-sdk-go-v2/service/iotanalytics v1.24.1 h1:HgYcw25tNge1/t+QTaGP5snHG2Ktb/u4KlD/qkxyjk8= +github.com/aws/aws-sdk-go-v2/service/iotanalytics v1.24.1/go.mod h1:7EAfulhWZOndeYQyqloMJoPK9YbInZ7MXsDRTB3QcU0= +github.com/aws/aws-sdk-go-v2/service/iotevents v1.25.1 h1:5DFNTv6jUEMVK/XiO/kjFhJLALQUXhBxERUHqY2I1Fg= +github.com/aws/aws-sdk-go-v2/service/iotevents v1.25.1/go.mod h1:aFAvBjoz1mujsaPHgVoj4Bhwg6xG7vzk1AfCOt7/u8I= github.com/aws/aws-sdk-go-v2/service/ivschat v1.14.1 h1:rmVLJaE6iqVSSeipZnhul8BMBm6PkVIWvFkPUnSLYcc= github.com/aws/aws-sdk-go-v2/service/ivschat v1.14.1/go.mod h1:IUQ9qdszWBPacNZ36JLkmOxGx/2LCzz/DOZjpg/8tz4= github.com/aws/aws-sdk-go-v2/service/kafka v1.35.1 h1:Q4Jr/gf+7LHjBFTdecQJn4ugVoVszCHzyq1EztrHHkc= diff --git a/internal/conns/awsclient_gen.go b/internal/conns/awsclient_gen.go index 77f20629330..0a7c294203f 100644 --- a/internal/conns/awsclient_gen.go +++ b/internal/conns/awsclient_gen.go @@ -98,6 +98,7 @@ import ( glacier_sdkv2 "github.com/aws/aws-sdk-go-v2/service/glacier" globalaccelerator_sdkv2 "github.com/aws/aws-sdk-go-v2/service/globalaccelerator" grafana_sdkv2 "github.com/aws/aws-sdk-go-v2/service/grafana" + greengrass_sdkv2 "github.com/aws/aws-sdk-go-v2/service/greengrass" groundstation_sdkv2 "github.com/aws/aws-sdk-go-v2/service/groundstation" guardduty_sdkv2 "github.com/aws/aws-sdk-go-v2/service/guardduty" healthlake_sdkv2 "github.com/aws/aws-sdk-go-v2/service/healthlake" @@ -105,6 +106,9 @@ import ( identitystore_sdkv2 "github.com/aws/aws-sdk-go-v2/service/identitystore" inspector2_sdkv2 "github.com/aws/aws-sdk-go-v2/service/inspector2" internetmonitor_sdkv2 "github.com/aws/aws-sdk-go-v2/service/internetmonitor" + iot_sdkv2 "github.com/aws/aws-sdk-go-v2/service/iot" + iotanalytics_sdkv2 "github.com/aws/aws-sdk-go-v2/service/iotanalytics" + iotevents_sdkv2 "github.com/aws/aws-sdk-go-v2/service/iotevents" ivschat_sdkv2 "github.com/aws/aws-sdk-go-v2/service/ivschat" kafka_sdkv2 "github.com/aws/aws-sdk-go-v2/service/kafka" kendra_sdkv2 "github.com/aws/aws-sdk-go-v2/service/kendra" @@ -215,13 +219,9 @@ import ( fsx_sdkv1 "github.com/aws/aws-sdk-go/service/fsx" gamelift_sdkv1 "github.com/aws/aws-sdk-go/service/gamelift" glue_sdkv1 "github.com/aws/aws-sdk-go/service/glue" - greengrass_sdkv1 "github.com/aws/aws-sdk-go/service/greengrass" guardduty_sdkv1 "github.com/aws/aws-sdk-go/service/guardduty" imagebuilder_sdkv1 "github.com/aws/aws-sdk-go/service/imagebuilder" inspector_sdkv1 "github.com/aws/aws-sdk-go/service/inspector" - iot_sdkv1 "github.com/aws/aws-sdk-go/service/iot" - iotanalytics_sdkv1 "github.com/aws/aws-sdk-go/service/iotanalytics" - iotevents_sdkv1 "github.com/aws/aws-sdk-go/service/iotevents" ivs_sdkv1 "github.com/aws/aws-sdk-go/service/ivs" kafkaconnect_sdkv1 "github.com/aws/aws-sdk-go/service/kafkaconnect" kinesisanalytics_sdkv1 "github.com/aws/aws-sdk-go/service/kinesisanalytics" @@ -722,8 +722,8 @@ func (c *AWSClient) GrafanaClient(ctx context.Context) *grafana_sdkv2.Client { return errs.Must(client[*grafana_sdkv2.Client](ctx, c, names.Grafana, make(map[string]any))) } -func (c *AWSClient) GreengrassConn(ctx context.Context) *greengrass_sdkv1.Greengrass { - return errs.Must(conn[*greengrass_sdkv1.Greengrass](ctx, c, names.Greengrass, make(map[string]any))) +func (c *AWSClient) GreengrassClient(ctx context.Context) *greengrass_sdkv2.Client { + return errs.Must(client[*greengrass_sdkv2.Client](ctx, c, names.Greengrass, make(map[string]any))) } func (c *AWSClient) GroundStationClient(ctx context.Context) *groundstation_sdkv2.Client { @@ -774,16 +774,16 @@ func (c *AWSClient) InternetMonitorClient(ctx context.Context) *internetmonitor_ return errs.Must(client[*internetmonitor_sdkv2.Client](ctx, c, names.InternetMonitor, make(map[string]any))) } -func (c *AWSClient) IoTConn(ctx context.Context) *iot_sdkv1.IoT { - return errs.Must(conn[*iot_sdkv1.IoT](ctx, c, names.IoT, make(map[string]any))) +func (c *AWSClient) IoTClient(ctx context.Context) *iot_sdkv2.Client { + return errs.Must(client[*iot_sdkv2.Client](ctx, c, names.IoT, make(map[string]any))) } -func (c *AWSClient) IoTAnalyticsConn(ctx context.Context) *iotanalytics_sdkv1.IoTAnalytics { - return errs.Must(conn[*iotanalytics_sdkv1.IoTAnalytics](ctx, c, names.IoTAnalytics, make(map[string]any))) +func (c *AWSClient) IoTAnalyticsClient(ctx context.Context) *iotanalytics_sdkv2.Client { + return errs.Must(client[*iotanalytics_sdkv2.Client](ctx, c, names.IoTAnalytics, make(map[string]any))) } -func (c *AWSClient) IoTEventsConn(ctx context.Context) *iotevents_sdkv1.IoTEvents { - return errs.Must(conn[*iotevents_sdkv1.IoTEvents](ctx, c, names.IoTEvents, make(map[string]any))) +func (c *AWSClient) IoTEventsClient(ctx context.Context) *iotevents_sdkv2.Client { + return errs.Must(client[*iotevents_sdkv2.Client](ctx, c, names.IoTEvents, make(map[string]any))) } func (c *AWSClient) KMSClient(ctx context.Context) *kms_sdkv2.Client { diff --git a/internal/service/greengrass/generate.go b/internal/service/greengrass/generate.go index dc1f07e6d4e..62f853c1770 100644 --- a/internal/service/greengrass/generate.go +++ b/internal/service/greengrass/generate.go @@ -1,7 +1,7 @@ // Copyright (c) HashiCorp, Inc. // SPDX-License-Identifier: MPL-2.0 -//go:generate go run ../../generate/tags/main.go -ListTags -ServiceTagsMap -UpdateTags +//go:generate go run ../../generate/tags/main.go -ListTags -ServiceTagsMap -UpdateTags -AWSSDKVersion=2 -KVTValues -SkipTypesImp //go:generate go run ../../generate/servicepackage/main.go // ONLY generate directives and package declaration! Do not add anything else to this file. diff --git a/internal/service/greengrass/service_endpoint_resolver_gen.go b/internal/service/greengrass/service_endpoint_resolver_gen.go index 39bb3bc7003..c1563d389c3 100644 --- a/internal/service/greengrass/service_endpoint_resolver_gen.go +++ b/internal/service/greengrass/service_endpoint_resolver_gen.go @@ -6,65 +6,63 @@ import ( "context" "fmt" "net" - "net/url" - endpoints_sdkv1 "github.com/aws/aws-sdk-go/aws/endpoints" + aws_sdkv2 "github.com/aws/aws-sdk-go-v2/aws" + greengrass_sdkv2 "github.com/aws/aws-sdk-go-v2/service/greengrass" + smithyendpoints "github.com/aws/smithy-go/endpoints" "github.com/hashicorp/terraform-plugin-log/tflog" "github.com/hashicorp/terraform-provider-aws/internal/errs" ) -var _ endpoints_sdkv1.Resolver = resolverSDKv1{} +var _ greengrass_sdkv2.EndpointResolverV2 = resolverSDKv2{} -type resolverSDKv1 struct { - ctx context.Context +type resolverSDKv2 struct { + defaultResolver greengrass_sdkv2.EndpointResolverV2 } -func newEndpointResolverSDKv1(ctx context.Context) resolverSDKv1 { - return resolverSDKv1{ - ctx: ctx, +func newEndpointResolverSDKv2() resolverSDKv2 { + return resolverSDKv2{ + defaultResolver: greengrass_sdkv2.NewDefaultEndpointResolverV2(), } } -func (r resolverSDKv1) EndpointFor(service, region string, opts ...func(*endpoints_sdkv1.Options)) (endpoint endpoints_sdkv1.ResolvedEndpoint, err error) { - ctx := r.ctx +func (r resolverSDKv2) ResolveEndpoint(ctx context.Context, params greengrass_sdkv2.EndpointParameters) (endpoint smithyendpoints.Endpoint, err error) { + params = params.WithDefaults() + useFIPS := aws_sdkv2.ToBool(params.UseFIPS) - var opt endpoints_sdkv1.Options - opt.Set(opts...) - - useFIPS := opt.UseFIPSEndpoint == endpoints_sdkv1.FIPSEndpointStateEnabled + if eps := params.Endpoint; aws_sdkv2.ToString(eps) != "" { + tflog.Debug(ctx, "setting endpoint", map[string]any{ + "tf_aws.endpoint": endpoint, + }) - defaultResolver := endpoints_sdkv1.DefaultResolver() + if useFIPS { + tflog.Debug(ctx, "endpoint set, ignoring UseFIPSEndpoint setting") + params.UseFIPS = aws_sdkv2.Bool(false) + } - if useFIPS { + return r.defaultResolver.ResolveEndpoint(ctx, params) + } else if useFIPS { ctx = tflog.SetField(ctx, "tf_aws.use_fips", useFIPS) - endpoint, err = defaultResolver.EndpointFor(service, region, opts...) + endpoint, err = r.defaultResolver.ResolveEndpoint(ctx, params) if err != nil { return endpoint, err } tflog.Debug(ctx, "endpoint resolved", map[string]any{ - "tf_aws.endpoint": endpoint.URL, + "tf_aws.endpoint": endpoint.URI.String(), }) - var endpointURL *url.URL - endpointURL, err = url.Parse(endpoint.URL) - if err != nil { - return endpoint, err - } - - hostname := endpointURL.Hostname() + hostname := endpoint.URI.Hostname() _, err = net.LookupHost(hostname) if err != nil { if dnsErr, ok := errs.As[*net.DNSError](err); ok && dnsErr.IsNotFound { tflog.Debug(ctx, "default endpoint host not found, disabling FIPS", map[string]any{ "tf_aws.hostname": hostname, }) - opts = append(opts, func(o *endpoints_sdkv1.Options) { - o.UseFIPSEndpoint = endpoints_sdkv1.FIPSEndpointStateDisabled - }) + params.UseFIPS = aws_sdkv2.Bool(false) } else { - err = fmt.Errorf("looking up accessanalyzer endpoint %q: %s", hostname, err) + err = fmt.Errorf("looking up greengrass endpoint %q: %s", hostname, err) return } } else { @@ -72,5 +70,13 @@ func (r resolverSDKv1) EndpointFor(service, region string, opts ...func(*endpoin } } - return defaultResolver.EndpointFor(service, region, opts...) + return r.defaultResolver.ResolveEndpoint(ctx, params) +} + +func withBaseEndpoint(endpoint string) func(*greengrass_sdkv2.Options) { + return func(o *greengrass_sdkv2.Options) { + if endpoint != "" { + o.BaseEndpoint = aws_sdkv2.String(endpoint) + } + } } diff --git a/internal/service/greengrass/service_endpoints_gen_test.go b/internal/service/greengrass/service_endpoints_gen_test.go index bf752d93c7d..7a6a2c1699c 100644 --- a/internal/service/greengrass/service_endpoints_gen_test.go +++ b/internal/service/greengrass/service_endpoints_gen_test.go @@ -4,18 +4,22 @@ package greengrass_test import ( "context" + "errors" "fmt" "maps" "net" "net/url" "os" "path/filepath" + "reflect" "strings" "testing" - aws_sdkv1 "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/endpoints" - greengrass_sdkv1 "github.com/aws/aws-sdk-go/service/greengrass" + aws_sdkv2 "github.com/aws/aws-sdk-go-v2/aws" + awsmiddleware "github.com/aws/aws-sdk-go-v2/aws/middleware" + greengrass_sdkv2 "github.com/aws/aws-sdk-go-v2/service/greengrass" + "github.com/aws/smithy-go/middleware" + smithyhttp "github.com/aws/smithy-go/transport/http" "github.com/google/go-cmp/cmp" "github.com/hashicorp/aws-sdk-go-base/v2/servicemocks" "github.com/hashicorp/terraform-plugin-sdk/v2/diag" @@ -240,54 +244,63 @@ func TestEndpointConfiguration(t *testing.T) { //nolint:paralleltest // uses t.S } func defaultEndpoint(region string) (url.URL, error) { - r := endpoints.DefaultResolver() + r := greengrass_sdkv2.NewDefaultEndpointResolverV2() - ep, err := r.EndpointFor(greengrass_sdkv1.EndpointsID, region) + ep, err := r.ResolveEndpoint(context.Background(), greengrass_sdkv2.EndpointParameters{ + Region: aws_sdkv2.String(region), + }) if err != nil { return url.URL{}, err } - url, _ := url.Parse(ep.URL) - - if url.Path == "" { - url.Path = "/" + if ep.URI.Path == "" { + ep.URI.Path = "/" } - return *url, nil + return ep.URI, nil } func defaultFIPSEndpoint(region string) (url.URL, error) { - r := endpoints.DefaultResolver() + r := greengrass_sdkv2.NewDefaultEndpointResolverV2() - ep, err := r.EndpointFor(greengrass_sdkv1.EndpointsID, region, func(opt *endpoints.Options) { - opt.UseFIPSEndpoint = endpoints.FIPSEndpointStateEnabled + ep, err := r.ResolveEndpoint(context.Background(), greengrass_sdkv2.EndpointParameters{ + Region: aws_sdkv2.String(region), + UseFIPS: aws_sdkv2.Bool(true), }) if err != nil { return url.URL{}, err } - url, _ := url.Parse(ep.URL) - - if url.Path == "" { - url.Path = "/" + if ep.URI.Path == "" { + ep.URI.Path = "/" } - return *url, nil + return ep.URI, nil } func callService(ctx context.Context, t *testing.T, meta *conns.AWSClient) apiCallParams { t.Helper() - client := meta.GreengrassConn(ctx) + client := meta.GreengrassClient(ctx) - req, _ := client.ListGroupsRequest(&greengrass_sdkv1.ListGroupsInput{}) + var result apiCallParams - req.HTTPRequest.URL.Path = "/" - - return apiCallParams{ - endpoint: req.HTTPRequest.URL.String(), - region: aws_sdkv1.StringValue(client.Config.Region), + _, err := client.ListGroups(ctx, &greengrass_sdkv2.ListGroupsInput{}, + func(opts *greengrass_sdkv2.Options) { + opts.APIOptions = append(opts.APIOptions, + addRetrieveEndpointURLMiddleware(t, &result.endpoint), + addRetrieveRegionMiddleware(&result.region), + addCancelRequestMiddleware(), + ) + }, + ) + if err == nil { + t.Fatal("Expected an error, got none") + } else if !errors.Is(err, errCancelOperation) { + t.Fatalf("Unexpected error: %s", err) } + + return result } func withNoConfig(_ *caseSetup) { @@ -466,6 +479,89 @@ func testEndpointCase(t *testing.T, region string, testcase endpointTestCase, ca } } +func addRetrieveEndpointURLMiddleware(t *testing.T, endpoint *string) func(*middleware.Stack) error { + return func(stack *middleware.Stack) error { + return stack.Finalize.Add( + retrieveEndpointURLMiddleware(t, endpoint), + middleware.After, + ) + } +} + +func retrieveEndpointURLMiddleware(t *testing.T, endpoint *string) middleware.FinalizeMiddleware { + return middleware.FinalizeMiddlewareFunc( + "Test: Retrieve Endpoint", + func(ctx context.Context, in middleware.FinalizeInput, next middleware.FinalizeHandler) (middleware.FinalizeOutput, middleware.Metadata, error) { + t.Helper() + + request, ok := in.Request.(*smithyhttp.Request) + if !ok { + t.Fatalf("Expected *github.com/aws/smithy-go/transport/http.Request, got %s", fullTypeName(in.Request)) + } + + url := request.URL + url.RawQuery = "" + url.Path = "/" + + *endpoint = url.String() + + return next.HandleFinalize(ctx, in) + }) +} + +func addRetrieveRegionMiddleware(region *string) func(*middleware.Stack) error { + return func(stack *middleware.Stack) error { + return stack.Serialize.Add( + retrieveRegionMiddleware(region), + middleware.After, + ) + } +} + +func retrieveRegionMiddleware(region *string) middleware.SerializeMiddleware { + return middleware.SerializeMiddlewareFunc( + "Test: Retrieve Region", + func(ctx context.Context, in middleware.SerializeInput, next middleware.SerializeHandler) (middleware.SerializeOutput, middleware.Metadata, error) { + *region = awsmiddleware.GetRegion(ctx) + + return next.HandleSerialize(ctx, in) + }, + ) +} + +var errCancelOperation = fmt.Errorf("Test: Canceling request") + +func addCancelRequestMiddleware() func(*middleware.Stack) error { + return func(stack *middleware.Stack) error { + return stack.Finalize.Add( + cancelRequestMiddleware(), + middleware.After, + ) + } +} + +// cancelRequestMiddleware creates a Smithy middleware that intercepts the request before sending and cancels it +func cancelRequestMiddleware() middleware.FinalizeMiddleware { + return middleware.FinalizeMiddlewareFunc( + "Test: Cancel Requests", + func(_ context.Context, in middleware.FinalizeInput, next middleware.FinalizeHandler) (middleware.FinalizeOutput, middleware.Metadata, error) { + return middleware.FinalizeOutput{}, middleware.Metadata{}, errCancelOperation + }) +} + +func fullTypeName(i interface{}) string { + return fullValueTypeName(reflect.ValueOf(i)) +} + +func fullValueTypeName(v reflect.Value) string { + if v.Kind() == reflect.Ptr { + return "*" + fullValueTypeName(reflect.Indirect(v)) + } + + requestType := v.Type() + return fmt.Sprintf("%s.%s", requestType.PkgPath(), requestType.Name()) +} + func generateSharedConfigFile(config configFile) string { var buf strings.Builder diff --git a/internal/service/greengrass/service_package_gen.go b/internal/service/greengrass/service_package_gen.go index 9ae480b6113..171fd82de01 100644 --- a/internal/service/greengrass/service_package_gen.go +++ b/internal/service/greengrass/service_package_gen.go @@ -5,10 +5,8 @@ package greengrass import ( "context" - aws_sdkv1 "github.com/aws/aws-sdk-go/aws" - session_sdkv1 "github.com/aws/aws-sdk-go/aws/session" - greengrass_sdkv1 "github.com/aws/aws-sdk-go/service/greengrass" - "github.com/hashicorp/terraform-plugin-log/tflog" + aws_sdkv2 "github.com/aws/aws-sdk-go-v2/aws" + greengrass_sdkv2 "github.com/aws/aws-sdk-go-v2/service/greengrass" "github.com/hashicorp/terraform-provider-aws/internal/conns" "github.com/hashicorp/terraform-provider-aws/internal/types" "github.com/hashicorp/terraform-provider-aws/names" @@ -36,22 +34,14 @@ func (p *servicePackage) ServicePackageName() string { return names.Greengrass } -// NewConn returns a new AWS SDK for Go v1 client for this service package's AWS API. -func (p *servicePackage) NewConn(ctx context.Context, config map[string]any) (*greengrass_sdkv1.Greengrass, error) { - sess := config[names.AttrSession].(*session_sdkv1.Session) +// NewClient returns a new AWS SDK for Go v2 client for this service package's AWS API. +func (p *servicePackage) NewClient(ctx context.Context, config map[string]any) (*greengrass_sdkv2.Client, error) { + cfg := *(config["aws_sdkv2_config"].(*aws_sdkv2.Config)) - cfg := aws_sdkv1.Config{} - - if endpoint := config[names.AttrEndpoint].(string); endpoint != "" { - tflog.Debug(ctx, "setting endpoint", map[string]any{ - "tf_aws.endpoint": endpoint, - }) - cfg.Endpoint = aws_sdkv1.String(endpoint) - } else { - cfg.EndpointResolver = newEndpointResolverSDKv1(ctx) - } - - return greengrass_sdkv1.New(sess.Copy(&cfg)), nil + return greengrass_sdkv2.NewFromConfig(cfg, + greengrass_sdkv2.WithEndpointResolverV2(newEndpointResolverSDKv2()), + withBaseEndpoint(config[names.AttrEndpoint].(string)), + ), nil } func ServicePackage(ctx context.Context) conns.ServicePackage { diff --git a/internal/service/greengrass/tags_gen.go b/internal/service/greengrass/tags_gen.go index 76b1d773c02..e1332362973 100644 --- a/internal/service/greengrass/tags_gen.go +++ b/internal/service/greengrass/tags_gen.go @@ -5,9 +5,8 @@ import ( "context" "fmt" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/service/greengrass" - "github.com/aws/aws-sdk-go/service/greengrass/greengrassiface" + "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/service/greengrass" "github.com/hashicorp/terraform-plugin-log/tflog" "github.com/hashicorp/terraform-provider-aws/internal/conns" "github.com/hashicorp/terraform-provider-aws/internal/logging" @@ -19,12 +18,12 @@ import ( // listTags lists greengrass service tags. // The identifier is typically the Amazon Resource Name (ARN), although // it may also be a different identifier depending on the service. -func listTags(ctx context.Context, conn greengrassiface.GreengrassAPI, identifier string) (tftags.KeyValueTags, error) { +func listTags(ctx context.Context, conn *greengrass.Client, identifier string, optFns ...func(*greengrass.Options)) (tftags.KeyValueTags, error) { input := &greengrass.ListTagsForResourceInput{ ResourceArn: aws.String(identifier), } - output, err := conn.ListTagsForResourceWithContext(ctx, input) + output, err := conn.ListTagsForResource(ctx, input, optFns...) if err != nil { return tftags.New(ctx, nil), err @@ -36,7 +35,7 @@ func listTags(ctx context.Context, conn greengrassiface.GreengrassAPI, identifie // ListTags lists greengrass service tags and set them in Context. // It is called from outside this package. func (p *servicePackage) ListTags(ctx context.Context, meta any, identifier string) error { - tags, err := listTags(ctx, meta.(*conns.AWSClient).GreengrassConn(ctx), identifier) + tags, err := listTags(ctx, meta.(*conns.AWSClient).GreengrassClient(ctx), identifier) if err != nil { return err @@ -49,21 +48,21 @@ func (p *servicePackage) ListTags(ctx context.Context, meta any, identifier stri return nil } -// map[string]*string handling +// map[string]string handling // Tags returns greengrass service tags. -func Tags(tags tftags.KeyValueTags) map[string]*string { - return aws.StringMap(tags.Map()) +func Tags(tags tftags.KeyValueTags) map[string]string { + return tags.Map() } // KeyValueTags creates tftags.KeyValueTags from greengrass service tags. -func KeyValueTags(ctx context.Context, tags map[string]*string) tftags.KeyValueTags { +func KeyValueTags(ctx context.Context, tags map[string]string) tftags.KeyValueTags { return tftags.New(ctx, tags) } // getTagsIn returns greengrass service tags from Context. // nil is returned if there are no input tags. -func getTagsIn(ctx context.Context) map[string]*string { +func getTagsIn(ctx context.Context) map[string]string { if inContext, ok := tftags.FromContext(ctx); ok { if tags := Tags(inContext.TagsIn.UnwrapOrDefault()); len(tags) > 0 { return tags @@ -74,7 +73,7 @@ func getTagsIn(ctx context.Context) map[string]*string { } // setTagsOut sets greengrass service tags in Context. -func setTagsOut(ctx context.Context, tags map[string]*string) { +func setTagsOut(ctx context.Context, tags map[string]string) { if inContext, ok := tftags.FromContext(ctx); ok { inContext.TagsOut = option.Some(KeyValueTags(ctx, tags)) } @@ -83,7 +82,7 @@ func setTagsOut(ctx context.Context, tags map[string]*string) { // updateTags updates greengrass service tags. // The identifier is typically the Amazon Resource Name (ARN), although // it may also be a different identifier depending on the service. -func updateTags(ctx context.Context, conn greengrassiface.GreengrassAPI, identifier string, oldTagsMap, newTagsMap any) error { +func updateTags(ctx context.Context, conn *greengrass.Client, identifier string, oldTagsMap, newTagsMap any, optFns ...func(*greengrass.Options)) error { oldTags := tftags.New(ctx, oldTagsMap) newTags := tftags.New(ctx, newTagsMap) @@ -94,10 +93,10 @@ func updateTags(ctx context.Context, conn greengrassiface.GreengrassAPI, identif if len(removedTags) > 0 { input := &greengrass.UntagResourceInput{ ResourceArn: aws.String(identifier), - TagKeys: aws.StringSlice(removedTags.Keys()), + TagKeys: removedTags.Keys(), } - _, err := conn.UntagResourceWithContext(ctx, input) + _, err := conn.UntagResource(ctx, input, optFns...) if err != nil { return fmt.Errorf("untagging resource (%s): %w", identifier, err) @@ -112,7 +111,7 @@ func updateTags(ctx context.Context, conn greengrassiface.GreengrassAPI, identif Tags: Tags(updatedTags), } - _, err := conn.TagResourceWithContext(ctx, input) + _, err := conn.TagResource(ctx, input, optFns...) if err != nil { return fmt.Errorf("tagging resource (%s): %w", identifier, err) @@ -125,5 +124,5 @@ func updateTags(ctx context.Context, conn greengrassiface.GreengrassAPI, identif // UpdateTags updates greengrass service tags. // It is called from outside this package. func (p *servicePackage) UpdateTags(ctx context.Context, meta any, identifier string, oldTags, newTags any) error { - return updateTags(ctx, meta.(*conns.AWSClient).GreengrassConn(ctx), identifier, oldTags, newTags) + return updateTags(ctx, meta.(*conns.AWSClient).GreengrassClient(ctx), identifier, oldTags, newTags) } diff --git a/internal/service/iot/authorizer.go b/internal/service/iot/authorizer.go index e14e2542e76..94c1053ffc1 100644 --- a/internal/service/iot/authorizer.go +++ b/internal/service/iot/authorizer.go @@ -9,22 +9,28 @@ import ( "log" "github.com/YakDriver/regexache" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/service/iot" - "github.com/hashicorp/aws-sdk-go-base/v2/awsv1shim/v2/tfawserr" + "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/service/iot" + awstypes "github.com/aws/aws-sdk-go-v2/service/iot/types" "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/customdiff" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/retry" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" "github.com/hashicorp/terraform-provider-aws/internal/conns" + "github.com/hashicorp/terraform-provider-aws/internal/enum" + "github.com/hashicorp/terraform-provider-aws/internal/errs" "github.com/hashicorp/terraform-provider-aws/internal/errs/sdkdiag" "github.com/hashicorp/terraform-provider-aws/internal/flex" + tftags "github.com/hashicorp/terraform-provider-aws/internal/tags" "github.com/hashicorp/terraform-provider-aws/internal/tfresource" "github.com/hashicorp/terraform-provider-aws/internal/verify" "github.com/hashicorp/terraform-provider-aws/names" ) -// @SDKResource("aws_iot_authorizer") -func ResourceAuthorizer() *schema.Resource { +// @SDKResource("aws_iot_authorizer", name="Authorizer") +// @Tags(identifierAttribute="arn") +func resourceAuthorizer() *schema.Resource { return &schema.Resource{ CreateWithoutTimeout: resourceAuthorizerCreate, ReadWithoutTimeout: resourceAuthorizerRead, @@ -35,7 +41,10 @@ func ResourceAuthorizer() *schema.Resource { StateContext: schema.ImportStatePassthroughContext, }, - CustomizeDiff: resourceAuthorizerCustomizeDiff, + CustomizeDiff: customdiff.Sequence( + verify.SetTagsDiff, + resourceAuthorizerCustomizeDiff, + ), Schema: map[string]*schema.Schema{ names.AttrARN: { @@ -66,11 +75,13 @@ func ResourceAuthorizer() *schema.Resource { Default: false, }, names.AttrStatus: { - Type: schema.TypeString, - Optional: true, - Default: iot.AuthorizerStatusActive, - ValidateFunc: validation.StringInSlice(iot.AuthorizerStatus_Values(), false), + Type: schema.TypeString, + Optional: true, + Default: awstypes.AuthorizerStatusActive, + ValidateDiagFunc: enum.Validate[awstypes.AuthorizerStatus](), }, + names.AttrTags: tftags.TagsSchema(), + names.AttrTagsAll: tftags.TagsSchemaComputed(), "token_key_name": { Type: schema.TypeString, Optional: true, @@ -91,7 +102,7 @@ func ResourceAuthorizer() *schema.Resource { func resourceAuthorizerCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { var diags diag.Diagnostics - conn := meta.(*conns.AWSClient).IoTConn(ctx) + conn := meta.(*conns.AWSClient).IoTClient(ctx) name := d.Get(names.AttrName).(string) input := &iot.CreateAuthorizerInput{ @@ -99,7 +110,8 @@ func resourceAuthorizerCreate(ctx context.Context, d *schema.ResourceData, meta AuthorizerName: aws.String(name), EnableCachingForHttp: aws.Bool(d.Get("enable_caching_for_http").(bool)), SigningDisabled: aws.Bool(d.Get("signing_disabled").(bool)), - Status: aws.String(d.Get(names.AttrStatus).(string)), + Status: awstypes.AuthorizerStatus((d.Get(names.AttrStatus).(string))), + Tags: getTagsIn(ctx), } if v, ok := d.GetOk("token_key_name"); ok { @@ -107,26 +119,25 @@ func resourceAuthorizerCreate(ctx context.Context, d *schema.ResourceData, meta } if v, ok := d.GetOk("token_signing_public_keys"); ok { - input.TokenSigningPublicKeys = flex.ExpandStringMap(v.(map[string]interface{})) + input.TokenSigningPublicKeys = flex.ExpandStringValueMap(v.(map[string]interface{})) } - log.Printf("[INFO] Creating IoT Authorizer: %s", input) - output, err := conn.CreateAuthorizerWithContext(ctx, input) + output, err := conn.CreateAuthorizer(ctx, input) if err != nil { return sdkdiag.AppendErrorf(diags, "creating IoT Authorizer (%s): %s", name, err) } - d.SetId(aws.StringValue(output.AuthorizerName)) + d.SetId(aws.ToString(output.AuthorizerName)) return append(diags, resourceAuthorizerRead(ctx, d, meta)...) } func resourceAuthorizerRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { var diags diag.Diagnostics - conn := meta.(*conns.AWSClient).IoTConn(ctx) + conn := meta.(*conns.AWSClient).IoTClient(ctx) - authorizer, err := FindAuthorizerByName(ctx, conn, d.Id()) + authorizer, err := findAuthorizerByName(ctx, conn, d.Id()) if !d.IsNewResource() && tfresource.NotFound(err) { log.Printf("[WARN] IoT Authorizer (%s) not found, removing from state", d.Id()) @@ -145,14 +156,14 @@ func resourceAuthorizerRead(ctx context.Context, d *schema.ResourceData, meta in d.Set("signing_disabled", authorizer.SigningDisabled) d.Set(names.AttrStatus, authorizer.Status) d.Set("token_key_name", authorizer.TokenKeyName) - d.Set("token_signing_public_keys", aws.StringValueMap(authorizer.TokenSigningPublicKeys)) + d.Set("token_signing_public_keys", aws.StringMap(authorizer.TokenSigningPublicKeys)) return diags } func resourceAuthorizerUpdate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { var diags diag.Diagnostics - conn := meta.(*conns.AWSClient).IoTConn(ctx) + conn := meta.(*conns.AWSClient).IoTClient(ctx) input := iot.UpdateAuthorizerInput{ AuthorizerName: aws.String(d.Id()), @@ -167,7 +178,7 @@ func resourceAuthorizerUpdate(ctx context.Context, d *schema.ResourceData, meta } if d.HasChange(names.AttrStatus) { - input.Status = aws.String(d.Get(names.AttrStatus).(string)) + input.Status = awstypes.AuthorizerStatus(d.Get(names.AttrStatus).(string)) } if d.HasChange("token_key_name") { @@ -175,11 +186,10 @@ func resourceAuthorizerUpdate(ctx context.Context, d *schema.ResourceData, meta } if d.HasChange("token_signing_public_keys") { - input.TokenSigningPublicKeys = flex.ExpandStringMap(d.Get("token_signing_public_keys").(map[string]interface{})) + input.TokenSigningPublicKeys = flex.ExpandStringValueMap(d.Get("token_signing_public_keys").(map[string]interface{})) } - log.Printf("[INFO] Updating IoT Authorizer: %s", input) - _, err := conn.UpdateAuthorizerWithContext(ctx, &input) + _, err := conn.UpdateAuthorizer(ctx, &input) if err != nil { return sdkdiag.AppendErrorf(diags, "updating IoT Authorizer (%s): %s", d.Id(), err) @@ -190,27 +200,30 @@ func resourceAuthorizerUpdate(ctx context.Context, d *schema.ResourceData, meta func resourceAuthorizerDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { var diags diag.Diagnostics - conn := meta.(*conns.AWSClient).IoTConn(ctx) + conn := meta.(*conns.AWSClient).IoTClient(ctx) // In order to delete an IoT Authorizer, you must set it inactive first. - if d.Get(names.AttrStatus).(string) == iot.AuthorizerStatusActive { - log.Printf("[INFO] Deactivating IoT Authorizer: %s", d.Id()) - _, err := conn.UpdateAuthorizerWithContext(ctx, &iot.UpdateAuthorizerInput{ + if d.Get(names.AttrStatus).(string) == string(awstypes.AuthorizerStatusActive) { + _, err := conn.UpdateAuthorizer(ctx, &iot.UpdateAuthorizerInput{ AuthorizerName: aws.String(d.Id()), - Status: aws.String(iot.AuthorizerStatusInactive), + Status: awstypes.AuthorizerStatusInactive, }) + if errs.IsA[*awstypes.ResourceNotFoundException](err) { + return diags + } + if err != nil { return sdkdiag.AppendErrorf(diags, "deactivating IoT Authorizer (%s): %s", d.Id(), err) } } log.Printf("[INFO] Deleting IoT Authorizer: %s", d.Id()) - _, err := conn.DeleteAuthorizerWithContext(ctx, &iot.DeleteAuthorizerInput{ + _, err := conn.DeleteAuthorizer(ctx, &iot.DeleteAuthorizerInput{ AuthorizerName: aws.String(d.Id()), }) - if tfawserr.ErrCodeEquals(err, iot.ErrCodeResourceNotFoundException) { + if errs.IsA[*awstypes.ResourceNotFoundException](err) { return diags } @@ -233,3 +246,28 @@ func resourceAuthorizerCustomizeDiff(_ context.Context, diff *schema.ResourceDif return nil } + +func findAuthorizerByName(ctx context.Context, conn *iot.Client, name string) (*awstypes.AuthorizerDescription, error) { + input := &iot.DescribeAuthorizerInput{ + AuthorizerName: aws.String(name), + } + + output, err := conn.DescribeAuthorizer(ctx, input) + + if errs.IsA[*awstypes.ResourceNotFoundException](err) { + return nil, &retry.NotFoundError{ + LastError: err, + LastRequest: input, + } + } + + if err != nil { + return nil, err + } + + if output == nil || output.AuthorizerDescription == nil { + return nil, tfresource.NewEmptyResultError(input) + } + + return output.AuthorizerDescription, nil +} diff --git a/internal/service/iot/authorizer_test.go b/internal/service/iot/authorizer_test.go index 64b6ac45f84..19bb2231940 100644 --- a/internal/service/iot/authorizer_test.go +++ b/internal/service/iot/authorizer_test.go @@ -8,7 +8,7 @@ import ( "fmt" "testing" - "github.com/aws/aws-sdk-go/service/iot" + awstypes "github.com/aws/aws-sdk-go-v2/service/iot/types" sdkacctest "github.com/hashicorp/terraform-plugin-testing/helper/acctest" "github.com/hashicorp/terraform-plugin-testing/helper/resource" "github.com/hashicorp/terraform-plugin-testing/terraform" @@ -21,7 +21,7 @@ import ( func TestAccIoTAuthorizer_basic(t *testing.T) { ctx := acctest.Context(t) - var conf iot.AuthorizerDescription + var conf awstypes.AuthorizerDescription rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) resourceName := "aws_iot_authorizer.test" @@ -56,7 +56,7 @@ func TestAccIoTAuthorizer_basic(t *testing.T) { func TestAccIoTAuthorizer_disappears(t *testing.T) { ctx := acctest.Context(t) - var conf iot.AuthorizerDescription + var conf awstypes.AuthorizerDescription rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) resourceName := "aws_iot_authorizer.test" @@ -80,7 +80,7 @@ func TestAccIoTAuthorizer_disappears(t *testing.T) { func TestAccIoTAuthorizer_signingDisabled(t *testing.T) { ctx := acctest.Context(t) - var conf iot.AuthorizerDescription + var conf awstypes.AuthorizerDescription rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) resourceName := "aws_iot_authorizer.test" @@ -113,7 +113,7 @@ func TestAccIoTAuthorizer_signingDisabled(t *testing.T) { func TestAccIoTAuthorizer_update(t *testing.T) { ctx := acctest.Context(t) - var conf iot.AuthorizerDescription + var conf awstypes.AuthorizerDescription rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) resourceName := "aws_iot_authorizer.test" @@ -156,7 +156,53 @@ func TestAccIoTAuthorizer_update(t *testing.T) { }) } -func testAccCheckAuthorizerExists(ctx context.Context, n string, v *iot.AuthorizerDescription) resource.TestCheckFunc { +func TestAccIoTAuthorizer_tags(t *testing.T) { + ctx := acctest.Context(t) + var conf awstypes.AuthorizerDescription + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + resourceName := "aws_iot_authorizer.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.IoTServiceID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckAuthorizerDestroy(ctx), + Steps: []resource.TestStep{ + { + Config: testAccAuthorizerConfig_tags1(rName, acctest.CtKey1, acctest.CtValue1), + Check: resource.ComposeTestCheckFunc( + testAccCheckAuthorizerExists(ctx, resourceName, &conf), + resource.TestCheckResourceAttr(resourceName, acctest.CtTagsPercent, acctest.Ct1), + resource.TestCheckResourceAttr(resourceName, acctest.CtTagsKey1, acctest.CtValue1), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + Config: testAccAuthorizerConfig_tags2(rName, acctest.CtKey1, acctest.CtValue1Updated, acctest.CtKey2, acctest.CtValue2), + Check: resource.ComposeTestCheckFunc( + testAccCheckAuthorizerExists(ctx, resourceName, &conf), + resource.TestCheckResourceAttr(resourceName, acctest.CtTagsPercent, acctest.Ct2), + resource.TestCheckResourceAttr(resourceName, acctest.CtTagsKey1, acctest.CtValue1Updated), + resource.TestCheckResourceAttr(resourceName, acctest.CtTagsKey2, acctest.CtValue2), + ), + }, + { + Config: testAccAuthorizerConfig_tags1(rName, acctest.CtKey2, acctest.CtValue2), + Check: resource.ComposeTestCheckFunc( + testAccCheckAuthorizerExists(ctx, resourceName, &conf), + resource.TestCheckResourceAttr(resourceName, acctest.CtTagsPercent, acctest.Ct1), + resource.TestCheckResourceAttr(resourceName, acctest.CtTagsKey2, acctest.CtValue2), + ), + }, + }, + }) +} + +func testAccCheckAuthorizerExists(ctx context.Context, n string, v *awstypes.AuthorizerDescription) resource.TestCheckFunc { return func(s *terraform.State) error { rs, ok := s.RootModule().Resources[n] if !ok { @@ -167,7 +213,7 @@ func testAccCheckAuthorizerExists(ctx context.Context, n string, v *iot.Authoriz return fmt.Errorf("No IoT Authorizer ID is set") } - conn := acctest.Provider.Meta().(*conns.AWSClient).IoTConn(ctx) + conn := acctest.Provider.Meta().(*conns.AWSClient).IoTClient(ctx) output, err := tfiot.FindAuthorizerByName(ctx, conn, rs.Primary.ID) @@ -183,7 +229,7 @@ func testAccCheckAuthorizerExists(ctx context.Context, n string, v *iot.Authoriz func testAccCheckAuthorizerDestroy(ctx context.Context) resource.TestCheckFunc { return func(s *terraform.State) error { - conn := acctest.Provider.Meta().(*conns.AWSClient).IoTConn(ctx) + conn := acctest.Provider.Meta().(*conns.AWSClient).IoTClient(ctx) for _, rs := range s.RootModule().Resources { if rs.Type != "aws_iot_authorizer" { @@ -235,7 +281,7 @@ resource "aws_lambda_function" "test" { function_name = %[1]q role = aws_iam_role.test.arn handler = "exports.example" - runtime = "nodejs16.x" + runtime = "nodejs20.x" } `, rName) } @@ -282,3 +328,40 @@ resource "aws_iot_authorizer" "test" { } `, rName)) } + +func testAccAuthorizerConfig_tags1(rName, tagKey1, tagValue1 string) string { + return acctest.ConfigCompose(testAccAuthorizerConfig_base(rName), fmt.Sprintf(` +resource "aws_iot_authorizer" "test" { + name = %[1]q + authorizer_function_arn = aws_lambda_function.test.arn + token_key_name = "Token-Header-1" + + token_signing_public_keys = { + Key1 = file("test-fixtures/iot-authorizer-signing-key.pem") + } + + tags = { + %[2]q = %[3]q + } +} +`, rName, tagKey1, tagValue1)) +} + +func testAccAuthorizerConfig_tags2(rName, tagKey1, tagValue1, tagKey2, tagValue2 string) string { + return acctest.ConfigCompose(testAccAuthorizerConfig_base(rName), fmt.Sprintf(` +resource "aws_iot_authorizer" "test" { + name = %[1]q + authorizer_function_arn = aws_lambda_function.test.arn + token_key_name = "Token-Header-1" + + token_signing_public_keys = { + Key1 = file("test-fixtures/iot-authorizer-signing-key.pem") + } + + tags = { + %[2]q = %[3]q + %[4]q = %[5]q + } +} +`, rName, tagKey1, tagValue1, tagKey2, tagValue2)) +} diff --git a/internal/service/iot/billing_group.go b/internal/service/iot/billing_group.go index 5c6c6303f41..beaaa34cfcf 100644 --- a/internal/service/iot/billing_group.go +++ b/internal/service/iot/billing_group.go @@ -8,14 +8,15 @@ import ( "log" "time" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/service/iot" - "github.com/hashicorp/aws-sdk-go-base/v2/awsv1shim/v2/tfawserr" + "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/service/iot" + awstypes "github.com/aws/aws-sdk-go-v2/service/iot/types" "github.com/hashicorp/terraform-plugin-sdk/v2/diag" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/retry" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" "github.com/hashicorp/terraform-provider-aws/internal/conns" + "github.com/hashicorp/terraform-provider-aws/internal/errs" "github.com/hashicorp/terraform-provider-aws/internal/errs/sdkdiag" tftags "github.com/hashicorp/terraform-provider-aws/internal/tags" "github.com/hashicorp/terraform-provider-aws/internal/tfresource" @@ -25,7 +26,7 @@ import ( // @SDKResource("aws_iot_billing_group", name="Billing Group") // @Tags(identifierAttribute="arn") -func ResourceBillingGroup() *schema.Resource { +func resourceBillingGroup() *schema.Resource { return &schema.Resource{ CreateWithoutTimeout: resourceBillingGroupCreate, ReadWithoutTimeout: resourceBillingGroupRead, @@ -86,7 +87,7 @@ func ResourceBillingGroup() *schema.Resource { func resourceBillingGroupCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { var diags diag.Diagnostics - conn := meta.(*conns.AWSClient).IoTConn(ctx) + conn := meta.(*conns.AWSClient).IoTClient(ctx) name := d.Get(names.AttrName).(string) input := &iot.CreateBillingGroupInput{ @@ -98,22 +99,22 @@ func resourceBillingGroupCreate(ctx context.Context, d *schema.ResourceData, met input.BillingGroupProperties = expandBillingGroupProperties(v.([]interface{})[0].(map[string]interface{})) } - output, err := conn.CreateBillingGroupWithContext(ctx, input) + output, err := conn.CreateBillingGroup(ctx, input) if err != nil { return sdkdiag.AppendErrorf(diags, "creating IoT Billing Group (%s): %s", name, err) } - d.SetId(aws.StringValue(output.BillingGroupName)) + d.SetId(aws.ToString(output.BillingGroupName)) return append(diags, resourceBillingGroupRead(ctx, d, meta)...) } func resourceBillingGroupRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { var diags diag.Diagnostics - conn := meta.(*conns.AWSClient).IoTConn(ctx) + conn := meta.(*conns.AWSClient).IoTClient(ctx) - output, err := FindBillingGroupByName(ctx, conn, d.Id()) + output, err := findBillingGroupByName(ctx, conn, d.Id()) if !d.IsNewResource() && tfresource.NotFound(err) { log.Printf("[WARN] IoT Billing Group (%s) not found, removing from state", d.Id()) @@ -149,7 +150,7 @@ func resourceBillingGroupRead(ctx context.Context, d *schema.ResourceData, meta func resourceBillingGroupUpdate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { var diags diag.Diagnostics - conn := meta.(*conns.AWSClient).IoTConn(ctx) + conn := meta.(*conns.AWSClient).IoTClient(ctx) if d.HasChangesExcept(names.AttrTags, names.AttrTagsAll) { input := &iot.UpdateBillingGroupInput{ @@ -160,10 +161,10 @@ func resourceBillingGroupUpdate(ctx context.Context, d *schema.ResourceData, met if v, ok := d.GetOk(names.AttrProperties); ok && len(v.([]interface{})) > 0 && v.([]interface{})[0] != nil { input.BillingGroupProperties = expandBillingGroupProperties(v.([]interface{})[0].(map[string]interface{})) } else { - input.BillingGroupProperties = &iot.BillingGroupProperties{} + input.BillingGroupProperties = &awstypes.BillingGroupProperties{} } - _, err := conn.UpdateBillingGroupWithContext(ctx, input) + _, err := conn.UpdateBillingGroup(ctx, input) if err != nil { return sdkdiag.AppendErrorf(diags, "updating IoT Billing Group (%s): %s", d.Id(), err) @@ -175,14 +176,14 @@ func resourceBillingGroupUpdate(ctx context.Context, d *schema.ResourceData, met func resourceBillingGroupDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { var diags diag.Diagnostics - conn := meta.(*conns.AWSClient).IoTConn(ctx) + conn := meta.(*conns.AWSClient).IoTClient(ctx) log.Printf("[DEBUG] Deleting IoT Billing Group: %s", d.Id()) - _, err := conn.DeleteBillingGroupWithContext(ctx, &iot.DeleteBillingGroupInput{ + _, err := conn.DeleteBillingGroup(ctx, &iot.DeleteBillingGroupInput{ BillingGroupName: aws.String(d.Id()), }) - if tfawserr.ErrCodeEquals(err, iot.ErrCodeResourceNotFoundException) { + if errs.IsA[*awstypes.ResourceNotFoundException](err) { return diags } @@ -193,14 +194,14 @@ func resourceBillingGroupDelete(ctx context.Context, d *schema.ResourceData, met return diags } -func FindBillingGroupByName(ctx context.Context, conn *iot.IoT, name string) (*iot.DescribeBillingGroupOutput, error) { +func findBillingGroupByName(ctx context.Context, conn *iot.Client, name string) (*iot.DescribeBillingGroupOutput, error) { input := &iot.DescribeBillingGroupInput{ BillingGroupName: aws.String(name), } - output, err := conn.DescribeBillingGroupWithContext(ctx, input) + output, err := conn.DescribeBillingGroup(ctx, input) - if tfawserr.ErrCodeEquals(err, iot.ErrCodeResourceNotFoundException) { + if errs.IsA[*awstypes.ResourceNotFoundException](err) { return nil, &retry.NotFoundError{ LastError: err, LastRequest: input, @@ -218,12 +219,12 @@ func FindBillingGroupByName(ctx context.Context, conn *iot.IoT, name string) (*i return output, nil } -func expandBillingGroupProperties(tfMap map[string]interface{}) *iot.BillingGroupProperties { +func expandBillingGroupProperties(tfMap map[string]interface{}) *awstypes.BillingGroupProperties { if tfMap == nil { return nil } - apiObject := &iot.BillingGroupProperties{} + apiObject := &awstypes.BillingGroupProperties{} if v, ok := tfMap[names.AttrDescription].(string); ok && v != "" { apiObject.BillingGroupDescription = aws.String(v) @@ -232,7 +233,7 @@ func expandBillingGroupProperties(tfMap map[string]interface{}) *iot.BillingGrou return apiObject } -func flattenBillingGroupMetadata(apiObject *iot.BillingGroupMetadata) map[string]interface{} { +func flattenBillingGroupMetadata(apiObject *awstypes.BillingGroupMetadata) map[string]interface{} { if apiObject == nil { return nil } @@ -240,13 +241,13 @@ func flattenBillingGroupMetadata(apiObject *iot.BillingGroupMetadata) map[string tfMap := map[string]interface{}{} if v := apiObject.CreationDate; v != nil { - tfMap[names.AttrCreationDate] = aws.TimeValue(v).Format(time.RFC3339) + tfMap[names.AttrCreationDate] = aws.ToTime(v).Format(time.RFC3339) } return tfMap } -func flattenBillingGroupProperties(apiObject *iot.BillingGroupProperties) map[string]interface{} { +func flattenBillingGroupProperties(apiObject *awstypes.BillingGroupProperties) map[string]interface{} { if apiObject == nil { return nil } @@ -254,7 +255,7 @@ func flattenBillingGroupProperties(apiObject *iot.BillingGroupProperties) map[st tfMap := map[string]interface{}{} if v := apiObject.BillingGroupDescription; v != nil { - tfMap[names.AttrDescription] = aws.StringValue(v) + tfMap[names.AttrDescription] = aws.ToString(v) } return tfMap diff --git a/internal/service/iot/billing_group_test.go b/internal/service/iot/billing_group_test.go index 27ed985b773..50f38d7c628 100644 --- a/internal/service/iot/billing_group_test.go +++ b/internal/service/iot/billing_group_test.go @@ -9,7 +9,6 @@ import ( "testing" "github.com/YakDriver/regexache" - "github.com/aws/aws-sdk-go/service/iot" sdkacctest "github.com/hashicorp/terraform-plugin-testing/helper/acctest" "github.com/hashicorp/terraform-plugin-testing/helper/resource" "github.com/hashicorp/terraform-plugin-testing/terraform" @@ -22,7 +21,6 @@ import ( func TestAccIoTBillingGroup_basic(t *testing.T) { ctx := acctest.Context(t) - var v iot.DescribeBillingGroupOutput rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) resourceName := "aws_iot_billing_group.test" @@ -35,7 +33,7 @@ func TestAccIoTBillingGroup_basic(t *testing.T) { { Config: testAccBillingGroupConfig_basic(rName), Check: resource.ComposeAggregateTestCheckFunc( - testAccCheckBillingGroupExists(ctx, resourceName, &v), + testAccCheckBillingGroupExists(ctx, resourceName), acctest.MatchResourceAttrRegionalARN(resourceName, names.AttrARN, "iot", regexache.MustCompile(fmt.Sprintf("billinggroup/%s$", rName))), resource.TestCheckResourceAttr(resourceName, "metadata.#", acctest.Ct1), resource.TestCheckResourceAttrSet(resourceName, "metadata.0.creation_date"), @@ -56,7 +54,6 @@ func TestAccIoTBillingGroup_basic(t *testing.T) { func TestAccIoTBillingGroup_disappears(t *testing.T) { ctx := acctest.Context(t) - var v iot.DescribeBillingGroupOutput rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) resourceName := "aws_iot_billing_group.test" @@ -69,7 +66,7 @@ func TestAccIoTBillingGroup_disappears(t *testing.T) { { Config: testAccBillingGroupConfig_basic(rName), Check: resource.ComposeTestCheckFunc( - testAccCheckBillingGroupExists(ctx, resourceName, &v), + testAccCheckBillingGroupExists(ctx, resourceName), acctest.CheckResourceDisappears(ctx, acctest.Provider, tfiot.ResourceBillingGroup(), resourceName), ), ExpectNonEmptyPlan: true, @@ -80,7 +77,6 @@ func TestAccIoTBillingGroup_disappears(t *testing.T) { func TestAccIoTBillingGroup_tags(t *testing.T) { ctx := acctest.Context(t) - var v iot.DescribeBillingGroupOutput rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) resourceName := "aws_iot_billing_group.test" @@ -93,7 +89,7 @@ func TestAccIoTBillingGroup_tags(t *testing.T) { { Config: testAccBillingGroupConfig_tags1(rName, acctest.CtKey1, acctest.CtValue1), Check: resource.ComposeTestCheckFunc( - testAccCheckBillingGroupExists(ctx, resourceName, &v), + testAccCheckBillingGroupExists(ctx, resourceName), resource.TestCheckResourceAttr(resourceName, acctest.CtTagsPercent, acctest.Ct1), resource.TestCheckResourceAttr(resourceName, acctest.CtTagsKey1, acctest.CtValue1), ), @@ -106,7 +102,7 @@ func TestAccIoTBillingGroup_tags(t *testing.T) { { Config: testAccBillingGroupConfig_tags2(rName, acctest.CtKey1, acctest.CtValue1Updated, acctest.CtKey2, acctest.CtValue2), Check: resource.ComposeTestCheckFunc( - testAccCheckBillingGroupExists(ctx, resourceName, &v), + testAccCheckBillingGroupExists(ctx, resourceName), resource.TestCheckResourceAttr(resourceName, acctest.CtTagsPercent, acctest.Ct2), resource.TestCheckResourceAttr(resourceName, acctest.CtTagsKey1, acctest.CtValue1Updated), resource.TestCheckResourceAttr(resourceName, acctest.CtTagsKey2, acctest.CtValue2), @@ -115,7 +111,7 @@ func TestAccIoTBillingGroup_tags(t *testing.T) { { Config: testAccBillingGroupConfig_tags1(rName, acctest.CtKey2, acctest.CtValue2), Check: resource.ComposeTestCheckFunc( - testAccCheckBillingGroupExists(ctx, resourceName, &v), + testAccCheckBillingGroupExists(ctx, resourceName), resource.TestCheckResourceAttr(resourceName, acctest.CtTagsPercent, acctest.Ct1), resource.TestCheckResourceAttr(resourceName, acctest.CtTagsKey2, acctest.CtValue2), ), @@ -126,7 +122,6 @@ func TestAccIoTBillingGroup_tags(t *testing.T) { func TestAccIoTBillingGroup_properties(t *testing.T) { ctx := acctest.Context(t) - var v iot.DescribeBillingGroupOutput rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) resourceName := "aws_iot_billing_group.test" @@ -139,7 +134,7 @@ func TestAccIoTBillingGroup_properties(t *testing.T) { { Config: testAccBillingGroupConfig_properties(rName), Check: resource.ComposeTestCheckFunc( - testAccCheckBillingGroupExists(ctx, resourceName, &v), + testAccCheckBillingGroupExists(ctx, resourceName), resource.TestCheckResourceAttr(resourceName, "properties.#", acctest.Ct1), resource.TestCheckResourceAttr(resourceName, "properties.0.description", "test description 1"), resource.TestCheckResourceAttr(resourceName, names.AttrVersion, acctest.Ct1), @@ -153,7 +148,7 @@ func TestAccIoTBillingGroup_properties(t *testing.T) { { Config: testAccBillingGroupConfig_propertiesUpdated(rName), Check: resource.ComposeTestCheckFunc( - testAccCheckBillingGroupExists(ctx, resourceName, &v), + testAccCheckBillingGroupExists(ctx, resourceName), resource.TestCheckResourceAttr(resourceName, "properties.#", acctest.Ct1), resource.TestCheckResourceAttr(resourceName, "properties.0.description", "test description 2"), resource.TestCheckResourceAttr(resourceName, names.AttrVersion, acctest.Ct2), @@ -163,30 +158,24 @@ func TestAccIoTBillingGroup_properties(t *testing.T) { }) } -func testAccCheckBillingGroupExists(ctx context.Context, n string, v *iot.DescribeBillingGroupOutput) resource.TestCheckFunc { +func testAccCheckBillingGroupExists(ctx context.Context, n string) resource.TestCheckFunc { return func(s *terraform.State) error { rs, ok := s.RootModule().Resources[n] if !ok { return fmt.Errorf("Not found: %s", n) } - conn := acctest.Provider.Meta().(*conns.AWSClient).IoTConn(ctx) + conn := acctest.Provider.Meta().(*conns.AWSClient).IoTClient(ctx) - output, err := tfiot.FindBillingGroupByName(ctx, conn, rs.Primary.ID) + _, err := tfiot.FindBillingGroupByName(ctx, conn, rs.Primary.ID) - if err != nil { - return err - } - - *v = *output - - return nil + return err } } func testAccCheckBillingGroupDestroy(ctx context.Context) resource.TestCheckFunc { return func(s *terraform.State) error { - conn := acctest.Provider.Meta().(*conns.AWSClient).IoTConn(ctx) + conn := acctest.Provider.Meta().(*conns.AWSClient).IoTClient(ctx) for _, rs := range s.RootModule().Resources { if rs.Type != "aws_iot_billing_group" { diff --git a/internal/service/iot/ca_certificate.go b/internal/service/iot/ca_certificate.go index 43bb4bd6227..cc8ff2c2d74 100644 --- a/internal/service/iot/ca_certificate.go +++ b/internal/service/iot/ca_certificate.go @@ -10,15 +10,17 @@ import ( "time" "github.com/YakDriver/regexache" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/service/iot" - "github.com/hashicorp/aws-sdk-go-base/v2/awsv1shim/v2/tfawserr" + "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/service/iot" + awstypes "github.com/aws/aws-sdk-go-v2/service/iot/types" "github.com/hashicorp/terraform-plugin-sdk/v2/diag" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/customdiff" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/retry" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" "github.com/hashicorp/terraform-provider-aws/internal/conns" + "github.com/hashicorp/terraform-provider-aws/internal/enum" + "github.com/hashicorp/terraform-provider-aws/internal/errs" "github.com/hashicorp/terraform-provider-aws/internal/errs/sdkdiag" tftags "github.com/hashicorp/terraform-provider-aws/internal/tags" "github.com/hashicorp/terraform-provider-aws/internal/tfresource" @@ -28,7 +30,7 @@ import ( // @SDKResource("aws_iot_ca_certificate", name="CA Certificate") // @Tags(identifierAttribute="arn") -func ResourceCACertificate() *schema.Resource { +func resourceCACertificate() *schema.Resource { return &schema.Resource{ CreateWithoutTimeout: resourceCACertificateCreate, ReadWithoutTimeout: resourceCACertificateRead, @@ -55,11 +57,11 @@ func ResourceCACertificate() *schema.Resource { Sensitive: true, }, "certificate_mode": { - Type: schema.TypeString, - Optional: true, - ForceNew: true, - Default: iot.CertificateModeDefault, - ValidateFunc: validation.StringInSlice(iot.CertificateMode_Values(), false), + Type: schema.TypeString, + Optional: true, + ForceNew: true, + Default: awstypes.CertificateModeDefault, + ValidateDiagFunc: enum.Validate[awstypes.CertificateMode](), }, "customer_version": { Type: schema.TypeInt, @@ -124,7 +126,7 @@ func ResourceCACertificate() *schema.Resource { CustomizeDiff: customdiff.All( func(_ context.Context, diff *schema.ResourceDiff, meta interface{}) error { - if mode := diff.Get("certificate_mode").(string); mode == iot.CertificateModeDefault { + if mode := diff.Get("certificate_mode").(string); mode == string(awstypes.CertificateModeDefault) { if v := diff.GetRawConfig().GetAttr("verification_certificate_pem"); v.IsKnown() { if v.IsNull() || v.AsString() == "" { return fmt.Errorf(`"verification_certificate_pem" is required when certificate_mode is %q`, mode) @@ -141,13 +143,13 @@ func ResourceCACertificate() *schema.Resource { func resourceCACertificateCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { var diags diag.Diagnostics - conn := meta.(*conns.AWSClient).IoTConn(ctx) + conn := meta.(*conns.AWSClient).IoTClient(ctx) input := &iot.RegisterCACertificateInput{ - AllowAutoRegistration: aws.Bool(d.Get("allow_auto_registration").(bool)), + AllowAutoRegistration: d.Get("allow_auto_registration").(bool), CaCertificate: aws.String(d.Get("ca_certificate_pem").(string)), - CertificateMode: aws.String(d.Get("certificate_mode").(string)), - SetAsActive: aws.Bool(d.Get("active").(bool)), + CertificateMode: awstypes.CertificateMode(d.Get("certificate_mode").(string)), + SetAsActive: d.Get("active").(bool), Tags: getTagsIn(ctx), } @@ -159,26 +161,24 @@ func resourceCACertificateCreate(ctx context.Context, d *schema.ResourceData, me input.VerificationCertificate = aws.String(v.(string)) } - outputRaw, err := tfresource.RetryWhenAWSErrMessageContains(ctx, propagationTimeout, - func() (interface{}, error) { - return conn.RegisterCACertificateWithContext(ctx, input) - }, - iot.ErrCodeInvalidRequestException, "included in the RegistrationConfig does not exist or cannot be assumed by AWS IoT") + outputRaw, err := tfresource.RetryWhenIsA[*awstypes.InvalidRequestException](ctx, propagationTimeout, func() (interface{}, error) { + return conn.RegisterCACertificate(ctx, input) + }) if err != nil { return sdkdiag.AppendErrorf(diags, "registering IoT CA Certificate: %s", err) } - d.SetId(aws.StringValue(outputRaw.(*iot.RegisterCACertificateOutput).CertificateId)) + d.SetId(aws.ToString(outputRaw.(*iot.RegisterCACertificateOutput).CertificateId)) return append(diags, resourceCACertificateRead(ctx, d, meta)...) } func resourceCACertificateRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { var diags diag.Diagnostics - conn := meta.(*conns.AWSClient).IoTConn(ctx) + conn := meta.(*conns.AWSClient).IoTClient(ctx) - output, err := FindCACertificateByID(ctx, conn, d.Id()) + output, err := findCACertificateByID(ctx, conn, d.Id()) if !d.IsNewResource() && tfresource.NotFound(err) { log.Printf("[WARN] IoT CA Certificate (%s) not found, removing from state", d.Id()) @@ -191,8 +191,8 @@ func resourceCACertificateRead(ctx context.Context, d *schema.ResourceData, meta } certificateDescription := output.CertificateDescription - d.Set("active", aws.StringValue(certificateDescription.Status) == iot.CACertificateStatusActive) - d.Set("allow_auto_registration", aws.StringValue(certificateDescription.AutoRegistrationStatus) == iot.AutoRegistrationStatusEnable) + d.Set("active", string(certificateDescription.Status) == string(awstypes.CACertificateStatusActive)) + d.Set("allow_auto_registration", string(certificateDescription.AutoRegistrationStatus) == string(awstypes.AutoRegistrationStatusEnable)) d.Set(names.AttrARN, certificateDescription.CertificateArn) d.Set("ca_certificate_pem", certificateDescription.CertificatePem) d.Set("certificate_mode", certificateDescription.CertificateMode) @@ -218,7 +218,7 @@ func resourceCACertificateRead(ctx context.Context, d *schema.ResourceData, meta func resourceCACertificateUpdate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { var diags diag.Diagnostics - conn := meta.(*conns.AWSClient).IoTConn(ctx) + conn := meta.(*conns.AWSClient).IoTClient(ctx) if d.HasChangesExcept(names.AttrTags, names.AttrTagsAll) { input := &iot.UpdateCACertificateInput{ @@ -226,15 +226,15 @@ func resourceCACertificateUpdate(ctx context.Context, d *schema.ResourceData, me } if d.Get("active").(bool) { - input.NewStatus = aws.String(iot.CACertificateStatusActive) + input.NewStatus = awstypes.CACertificateStatusActive } else { - input.NewStatus = aws.String(iot.CACertificateStatusInactive) + input.NewStatus = awstypes.CACertificateStatusInactive } if d.Get("allow_auto_registration").(bool) { - input.NewAutoRegistrationStatus = aws.String(iot.AutoRegistrationStatusEnable) + input.NewAutoRegistrationStatus = awstypes.AutoRegistrationStatusEnable } else { - input.NewAutoRegistrationStatus = aws.String(iot.AutoRegistrationStatusDisable) + input.NewAutoRegistrationStatus = awstypes.AutoRegistrationStatusDisable } if d.HasChange("registration_config") { @@ -243,11 +243,9 @@ func resourceCACertificateUpdate(ctx context.Context, d *schema.ResourceData, me } } - _, err := tfresource.RetryWhenAWSErrMessageContains(ctx, propagationTimeout, - func() (interface{}, error) { - return conn.UpdateCACertificateWithContext(ctx, input) - }, - iot.ErrCodeInvalidRequestException, "included in the RegistrationConfig does not exist or cannot be assumed by AWS IoT") + _, err := tfresource.RetryWhenIsA[*awstypes.InvalidRequestException](ctx, propagationTimeout, func() (interface{}, error) { + return conn.UpdateCACertificate(ctx, input) + }) if err != nil { return sdkdiag.AppendErrorf(diags, "updating IoT CA Certificate (%s): %s", d.Id(), err) @@ -259,16 +257,15 @@ func resourceCACertificateUpdate(ctx context.Context, d *schema.ResourceData, me func resourceCACertificateDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { var diags diag.Diagnostics - conn := meta.(*conns.AWSClient).IoTConn(ctx) + conn := meta.(*conns.AWSClient).IoTClient(ctx) if d.Get("active").(bool) { - log.Printf("[DEBUG] Disabling IoT CA Certificate: %s", d.Id()) - _, err := conn.UpdateCACertificateWithContext(ctx, &iot.UpdateCACertificateInput{ + _, err := conn.UpdateCACertificate(ctx, &iot.UpdateCACertificateInput{ CertificateId: aws.String(d.Id()), - NewStatus: aws.String(iot.CACertificateStatusInactive), + NewStatus: awstypes.CACertificateStatusInactive, }) - if tfawserr.ErrCodeEquals(err, iot.ErrCodeResourceNotFoundException) { + if errs.IsA[*awstypes.ResourceNotFoundException](err) { return diags } @@ -278,11 +275,11 @@ func resourceCACertificateDelete(ctx context.Context, d *schema.ResourceData, me } log.Printf("[DEBUG] Deleting IoT CA Certificate: %s", d.Id()) - _, err := conn.DeleteCACertificateWithContext(ctx, &iot.DeleteCACertificateInput{ + _, err := conn.DeleteCACertificate(ctx, &iot.DeleteCACertificateInput{ CertificateId: aws.String(d.Id()), }) - if tfawserr.ErrCodeEquals(err, iot.ErrCodeResourceNotFoundException) { + if errs.IsA[*awstypes.ResourceNotFoundException](err) { return diags } @@ -293,14 +290,14 @@ func resourceCACertificateDelete(ctx context.Context, d *schema.ResourceData, me return diags } -func FindCACertificateByID(ctx context.Context, conn *iot.IoT, id string) (*iot.DescribeCACertificateOutput, error) { +func findCACertificateByID(ctx context.Context, conn *iot.Client, id string) (*iot.DescribeCACertificateOutput, error) { input := &iot.DescribeCACertificateInput{ CertificateId: aws.String(id), } - output, err := conn.DescribeCACertificateWithContext(ctx, input) + output, err := conn.DescribeCACertificate(ctx, input) - if tfawserr.ErrCodeEquals(err, iot.ErrCodeResourceNotFoundException) { + if errs.IsA[*awstypes.ResourceNotFoundException](err) { return nil, &retry.NotFoundError{ LastError: err, LastRequest: input, @@ -318,12 +315,12 @@ func FindCACertificateByID(ctx context.Context, conn *iot.IoT, id string) (*iot. return output, nil } -func expandRegistrationConfig(tfMap map[string]interface{}) *iot.RegistrationConfig { +func expandRegistrationConfig(tfMap map[string]interface{}) *awstypes.RegistrationConfig { if tfMap == nil { return nil } - apiObject := &iot.RegistrationConfig{} + apiObject := &awstypes.RegistrationConfig{} if v, ok := tfMap[names.AttrRoleARN].(string); ok && v != "" { apiObject.RoleArn = aws.String(v) @@ -340,7 +337,7 @@ func expandRegistrationConfig(tfMap map[string]interface{}) *iot.RegistrationCon return apiObject } -func flattenRegistrationConfig(apiObject *iot.RegistrationConfig) map[string]interface{} { +func flattenRegistrationConfig(apiObject *awstypes.RegistrationConfig) map[string]interface{} { if apiObject == nil { return nil } @@ -348,21 +345,21 @@ func flattenRegistrationConfig(apiObject *iot.RegistrationConfig) map[string]int tfMap := map[string]interface{}{} if v := apiObject.RoleArn; v != nil { - tfMap[names.AttrRoleARN] = aws.StringValue(v) + tfMap[names.AttrRoleARN] = aws.ToString(v) } if v := apiObject.TemplateBody; v != nil { - tfMap["template_body"] = aws.StringValue(v) + tfMap["template_body"] = aws.ToString(v) } if v := apiObject.TemplateName; v != nil { - tfMap["template_name"] = aws.StringValue(v) + tfMap["template_name"] = aws.ToString(v) } return tfMap } -func flattenCertificateValidity(apiObject *iot.CertificateValidity) map[string]interface{} { +func flattenCertificateValidity(apiObject *awstypes.CertificateValidity) map[string]interface{} { if apiObject == nil { return nil } @@ -370,11 +367,11 @@ func flattenCertificateValidity(apiObject *iot.CertificateValidity) map[string]i tfMap := map[string]interface{}{} if v := apiObject.NotAfter; v != nil { - tfMap["not_after"] = aws.TimeValue(v).Format(time.RFC3339) + tfMap["not_after"] = aws.ToTime(v).Format(time.RFC3339) } if v := apiObject.NotBefore; v != nil { - tfMap["not_before"] = aws.TimeValue(v).Format(time.RFC3339) + tfMap["not_before"] = aws.ToTime(v).Format(time.RFC3339) } return tfMap diff --git a/internal/service/iot/ca_certificate_test.go b/internal/service/iot/ca_certificate_test.go index 819571e57cc..d1f9e9b60cc 100644 --- a/internal/service/iot/ca_certificate_test.go +++ b/internal/service/iot/ca_certificate_test.go @@ -200,7 +200,7 @@ func testAccCheckCACertificateExists(ctx context.Context, n string) resource.Tes return fmt.Errorf("Not found: %s", n) } - conn := acctest.Provider.Meta().(*conns.AWSClient).IoTConn(ctx) + conn := acctest.Provider.Meta().(*conns.AWSClient).IoTClient(ctx) _, err := tfiot.FindCACertificateByID(ctx, conn, rs.Primary.ID) @@ -210,7 +210,7 @@ func testAccCheckCACertificateExists(ctx context.Context, n string) resource.Tes func testAccCheckCACertificateDestroy(ctx context.Context) resource.TestCheckFunc { return func(s *terraform.State) error { - conn := acctest.Provider.Meta().(*conns.AWSClient).IoTConn(ctx) + conn := acctest.Provider.Meta().(*conns.AWSClient).IoTClient(ctx) for _, rs := range s.RootModule().Resources { if rs.Type != "aws_iot_ca_certificate" { diff --git a/internal/service/iot/certificate.go b/internal/service/iot/certificate.go index 825f67422d3..23ae37e39ad 100644 --- a/internal/service/iot/certificate.go +++ b/internal/service/iot/certificate.go @@ -7,20 +7,21 @@ import ( "context" "log" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/service/iot" - "github.com/hashicorp/aws-sdk-go-base/v2/awsv1shim/v2/tfawserr" + "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/service/iot" + awstypes "github.com/aws/aws-sdk-go-v2/service/iot/types" "github.com/hashicorp/terraform-plugin-sdk/v2/diag" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/retry" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/terraform-provider-aws/internal/conns" + "github.com/hashicorp/terraform-provider-aws/internal/errs" "github.com/hashicorp/terraform-provider-aws/internal/errs/sdkdiag" "github.com/hashicorp/terraform-provider-aws/internal/tfresource" "github.com/hashicorp/terraform-provider-aws/names" ) // @SDKResource("aws_iot_certificate", name="Certificate) -func ResourceCertificate() *schema.Resource { +func resourceCertificate() *schema.Resource { return &schema.Resource{ CreateWithoutTimeout: resourceCertificateCreate, ReadWithoutTimeout: resourceCertificateRead, @@ -74,12 +75,12 @@ func ResourceCertificate() *schema.Resource { func resourceCertificateCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { var diags diag.Diagnostics - conn := meta.(*conns.AWSClient).IoTConn(ctx) + conn := meta.(*conns.AWSClient).IoTClient(ctx) active := d.Get("active").(bool) - status := iot.CertificateStatusInactive + status := awstypes.CertificateStatusInactive if active { - status = iot.CertificateStatusActive + status = awstypes.CertificateStatusActive } vCert, okCert := d.GetOk("certificate_pem") vCA, okCA := d.GetOk("ca_pem") @@ -87,55 +88,55 @@ func resourceCertificateCreate(ctx context.Context, d *schema.ResourceData, meta if vCSR, okCSR := d.GetOk("csr"); okCSR { input := &iot.CreateCertificateFromCsrInput{ CertificateSigningRequest: aws.String(vCSR.(string)), - SetAsActive: aws.Bool(active), + SetAsActive: active, } - output, err := conn.CreateCertificateFromCsrWithContext(ctx, input) + output, err := conn.CreateCertificateFromCsr(ctx, input) if err != nil { return sdkdiag.AppendErrorf(diags, "creating IoT Certificate from CSR: %s", err) } - d.SetId(aws.StringValue(output.CertificateId)) + d.SetId(aws.ToString(output.CertificateId)) } else if okCert && okCA { input := &iot.RegisterCertificateInput{ CaCertificatePem: aws.String(vCA.(string)), CertificatePem: aws.String(vCert.(string)), - Status: aws.String(status), + Status: status, } - output, err := conn.RegisterCertificateWithContext(ctx, input) + output, err := conn.RegisterCertificate(ctx, input) if err != nil { return sdkdiag.AppendErrorf(diags, "registering IoT Certificate with CA: %s", err) } - d.SetId(aws.StringValue(output.CertificateId)) + d.SetId(aws.ToString(output.CertificateId)) } else if okCert { input := &iot.RegisterCertificateWithoutCAInput{ CertificatePem: aws.String(vCert.(string)), - Status: aws.String(status), + Status: status, } - output, err := conn.RegisterCertificateWithoutCAWithContext(ctx, input) + output, err := conn.RegisterCertificateWithoutCA(ctx, input) if err != nil { return sdkdiag.AppendErrorf(diags, "registering IoT Certificate without CA: %s", err) } - d.SetId(aws.StringValue(output.CertificateId)) + d.SetId(aws.ToString(output.CertificateId)) } else { input := &iot.CreateKeysAndCertificateInput{ - SetAsActive: aws.Bool(active), + SetAsActive: active, } - output, err := conn.CreateKeysAndCertificateWithContext(ctx, input) + output, err := conn.CreateKeysAndCertificate(ctx, input) if err != nil { return sdkdiag.AppendErrorf(diags, "creating IoT Certificate: %s", err) } - d.SetId(aws.StringValue(output.CertificateId)) + d.SetId(aws.ToString(output.CertificateId)) d.Set(names.AttrPrivateKey, output.KeyPair.PrivateKey) d.Set(names.AttrPublicKey, output.KeyPair.PublicKey) } @@ -145,9 +146,9 @@ func resourceCertificateCreate(ctx context.Context, d *schema.ResourceData, meta func resourceCertificateRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { var diags diag.Diagnostics - conn := meta.(*conns.AWSClient).IoTConn(ctx) + conn := meta.(*conns.AWSClient).IoTClient(ctx) - output, err := FindCertificateByID(ctx, conn, d.Id()) + output, err := findCertificateByID(ctx, conn, d.Id()) if !d.IsNewResource() && tfresource.NotFound(err) { log.Printf("[WARN] IoT Certificate (%s) not found, removing from state", d.Id()) @@ -160,7 +161,7 @@ func resourceCertificateRead(ctx context.Context, d *schema.ResourceData, meta i } certificateDescription := output.CertificateDescription - d.Set("active", aws.StringValue(certificateDescription.Status) == iot.CertificateStatusActive) + d.Set("active", certificateDescription.Status == awstypes.CertificateStatusActive) d.Set(names.AttrARN, certificateDescription.CertificateArn) d.Set("ca_certificate_id", certificateDescription.CaCertificateId) d.Set("certificate_pem", certificateDescription.CertificatePem) @@ -170,18 +171,18 @@ func resourceCertificateRead(ctx context.Context, d *schema.ResourceData, meta i func resourceCertificateUpdate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { var diags diag.Diagnostics - conn := meta.(*conns.AWSClient).IoTConn(ctx) + conn := meta.(*conns.AWSClient).IoTClient(ctx) - status := iot.CertificateStatusInactive + status := awstypes.CertificateStatusInactive if d.Get("active").(bool) { - status = iot.CertificateStatusActive + status = awstypes.CertificateStatusActive } input := &iot.UpdateCertificateInput{ CertificateId: aws.String(d.Id()), - NewStatus: aws.String(status), + NewStatus: status, } - _, err := conn.UpdateCertificateWithContext(ctx, input) + _, err := conn.UpdateCertificate(ctx, input) if err != nil { return sdkdiag.AppendErrorf(diags, "updating IoT Certificate (%s): %s", d.Id(), err) @@ -192,16 +193,15 @@ func resourceCertificateUpdate(ctx context.Context, d *schema.ResourceData, meta func resourceCertificateDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { var diags diag.Diagnostics - conn := meta.(*conns.AWSClient).IoTConn(ctx) + conn := meta.(*conns.AWSClient).IoTClient(ctx) if d.Get("active").(bool) { - log.Printf("[DEBUG] Disabling IoT Certificate: %s", d.Id()) - _, err := conn.UpdateCertificateWithContext(ctx, &iot.UpdateCertificateInput{ + _, err := conn.UpdateCertificate(ctx, &iot.UpdateCertificateInput{ CertificateId: aws.String(d.Id()), - NewStatus: aws.String(iot.CertificateStatusInactive), + NewStatus: awstypes.CertificateStatusInactive, }) - if tfawserr.ErrCodeEquals(err, iot.ErrCodeResourceNotFoundException) { + if errs.IsA[*awstypes.ResourceNotFoundException](err) { return diags } @@ -211,11 +211,11 @@ func resourceCertificateDelete(ctx context.Context, d *schema.ResourceData, meta } log.Printf("[DEBUG] Deleting IoT Certificate: %s", d.Id()) - _, err := conn.DeleteCertificateWithContext(ctx, &iot.DeleteCertificateInput{ + _, err := conn.DeleteCertificate(ctx, &iot.DeleteCertificateInput{ CertificateId: aws.String(d.Id()), }) - if tfawserr.ErrCodeEquals(err, iot.ErrCodeResourceNotFoundException) { + if errs.IsA[*awstypes.ResourceNotFoundException](err) { return diags } @@ -226,14 +226,14 @@ func resourceCertificateDelete(ctx context.Context, d *schema.ResourceData, meta return diags } -func FindCertificateByID(ctx context.Context, conn *iot.IoT, id string) (*iot.DescribeCertificateOutput, error) { +func findCertificateByID(ctx context.Context, conn *iot.Client, id string) (*iot.DescribeCertificateOutput, error) { input := &iot.DescribeCertificateInput{ CertificateId: aws.String(id), } - output, err := conn.DescribeCertificateWithContext(ctx, input) + output, err := conn.DescribeCertificate(ctx, input) - if tfawserr.ErrCodeEquals(err, iot.ErrCodeResourceNotFoundException) { + if errs.IsA[*awstypes.ResourceNotFoundException](err) { return nil, &retry.NotFoundError{ LastError: err, LastRequest: input, diff --git a/internal/service/iot/certificate_test.go b/internal/service/iot/certificate_test.go index c009c569d42..b58383bb8d9 100644 --- a/internal/service/iot/certificate_test.go +++ b/internal/service/iot/certificate_test.go @@ -111,7 +111,7 @@ func testAccCheckCertificateExists(ctx context.Context, n string) resource.TestC return fmt.Errorf("Not found: %s", n) } - conn := acctest.Provider.Meta().(*conns.AWSClient).IoTConn(ctx) + conn := acctest.Provider.Meta().(*conns.AWSClient).IoTClient(ctx) _, err := tfiot.FindCertificateByID(ctx, conn, rs.Primary.ID) @@ -121,7 +121,7 @@ func testAccCheckCertificateExists(ctx context.Context, n string) resource.TestC func testAccCheckCertificateDestroy(ctx context.Context) resource.TestCheckFunc { return func(s *terraform.State) error { - conn := acctest.Provider.Meta().(*conns.AWSClient).IoTConn(ctx) + conn := acctest.Provider.Meta().(*conns.AWSClient).IoTClient(ctx) for _, rs := range s.RootModule().Resources { if rs.Type != "aws_iot_certificate" { diff --git a/internal/service/iot/consts.go b/internal/service/iot/consts.go index 57bbf5672b7..267822dbfd6 100644 --- a/internal/service/iot/consts.go +++ b/internal/service/iot/consts.go @@ -8,5 +8,6 @@ import ( ) const ( - propagationTimeout = 2 * time.Minute + propagationTimeout = 2 * time.Minute + deprecatePropagationTimeout = 6 * time.Minute ) diff --git a/internal/service/iot/domain_configuration.go b/internal/service/iot/domain_configuration.go index 57119844a48..db1c60f4ed8 100644 --- a/internal/service/iot/domain_configuration.go +++ b/internal/service/iot/domain_configuration.go @@ -7,14 +7,15 @@ import ( "context" "log" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/service/iot" - "github.com/hashicorp/aws-sdk-go-base/v2/awsv1shim/v2/tfawserr" + "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/service/iot" + awstypes "github.com/aws/aws-sdk-go-v2/service/iot/types" "github.com/hashicorp/terraform-plugin-sdk/v2/diag" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/retry" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" "github.com/hashicorp/terraform-provider-aws/internal/conns" + "github.com/hashicorp/terraform-provider-aws/internal/enum" + "github.com/hashicorp/terraform-provider-aws/internal/errs" "github.com/hashicorp/terraform-provider-aws/internal/errs/sdkdiag" "github.com/hashicorp/terraform-provider-aws/internal/flex" tfslices "github.com/hashicorp/terraform-provider-aws/internal/slices" @@ -26,7 +27,7 @@ import ( // @SDKResource("aws_iot_domain_configuration", name="Domain Configuration") // @Tags(identifierAttribute="arn") -func ResourceDomainConfiguration() *schema.Resource { +func resourceDomainConfiguration() *schema.Resource { return &schema.Resource{ CreateWithoutTimeout: resourceDomainConfigurationCreate, ReadWithoutTimeout: resourceDomainConfigurationRead, @@ -85,17 +86,17 @@ func ResourceDomainConfiguration() *schema.Resource { }, }, "service_type": { - Type: schema.TypeString, - Optional: true, - ForceNew: true, - Default: iot.ServiceTypeData, - ValidateFunc: validation.StringInSlice(iot.ServiceType_Values(), false), + Type: schema.TypeString, + Optional: true, + ForceNew: true, + Default: awstypes.ServiceTypeData, + ValidateDiagFunc: enum.Validate[awstypes.ServiceType](), }, names.AttrStatus: { - Type: schema.TypeString, - Optional: true, - Default: iot.DomainConfigurationStatusEnabled, - ValidateFunc: validation.StringInSlice(iot.DomainConfigurationStatus_Values(), false), + Type: schema.TypeString, + Optional: true, + Default: awstypes.DomainConfigurationStatusEnabled, + ValidateDiagFunc: enum.Validate[awstypes.DomainConfigurationStatus](), }, names.AttrTags: tftags.TagsSchema(), names.AttrTagsAll: tftags.TagsSchemaComputed(), @@ -126,7 +127,7 @@ func ResourceDomainConfiguration() *schema.Resource { func resourceDomainConfigurationCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { var diags diag.Diagnostics - conn := meta.(*conns.AWSClient).IoTConn(ctx) + conn := meta.(*conns.AWSClient).IoTClient(ctx) name := d.Get(names.AttrName).(string) input := &iot.CreateDomainConfigurationInput{ @@ -143,11 +144,11 @@ func resourceDomainConfigurationCreate(ctx context.Context, d *schema.ResourceDa } if v, ok := d.GetOk("server_certificate_arns"); ok && v.(*schema.Set).Len() > 0 { - input.ServerCertificateArns = flex.ExpandStringSet(v.(*schema.Set)) + input.ServerCertificateArns = flex.ExpandStringValueSet(v.(*schema.Set)) } if v, ok := d.GetOk("service_type"); ok { - input.ServiceType = aws.String(v.(string)) + input.ServiceType = awstypes.ServiceType(v.(string)) } if v, ok := d.GetOk("tls_config"); ok && len(v.([]interface{})) > 0 && v.([]interface{})[0] != nil { @@ -158,22 +159,22 @@ func resourceDomainConfigurationCreate(ctx context.Context, d *schema.ResourceDa input.ValidationCertificateArn = aws.String(v.(string)) } - output, err := conn.CreateDomainConfigurationWithContext(ctx, input) + output, err := conn.CreateDomainConfiguration(ctx, input) if err != nil { return sdkdiag.AppendErrorf(diags, "creating IoT Domain Configuration (%s): %s", name, err) } - d.SetId(aws.StringValue(output.DomainConfigurationName)) + d.SetId(aws.ToString(output.DomainConfigurationName)) return append(diags, resourceDomainConfigurationRead(ctx, d, meta)...) } func resourceDomainConfigurationRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { var diags diag.Diagnostics - conn := meta.(*conns.AWSClient).IoTConn(ctx) + conn := meta.(*conns.AWSClient).IoTClient(ctx) - output, err := FindDomainConfigurationByName(ctx, conn, d.Id()) + output, err := findDomainConfigurationByName(ctx, conn, d.Id()) if !d.IsNewResource() && tfresource.NotFound(err) { log.Printf("[WARN] IoT Domain Configuration (%s) not found, removing from state", d.Id()) @@ -196,8 +197,8 @@ func resourceDomainConfigurationRead(ctx context.Context, d *schema.ResourceData d.Set(names.AttrDomainName, output.DomainName) d.Set("domain_type", output.DomainType) d.Set(names.AttrName, output.DomainConfigurationName) - d.Set("server_certificate_arns", tfslices.ApplyToAll(output.ServerCertificates, func(v *iot.ServerCertificateSummary) string { - return aws.StringValue(v.ServerCertificateArn) + d.Set("server_certificate_arns", tfslices.ApplyToAll(output.ServerCertificates, func(v awstypes.ServerCertificateSummary) string { + return aws.ToString(v.ServerCertificateArn) })) d.Set("service_type", output.ServiceType) d.Set(names.AttrStatus, output.DomainConfigurationStatus) @@ -215,7 +216,7 @@ func resourceDomainConfigurationRead(ctx context.Context, d *schema.ResourceData func resourceDomainConfigurationUpdate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { var diags diag.Diagnostics - conn := meta.(*conns.AWSClient).IoTConn(ctx) + conn := meta.(*conns.AWSClient).IoTClient(ctx) if d.HasChangesExcept(names.AttrTags, names.AttrTagsAll) { input := &iot.UpdateDomainConfigurationInput{ @@ -226,12 +227,12 @@ func resourceDomainConfigurationUpdate(ctx context.Context, d *schema.ResourceDa if v, ok := d.GetOk("authorizer_config"); ok && len(v.([]interface{})) > 0 && v.([]interface{})[0] != nil { input.AuthorizerConfig = expandAuthorizerConfig(v.([]interface{})[0].(map[string]interface{})) } else { - input.RemoveAuthorizerConfig = aws.Bool(true) + input.RemoveAuthorizerConfig = true } } if d.HasChange(names.AttrStatus) { - input.DomainConfigurationStatus = aws.String(d.Get(names.AttrStatus).(string)) + input.DomainConfigurationStatus = awstypes.DomainConfigurationStatus(d.Get(names.AttrStatus).(string)) } if d.HasChange("tls_config") { @@ -240,7 +241,7 @@ func resourceDomainConfigurationUpdate(ctx context.Context, d *schema.ResourceDa } } - _, err := conn.UpdateDomainConfigurationWithContext(ctx, input) + _, err := conn.UpdateDomainConfiguration(ctx, input) if err != nil { return sdkdiag.AppendErrorf(diags, "updating IoT Domain Configuration (%s): %s", d.Id(), err) @@ -252,16 +253,15 @@ func resourceDomainConfigurationUpdate(ctx context.Context, d *schema.ResourceDa func resourceDomainConfigurationDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { var diags diag.Diagnostics - conn := meta.(*conns.AWSClient).IoTConn(ctx) + conn := meta.(*conns.AWSClient).IoTClient(ctx) - if d.Get(names.AttrStatus).(string) == iot.DomainConfigurationStatusEnabled { - log.Printf("[DEBUG] Disabling IoT Domain Configuration: %s", d.Id()) - _, err := conn.UpdateDomainConfigurationWithContext(ctx, &iot.UpdateDomainConfigurationInput{ + if d.Get(names.AttrStatus).(string) == string(awstypes.DomainConfigurationStatusEnabled) { + _, err := conn.UpdateDomainConfiguration(ctx, &iot.UpdateDomainConfigurationInput{ DomainConfigurationName: aws.String(d.Id()), - DomainConfigurationStatus: aws.String(iot.DomainConfigurationStatusDisabled), + DomainConfigurationStatus: awstypes.DomainConfigurationStatusDisabled, }) - if tfawserr.ErrCodeEquals(err, iot.ErrCodeResourceNotFoundException) { + if errs.IsA[*awstypes.ResourceNotFoundException](err) { return diags } @@ -271,11 +271,11 @@ func resourceDomainConfigurationDelete(ctx context.Context, d *schema.ResourceDa } log.Printf("[DEBUG] Deleting IoT Domain Configuration: %s", d.Id()) - _, err := conn.DeleteDomainConfigurationWithContext(ctx, &iot.DeleteDomainConfigurationInput{ + _, err := conn.DeleteDomainConfiguration(ctx, &iot.DeleteDomainConfigurationInput{ DomainConfigurationName: aws.String(d.Id()), }) - if tfawserr.ErrCodeEquals(err, iot.ErrCodeResourceNotFoundException) { + if errs.IsA[*awstypes.ResourceNotFoundException](err) { return diags } @@ -286,14 +286,14 @@ func resourceDomainConfigurationDelete(ctx context.Context, d *schema.ResourceDa return diags } -func FindDomainConfigurationByName(ctx context.Context, conn *iot.IoT, name string) (*iot.DescribeDomainConfigurationOutput, error) { +func findDomainConfigurationByName(ctx context.Context, conn *iot.Client, name string) (*iot.DescribeDomainConfigurationOutput, error) { input := &iot.DescribeDomainConfigurationInput{ DomainConfigurationName: aws.String(name), } - output, err := conn.DescribeDomainConfigurationWithContext(ctx, input) + output, err := conn.DescribeDomainConfiguration(ctx, input) - if tfawserr.ErrCodeEquals(err, iot.ErrCodeResourceNotFoundException) { + if errs.IsA[*awstypes.ResourceNotFoundException](err) { return nil, &retry.NotFoundError{ LastError: err, LastRequest: input, @@ -311,12 +311,12 @@ func FindDomainConfigurationByName(ctx context.Context, conn *iot.IoT, name stri return output, nil } -func expandAuthorizerConfig(tfMap map[string]interface{}) *iot.AuthorizerConfig { +func expandAuthorizerConfig(tfMap map[string]interface{}) *awstypes.AuthorizerConfig { if tfMap == nil { return nil } - apiObject := &iot.AuthorizerConfig{} + apiObject := &awstypes.AuthorizerConfig{} if v, ok := tfMap["allow_authorizer_override"].(bool); ok { apiObject.AllowAuthorizerOverride = aws.Bool(v) @@ -329,12 +329,12 @@ func expandAuthorizerConfig(tfMap map[string]interface{}) *iot.AuthorizerConfig return apiObject } -func expandTlsConfig(tfMap map[string]interface{}) *iot.TlsConfig { // nosemgrep:ci.caps5-in-func-name +func expandTlsConfig(tfMap map[string]interface{}) *awstypes.TlsConfig { // nosemgrep:ci.caps5-in-func-name if tfMap == nil { return nil } - apiObject := &iot.TlsConfig{} + apiObject := &awstypes.TlsConfig{} if v, ok := tfMap["security_policy"].(string); ok && v != "" { apiObject.SecurityPolicy = aws.String(v) @@ -343,7 +343,7 @@ func expandTlsConfig(tfMap map[string]interface{}) *iot.TlsConfig { // nosemgrep return apiObject } -func flattenAuthorizerConfig(apiObject *iot.AuthorizerConfig) map[string]interface{} { +func flattenAuthorizerConfig(apiObject *awstypes.AuthorizerConfig) map[string]interface{} { if apiObject == nil { return nil } @@ -351,17 +351,17 @@ func flattenAuthorizerConfig(apiObject *iot.AuthorizerConfig) map[string]interfa tfMap := map[string]interface{}{} if v := apiObject.AllowAuthorizerOverride; v != nil { - tfMap["allow_authorizer_override"] = aws.BoolValue(v) + tfMap["allow_authorizer_override"] = aws.ToBool(v) } if v := apiObject.DefaultAuthorizerName; v != nil { - tfMap["default_authorizer_name"] = aws.StringValue(v) + tfMap["default_authorizer_name"] = aws.ToString(v) } return tfMap } -func flattenTlsConfig(apiObject *iot.TlsConfig) map[string]interface{} { // nosemgrep:ci.caps5-in-func-name +func flattenTlsConfig(apiObject *awstypes.TlsConfig) map[string]interface{} { // nosemgrep:ci.caps5-in-func-name if apiObject == nil { return nil } @@ -369,7 +369,7 @@ func flattenTlsConfig(apiObject *iot.TlsConfig) map[string]interface{} { // nose tfMap := map[string]interface{}{} if v := apiObject.SecurityPolicy; v != nil { - tfMap["security_policy"] = aws.StringValue(v) + tfMap["security_policy"] = aws.ToString(v) } return tfMap diff --git a/internal/service/iot/domain_configuration_test.go b/internal/service/iot/domain_configuration_test.go index c56f0cf8757..bd1e0204894 100644 --- a/internal/service/iot/domain_configuration_test.go +++ b/internal/service/iot/domain_configuration_test.go @@ -215,7 +215,7 @@ func testAccCheckDomainConfigurationExists(ctx context.Context, n string) resour return fmt.Errorf("Not found: %s", n) } - conn := acctest.Provider.Meta().(*conns.AWSClient).IoTConn(ctx) + conn := acctest.Provider.Meta().(*conns.AWSClient).IoTClient(ctx) _, err := tfiot.FindDomainConfigurationByName(ctx, conn, rs.Primary.ID) @@ -225,7 +225,7 @@ func testAccCheckDomainConfigurationExists(ctx context.Context, n string) resour func testAccCheckDomainConfigurationDestroy(ctx context.Context) resource.TestCheckFunc { return func(s *terraform.State) error { - conn := acctest.Provider.Meta().(*conns.AWSClient).IoTConn(ctx) + conn := acctest.Provider.Meta().(*conns.AWSClient).IoTClient(ctx) for _, rs := range s.RootModule().Resources { if rs.Type != "aws_iot_domain_configuration" { diff --git a/internal/service/iot/endpoint_data_source.go b/internal/service/iot/endpoint_data_source.go index 5d110fdbf63..0a8e4aa0eb4 100644 --- a/internal/service/iot/endpoint_data_source.go +++ b/internal/service/iot/endpoint_data_source.go @@ -6,8 +6,8 @@ package iot import ( "context" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/service/iot" + "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/service/iot" "github.com/hashicorp/terraform-plugin-sdk/v2/diag" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" @@ -16,8 +16,8 @@ import ( "github.com/hashicorp/terraform-provider-aws/names" ) -// @SDKDataSource("aws_iot_endpoint") -func DataSourceEndpoint() *schema.Resource { +// @SDKDataSource("aws_iot_endpoint", name="Endpoint") +func dataSourceEndpoint() *schema.Resource { return &schema.Resource{ ReadWithoutTimeout: dataSourceEndpointRead, Schema: map[string]*schema.Schema{ @@ -41,21 +41,25 @@ func DataSourceEndpoint() *schema.Resource { func dataSourceEndpointRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { var diags diag.Diagnostics - conn := meta.(*conns.AWSClient).IoTConn(ctx) + conn := meta.(*conns.AWSClient).IoTClient(ctx) + input := &iot.DescribeEndpointInput{} if v, ok := d.GetOk(names.AttrEndpointType); ok { input.EndpointType = aws.String(v.(string)) } - output, err := conn.DescribeEndpointWithContext(ctx, input) + output, err := conn.DescribeEndpoint(ctx, input) + if err != nil { - return sdkdiag.AppendErrorf(diags, "while describing iot endpoint: %s", err) + return sdkdiag.AppendErrorf(diags, "reading IoT Endpoint: %s", err) } - endpointAddress := aws.StringValue(output.EndpointAddress) + + endpointAddress := aws.ToString(output.EndpointAddress) d.SetId(endpointAddress) if err := d.Set("endpoint_address", endpointAddress); err != nil { return sdkdiag.AppendErrorf(diags, "setting endpoint_address: %s", err) } + return diags } diff --git a/internal/service/iot/event_configurations.go b/internal/service/iot/event_configurations.go index 1a8477be123..48cb55eebaf 100644 --- a/internal/service/iot/event_configurations.go +++ b/internal/service/iot/event_configurations.go @@ -7,12 +7,14 @@ import ( "context" "log" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/service/iot" + "github.com/aws/aws-sdk-go-v2/service/iot" + awstypes "github.com/aws/aws-sdk-go-v2/service/iot/types" "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/retry" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" "github.com/hashicorp/terraform-provider-aws/internal/conns" + "github.com/hashicorp/terraform-provider-aws/internal/enum" + "github.com/hashicorp/terraform-provider-aws/internal/errs" "github.com/hashicorp/terraform-provider-aws/internal/errs/sdkdiag" tfmaps "github.com/hashicorp/terraform-provider-aws/internal/maps" "github.com/hashicorp/terraform-provider-aws/internal/tfresource" @@ -20,7 +22,7 @@ import ( ) // @SDKResource("aws_iot_event_configurations", name="Event Configurations") -func ResourceEventConfigurations() *schema.Resource { +func resourceEventConfigurations() *schema.Resource { return &schema.Resource{ CreateWithoutTimeout: resourceEventConfigurationsPut, ReadWithoutTimeout: resourceEventConfigurationsRead, @@ -36,7 +38,7 @@ func ResourceEventConfigurations() *schema.Resource { Type: schema.TypeMap, Required: true, Elem: &schema.Schema{Type: schema.TypeBool}, - ValidateDiagFunc: verify.MapKeysAre(validation.ToDiagFunc(validation.StringInSlice(iot.EventType_Values(), false))), + ValidateDiagFunc: verify.MapKeysAre(enum.Validate[awstypes.EventType]()), }, }, } @@ -44,22 +46,22 @@ func ResourceEventConfigurations() *schema.Resource { func resourceEventConfigurationsPut(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { var diags diag.Diagnostics - conn := meta.(*conns.AWSClient).IoTConn(ctx) + conn := meta.(*conns.AWSClient).IoTClient(ctx) input := &iot.UpdateEventConfigurationsInput{} if v, ok := d.GetOk("event_configurations"); ok && len(v.(map[string]interface{})) > 0 { - input.EventConfigurations = tfmaps.ApplyToAllValues(v.(map[string]interface{}), func(v interface{}) *iot.Configuration { - return &iot.Configuration{ - Enabled: aws.Bool(v.(bool)), + input.EventConfigurations = tfmaps.ApplyToAllValues(v.(map[string]interface{}), func(v interface{}) awstypes.Configuration { + return awstypes.Configuration{ + Enabled: v.(bool), } }) } - _, err := conn.UpdateEventConfigurationsWithContext(ctx, input) + _, err := conn.UpdateEventConfigurations(ctx, input) if err != nil { - return sdkdiag.AppendErrorf(diags, "updating IoT Event Configurations (%s): %s", meta.(*conns.AWSClient).Region, err) + return sdkdiag.AppendErrorf(diags, "updating IoT Event Configurations: %s", err) } if d.IsNewResource() { @@ -71,7 +73,7 @@ func resourceEventConfigurationsPut(ctx context.Context, d *schema.ResourceData, func resourceEventConfigurationsRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { var diags diag.Diagnostics - conn := meta.(*conns.AWSClient).IoTConn(ctx) + conn := meta.(*conns.AWSClient).IoTClient(ctx) output, err := findEventConfigurations(ctx, conn) @@ -85,16 +87,23 @@ func resourceEventConfigurationsRead(ctx context.Context, d *schema.ResourceData return sdkdiag.AppendErrorf(diags, "reading IoT Event Configurations (%s): %s", d.Id(), err) } - d.Set("event_configurations", tfmaps.ApplyToAllValues(output, func(v *iot.Configuration) bool { - return aws.BoolValue(v.Enabled) + d.Set("event_configurations", tfmaps.ApplyToAllValues(output, func(v awstypes.Configuration) bool { + return v.Enabled })) return diags } -func findEventConfigurations(ctx context.Context, conn *iot.IoT) (map[string]*iot.Configuration, error) { +func findEventConfigurations(ctx context.Context, conn *iot.Client) (map[string]awstypes.Configuration, error) { input := &iot.DescribeEventConfigurationsInput{} - output, err := conn.DescribeEventConfigurationsWithContext(ctx, input) + output, err := conn.DescribeEventConfigurations(ctx, input) + + if errs.IsA[*awstypes.ResourceNotFoundException](err) { + return nil, &retry.NotFoundError{ + LastError: err, + LastRequest: input, + } + } if err != nil { return nil, err diff --git a/internal/service/iot/exports_test.go b/internal/service/iot/exports_test.go new file mode 100644 index 00000000000..b87987edfa1 --- /dev/null +++ b/internal/service/iot/exports_test.go @@ -0,0 +1,44 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package iot + +// Exports for use in tests only. +var ( + ResourceAuthorizer = resourceAuthorizer + ResourceBillingGroup = resourceBillingGroup + ResourceCACertificate = resourceCACertificate + ResourceCertificate = resourceCertificate + ResourceDomainConfiguration = resourceDomainConfiguration + ResourceEventConfigurations = resourceEventConfigurations + ResourceIndexingConfiguration = resourceIndexingConfiguration + ResourceLoggingOptions = resourceLoggingOptions + ResourcePolicy = resourcePolicy + ResourcePolicyAttachment = resourcePolicyAttachment + ResourceProvisioningTemplate = resourceProvisioningTemplate + ResourceThing = resourceThing + ResourceThingGroup = resourceThingGroup + ResourceThingGroupMembership = resourceThingGroupMembership + ResourceThingPrincipalAttachment = resourceThingPrincipalAttachment + ResourceThingType = resourceThingType + ResourceTopicRule = resourceTopicRule + ResourceTopicRuleDestination = resourceTopicRuleDestination + + FindAttachedPolicyByTwoPartKey = findAttachedPolicyByTwoPartKey + FindAuthorizerByName = findAuthorizerByName + FindBillingGroupByName = findBillingGroupByName + FindCACertificateByID = findCACertificateByID + FindCertificateByID = findCertificateByID + FindDomainConfigurationByName = findDomainConfigurationByName + FindPolicyByName = findPolicyByName + FindPolicyVersionsByName = findPolicyVersionsByName + FindProvisioningTemplateByName = findProvisioningTemplateByName + FindRoleAliasByID = findRoleAliasByID + FindThingByName = findThingByName + FindThingGroupByName = findThingGroupByName + FindThingGroupMembershipByTwoPartKey = findThingGroupMembershipByTwoPartKey + FindThingPrincipalAttachmentByTwoPartKey = findThingPrincipalAttachmentByTwoPartKey + FindThingTypeByName = findThingTypeByName + FindTopicRuleDestinationByARN = findTopicRuleDestinationByARN + FindTopicRuleByName = findTopicRuleByName +) diff --git a/internal/service/iot/find.go b/internal/service/iot/find.go deleted file mode 100644 index ecfdbea6eec..00000000000 --- a/internal/service/iot/find.go +++ /dev/null @@ -1,228 +0,0 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - -package iot - -import ( - "context" - - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/service/iot" - "github.com/hashicorp/aws-sdk-go-base/v2/awsv1shim/v2/tfawserr" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/retry" - "github.com/hashicorp/terraform-provider-aws/internal/tfresource" -) - -func FindAuthorizerByName(ctx context.Context, conn *iot.IoT, name string) (*iot.AuthorizerDescription, error) { - input := &iot.DescribeAuthorizerInput{ - AuthorizerName: aws.String(name), - } - - output, err := conn.DescribeAuthorizerWithContext(ctx, input) - - if tfawserr.ErrCodeEquals(err, iot.ErrCodeResourceNotFoundException) { - return nil, &retry.NotFoundError{ - LastError: err, - LastRequest: input, - } - } - - if err != nil { - return nil, err - } - - if output == nil || output.AuthorizerDescription == nil { - return nil, tfresource.NewEmptyResultError(input) - } - - return output.AuthorizerDescription, nil -} - -func FindThingByName(ctx context.Context, conn *iot.IoT, name string) (*iot.DescribeThingOutput, error) { - input := &iot.DescribeThingInput{ - ThingName: aws.String(name), - } - - output, err := conn.DescribeThingWithContext(ctx, input) - - if tfawserr.ErrCodeEquals(err, iot.ErrCodeResourceNotFoundException) { - return nil, &retry.NotFoundError{ - LastError: err, - LastRequest: input, - } - } - - if err != nil { - return nil, err - } - - if output == nil { - return nil, tfresource.NewEmptyResultError(input) - } - - return output, nil -} - -func FindThingGroupByName(ctx context.Context, conn *iot.IoT, name string) (*iot.DescribeThingGroupOutput, error) { - input := &iot.DescribeThingGroupInput{ - ThingGroupName: aws.String(name), - } - - output, err := conn.DescribeThingGroupWithContext(ctx, input) - - if tfawserr.ErrCodeEquals(err, iot.ErrCodeResourceNotFoundException) { - return nil, &retry.NotFoundError{ - LastError: err, - LastRequest: input, - } - } - - if err != nil { - return nil, err - } - - if output == nil { - return nil, tfresource.NewEmptyResultError(input) - } - - return output, nil -} - -func FindThingGroupMembership(ctx context.Context, conn *iot.IoT, thingGroupName, thingName string) error { - input := &iot.ListThingGroupsForThingInput{ - ThingName: aws.String(thingName), - } - - var v *iot.GroupNameAndArn - - err := conn.ListThingGroupsForThingPagesWithContext(ctx, input, func(page *iot.ListThingGroupsForThingOutput, lastPage bool) bool { - if page == nil { - return !lastPage - } - - for _, group := range page.ThingGroups { - if aws.StringValue(group.GroupName) == thingGroupName { - v = group - - return false - } - } - - return !lastPage - }) - - if tfawserr.ErrCodeEquals(err, iot.ErrCodeResourceNotFoundException) { - return &retry.NotFoundError{ - LastError: err, - LastRequest: input, - } - } - - if v == nil { - return tfresource.NewEmptyResultError(input) - } - - return nil -} - -func FindTopicRuleByName(ctx context.Context, conn *iot.IoT, name string) (*iot.GetTopicRuleOutput, error) { - // GetTopicRule returns unhelpful errors such as - // "An error occurred (UnauthorizedException) when calling the GetTopicRule operation: Access to topic rule 'xxxxxxxx' was denied" - // when querying for a rule that doesn't exist. - var rule *iot.TopicRuleListItem - - err := conn.ListTopicRulesPagesWithContext(ctx, &iot.ListTopicRulesInput{}, func(page *iot.ListTopicRulesOutput, lastPage bool) bool { - if page == nil { - return !lastPage - } - - for _, v := range page.Rules { - if v == nil { - continue - } - - if aws.StringValue(v.RuleName) == name { - rule = v - - return false - } - } - - return !lastPage - }) - - if err != nil { - return nil, err - } - - if rule == nil { - return nil, tfresource.NewEmptyResultError(name) - } - - input := &iot.GetTopicRuleInput{ - RuleName: aws.String(name), - } - - output, err := conn.GetTopicRuleWithContext(ctx, input) - - if err != nil { - return nil, err - } - - if output == nil { - return nil, tfresource.NewEmptyResultError(input) - } - - return output, nil -} - -func FindTopicRuleDestinationByARN(ctx context.Context, conn *iot.IoT, arn string) (*iot.TopicRuleDestination, error) { - // GetTopicRuleDestination returns unhelpful errors such as - // "UnauthorizedException: Access to TopicRuleDestination 'arn:aws:iot:us-west-2:123456789012:ruledestination/vpc/f267138a-7383-4670-9e44-a7fe2f48af5e' was denied" - // when querying for a rule destination that doesn't exist. - var destination *iot.TopicRuleDestinationSummary - - err := conn.ListTopicRuleDestinationsPagesWithContext(ctx, &iot.ListTopicRuleDestinationsInput{}, func(page *iot.ListTopicRuleDestinationsOutput, lastPage bool) bool { - if page == nil { - return !lastPage - } - - for _, v := range page.DestinationSummaries { - if v == nil { - continue - } - - if aws.StringValue(v.Arn) == arn { - destination = v - - return false - } - } - - return !lastPage - }) - - if err != nil { - return nil, err - } - - if destination == nil { - return nil, tfresource.NewEmptyResultError(destination) - } - - input := &iot.GetTopicRuleDestinationInput{ - Arn: aws.String(arn), - } - - output, err := conn.GetTopicRuleDestinationWithContext(ctx, input) - - if err != nil { - return nil, err - } - - if output == nil || output.TopicRuleDestination == nil { - return nil, tfresource.NewEmptyResultError(input) - } - - return output.TopicRuleDestination, nil -} diff --git a/internal/service/iot/flex.go b/internal/service/iot/flex.go deleted file mode 100644 index 50b98f4739b..00000000000 --- a/internal/service/iot/flex.go +++ /dev/null @@ -1,40 +0,0 @@ -// Copyright (c) HashiCorp, Inc. -// SPDX-License-Identifier: MPL-2.0 - -package iot - -import ( - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/service/iot" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" - "github.com/hashicorp/terraform-provider-aws/internal/flex" - "github.com/hashicorp/terraform-provider-aws/names" -) - -func expandThingTypeProperties(config map[string]interface{}) *iot.ThingTypeProperties { - properties := &iot.ThingTypeProperties{ - SearchableAttributes: flex.ExpandStringSet(config["searchable_attributes"].(*schema.Set)), - } - - if v, ok := config[names.AttrDescription]; ok && v.(string) != "" { - properties.ThingTypeDescription = aws.String(v.(string)) - } - - return properties -} - -func flattenThingTypeProperties(s *iot.ThingTypeProperties) []map[string]interface{} { - m := map[string]interface{}{ - names.AttrDescription: "", - "searchable_attributes": flex.FlattenStringSet(nil), - } - - if s == nil { - return []map[string]interface{}{m} - } - - m[names.AttrDescription] = aws.StringValue(s.ThingTypeDescription) - m["searchable_attributes"] = flex.FlattenStringSet(s.SearchableAttributes) - - return []map[string]interface{}{m} -} diff --git a/internal/service/iot/generate.go b/internal/service/iot/generate.go index d93df36bc39..6585ee81cb7 100644 --- a/internal/service/iot/generate.go +++ b/internal/service/iot/generate.go @@ -1,7 +1,7 @@ // Copyright (c) HashiCorp, Inc. // SPDX-License-Identifier: MPL-2.0 -//go:generate go run ../../generate/tags/main.go -ListTags -ServiceTagsSlice -UpdateTags +//go:generate go run ../../generate/tags/main.go -ListTags -ServiceTagsSlice -UpdateTags -AWSSDKVersion=2 //go:generate go run ../../generate/servicepackage/main.go // ONLY generate directives and package declaration! Do not add anything else to this file. diff --git a/internal/service/iot/indexing_configuration.go b/internal/service/iot/indexing_configuration.go index 0328ed24c47..349ae0b3eea 100644 --- a/internal/service/iot/indexing_configuration.go +++ b/internal/service/iot/indexing_configuration.go @@ -7,19 +7,21 @@ import ( "context" "github.com/YakDriver/regexache" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/service/iot" + "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/service/iot" + awstypes "github.com/aws/aws-sdk-go-v2/service/iot/types" "github.com/hashicorp/terraform-plugin-sdk/v2/diag" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" "github.com/hashicorp/terraform-provider-aws/internal/conns" + "github.com/hashicorp/terraform-provider-aws/internal/enum" "github.com/hashicorp/terraform-provider-aws/internal/errs/sdkdiag" "github.com/hashicorp/terraform-provider-aws/internal/flex" "github.com/hashicorp/terraform-provider-aws/names" ) -// @SDKResource("aws_iot_indexing_configuration") -func ResourceIndexingConfiguration() *schema.Resource { +// @SDKResource("aws_iot_indexing_configuration", name="Indexing Configuration") +func resourceIndexingConfiguration() *schema.Resource { return &schema.Resource{ CreateWithoutTimeout: resourceIndexingConfigurationPut, ReadWithoutTimeout: resourceIndexingConfigurationRead, @@ -48,9 +50,9 @@ func ResourceIndexingConfiguration() *schema.Resource { Optional: true, }, names.AttrType: { - Type: schema.TypeString, - Optional: true, - ValidateFunc: validation.StringInSlice(iot.FieldType_Values(), false), + Type: schema.TypeString, + Optional: true, + ValidateDiagFunc: enum.Validate[awstypes.FieldType](), }, }, }, @@ -66,17 +68,17 @@ func ResourceIndexingConfiguration() *schema.Resource { Optional: true, }, names.AttrType: { - Type: schema.TypeString, - Optional: true, - ValidateFunc: validation.StringInSlice(iot.FieldType_Values(), false), + Type: schema.TypeString, + Optional: true, + ValidateDiagFunc: enum.Validate[awstypes.FieldType](), }, }, }, }, "thing_group_indexing_mode": { - Type: schema.TypeString, - Required: true, - ValidateFunc: validation.StringInSlice(iot.ThingGroupIndexingMode_Values(), false), + Type: schema.TypeString, + Required: true, + ValidateDiagFunc: enum.Validate[awstypes.ThingGroupIndexingMode](), }, }, }, @@ -99,18 +101,18 @@ func ResourceIndexingConfiguration() *schema.Resource { Optional: true, }, names.AttrType: { - Type: schema.TypeString, - Optional: true, - ValidateFunc: validation.StringInSlice(iot.FieldType_Values(), false), + Type: schema.TypeString, + Optional: true, + ValidateDiagFunc: enum.Validate[awstypes.FieldType](), }, }, }, }, "device_defender_indexing_mode": { - Type: schema.TypeString, - Optional: true, - Default: iot.DeviceDefenderIndexingModeOff, - ValidateFunc: validation.StringInSlice(iot.DeviceDefenderIndexingMode_Values(), false), + Type: schema.TypeString, + Optional: true, + Default: awstypes.DeviceDefenderIndexingModeOff, + ValidateDiagFunc: enum.Validate[awstypes.DeviceDefenderIndexingMode](), }, names.AttrFilter: { Type: schema.TypeList, @@ -145,29 +147,29 @@ func ResourceIndexingConfiguration() *schema.Resource { Optional: true, }, names.AttrType: { - Type: schema.TypeString, - Optional: true, - ValidateFunc: validation.StringInSlice(iot.FieldType_Values(), false), + Type: schema.TypeString, + Optional: true, + ValidateDiagFunc: enum.Validate[awstypes.FieldType](), }, }, }, }, "named_shadow_indexing_mode": { - Type: schema.TypeString, - Optional: true, - Default: iot.NamedShadowIndexingModeOff, - ValidateFunc: validation.StringInSlice(iot.NamedShadowIndexingMode_Values(), false), + Type: schema.TypeString, + Optional: true, + Default: awstypes.NamedShadowIndexingModeOff, + ValidateDiagFunc: enum.Validate[awstypes.NamedShadowIndexingMode](), }, "thing_connectivity_indexing_mode": { - Type: schema.TypeString, - Optional: true, - Default: iot.ThingConnectivityIndexingModeOff, - ValidateFunc: validation.StringInSlice(iot.ThingConnectivityIndexingMode_Values(), false), + Type: schema.TypeString, + Optional: true, + Default: awstypes.ThingConnectivityIndexingModeOff, + ValidateDiagFunc: enum.Validate[awstypes.ThingConnectivityIndexingMode](), }, "thing_indexing_mode": { - Type: schema.TypeString, - Required: true, - ValidateFunc: validation.StringInSlice(iot.ThingIndexingMode_Values(), false), + Type: schema.TypeString, + Required: true, + ValidateDiagFunc: enum.Validate[awstypes.ThingIndexingMode](), }, }, }, @@ -180,7 +182,7 @@ func ResourceIndexingConfiguration() *schema.Resource { func resourceIndexingConfigurationPut(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { var diags diag.Diagnostics - conn := meta.(*conns.AWSClient).IoTConn(ctx) + conn := meta.(*conns.AWSClient).IoTClient(ctx) input := &iot.UpdateIndexingConfigurationInput{} @@ -192,13 +194,15 @@ func resourceIndexingConfigurationPut(ctx context.Context, d *schema.ResourceDat input.ThingIndexingConfiguration = expandThingIndexingConfiguration(v.([]interface{})[0].(map[string]interface{})) } - _, err := conn.UpdateIndexingConfigurationWithContext(ctx, input) + _, err := conn.UpdateIndexingConfiguration(ctx, input) if err != nil { return sdkdiag.AppendErrorf(diags, "updating IoT Indexing Configuration: %s", err) } - d.SetId(meta.(*conns.AWSClient).Region) + if d.IsNewResource() { + d.SetId(meta.(*conns.AWSClient).Region) + } return append(diags, resourceIndexingConfigurationRead(ctx, d, meta)...) } @@ -206,12 +210,12 @@ func resourceIndexingConfigurationPut(ctx context.Context, d *schema.ResourceDat func resourceIndexingConfigurationRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { var diags diag.Diagnostics - conn := meta.(*conns.AWSClient).IoTConn(ctx) + conn := meta.(*conns.AWSClient).IoTClient(ctx) - output, err := conn.GetIndexingConfigurationWithContext(ctx, &iot.GetIndexingConfigurationInput{}) + output, err := conn.GetIndexingConfiguration(ctx, &iot.GetIndexingConfigurationInput{}) if err != nil { - return sdkdiag.AppendErrorf(diags, "reading IoT Indexing Configuration: %s", err) + return sdkdiag.AppendErrorf(diags, "reading IoT Indexing Configuration (%s): %s", d.Id(), err) } if output.ThingGroupIndexingConfiguration != nil { @@ -232,12 +236,14 @@ func resourceIndexingConfigurationRead(ctx context.Context, d *schema.ResourceDa return diags } -func flattenThingGroupIndexingConfiguration(apiObject *iot.ThingGroupIndexingConfiguration) map[string]interface{} { +func flattenThingGroupIndexingConfiguration(apiObject *awstypes.ThingGroupIndexingConfiguration) map[string]interface{} { if apiObject == nil { return nil } - tfMap := map[string]interface{}{} + tfMap := map[string]interface{}{ + "thing_group_indexing_mode": apiObject.ThingGroupIndexingMode, + } if v := apiObject.CustomFields; v != nil { tfMap["custom_field"] = flattenFields(v) @@ -247,28 +253,25 @@ func flattenThingGroupIndexingConfiguration(apiObject *iot.ThingGroupIndexingCon tfMap["managed_field"] = flattenFields(v) } - if v := apiObject.ThingGroupIndexingMode; v != nil { - tfMap["thing_group_indexing_mode"] = aws.StringValue(v) - } - return tfMap } -func flattenThingIndexingConfiguration(apiObject *iot.ThingIndexingConfiguration) map[string]interface{} { +func flattenThingIndexingConfiguration(apiObject *awstypes.ThingIndexingConfiguration) map[string]interface{} { if apiObject == nil { return nil } - tfMap := map[string]interface{}{} + tfMap := map[string]interface{}{ + "device_defender_indexing_mode": apiObject.DeviceDefenderIndexingMode, + "named_shadow_indexing_mode": apiObject.NamedShadowIndexingMode, + "thing_connectivity_indexing_mode": apiObject.ThingConnectivityIndexingMode, + "thing_indexing_mode": apiObject.ThingIndexingMode, + } if v := apiObject.CustomFields; v != nil { tfMap["custom_field"] = flattenFields(v) } - if v := apiObject.DeviceDefenderIndexingMode; v != nil { - tfMap["device_defender_indexing_mode"] = aws.StringValue(v) - } - if v := apiObject.Filter; v != nil { tfMap[names.AttrFilter] = []interface{}{flattenIndexingFilter(v)} } @@ -277,22 +280,10 @@ func flattenThingIndexingConfiguration(apiObject *iot.ThingIndexingConfiguration tfMap["managed_field"] = flattenFields(v) } - if v := apiObject.NamedShadowIndexingMode; v != nil { - tfMap["named_shadow_indexing_mode"] = aws.StringValue(v) - } - - if v := apiObject.ThingConnectivityIndexingMode; v != nil { - tfMap["thing_connectivity_indexing_mode"] = aws.StringValue(v) - } - - if v := apiObject.ThingIndexingMode; v != nil { - tfMap["thing_indexing_mode"] = aws.StringValue(v) - } - return tfMap } -func flattenIndexingFilter(apiObject *iot.IndexingFilter) map[string]interface{} { +func flattenIndexingFilter(apiObject *awstypes.IndexingFilter) map[string]interface{} { if apiObject == nil { return nil } @@ -300,31 +291,25 @@ func flattenIndexingFilter(apiObject *iot.IndexingFilter) map[string]interface{} tfMap := map[string]interface{}{} if v := apiObject.NamedShadowNames; v != nil { - tfMap["named_shadow_names"] = aws.StringValueSlice(v) + tfMap["named_shadow_names"] = aws.StringSlice(v) } return tfMap } -func flattenField(apiObject *iot.Field) map[string]interface{} { - if apiObject == nil { - return nil +func flattenField(apiObject awstypes.Field) map[string]interface{} { + tfMap := map[string]interface{}{ + names.AttrType: apiObject.Type, } - tfMap := map[string]interface{}{} - if v := apiObject.Name; v != nil { - tfMap[names.AttrName] = aws.StringValue(v) - } - - if v := apiObject.Type; v != nil { - tfMap[names.AttrType] = aws.StringValue(v) + tfMap[names.AttrName] = aws.ToString(v) } return tfMap } -func flattenFields(apiObjects []*iot.Field) []interface{} { +func flattenFields(apiObjects []awstypes.Field) []interface{} { if len(apiObjects) == 0 { return nil } @@ -332,22 +317,18 @@ func flattenFields(apiObjects []*iot.Field) []interface{} { var tfList []interface{} for _, apiObject := range apiObjects { - if apiObject == nil { - continue - } - tfList = append(tfList, flattenField(apiObject)) } return tfList } -func expandThingGroupIndexingConfiguration(tfMap map[string]interface{}) *iot.ThingGroupIndexingConfiguration { +func expandThingGroupIndexingConfiguration(tfMap map[string]interface{}) *awstypes.ThingGroupIndexingConfiguration { if tfMap == nil { return nil } - apiObject := &iot.ThingGroupIndexingConfiguration{} + apiObject := &awstypes.ThingGroupIndexingConfiguration{} if v, ok := tfMap["custom_field"].(*schema.Set); ok && v.Len() > 0 { apiObject.CustomFields = expandFields(v.List()) @@ -358,25 +339,25 @@ func expandThingGroupIndexingConfiguration(tfMap map[string]interface{}) *iot.Th } if v, ok := tfMap["thing_group_indexing_mode"].(string); ok && v != "" { - apiObject.ThingGroupIndexingMode = aws.String(v) + apiObject.ThingGroupIndexingMode = awstypes.ThingGroupIndexingMode(v) } return apiObject } -func expandThingIndexingConfiguration(tfMap map[string]interface{}) *iot.ThingIndexingConfiguration { +func expandThingIndexingConfiguration(tfMap map[string]interface{}) *awstypes.ThingIndexingConfiguration { if tfMap == nil { return nil } - apiObject := &iot.ThingIndexingConfiguration{} + apiObject := &awstypes.ThingIndexingConfiguration{} if v, ok := tfMap["custom_field"].(*schema.Set); ok && v.Len() > 0 { apiObject.CustomFields = expandFields(v.List()) } if v, ok := tfMap["device_defender_indexing_mode"].(string); ok && v != "" { - apiObject.DeviceDefenderIndexingMode = aws.String(v) + apiObject.DeviceDefenderIndexingMode = awstypes.DeviceDefenderIndexingMode(v) } if v, ok := tfMap[names.AttrFilter]; ok && len(v.([]interface{})) > 0 && v.([]interface{})[0] != nil { @@ -388,58 +369,58 @@ func expandThingIndexingConfiguration(tfMap map[string]interface{}) *iot.ThingIn } if v, ok := tfMap["named_shadow_indexing_mode"].(string); ok && v != "" { - apiObject.NamedShadowIndexingMode = aws.String(v) + apiObject.NamedShadowIndexingMode = awstypes.NamedShadowIndexingMode(v) } if v, ok := tfMap["thing_connectivity_indexing_mode"].(string); ok && v != "" { - apiObject.ThingConnectivityIndexingMode = aws.String(v) + apiObject.ThingConnectivityIndexingMode = awstypes.ThingConnectivityIndexingMode(v) } if v, ok := tfMap["thing_indexing_mode"].(string); ok && v != "" { - apiObject.ThingIndexingMode = aws.String(v) + apiObject.ThingIndexingMode = awstypes.ThingIndexingMode(v) } return apiObject } -func expandIndexingFilter(tfMap map[string]interface{}) *iot.IndexingFilter { +func expandIndexingFilter(tfMap map[string]interface{}) *awstypes.IndexingFilter { if tfMap == nil { return nil } - apiObject := &iot.IndexingFilter{} + apiObject := &awstypes.IndexingFilter{} if v, ok := tfMap["named_shadow_names"].(*schema.Set); ok && v.Len() > 0 { - apiObject.NamedShadowNames = flex.ExpandStringSet(v) + apiObject.NamedShadowNames = flex.ExpandStringValueSet(v) } return apiObject } -func expandField(tfMap map[string]interface{}) *iot.Field { +func expandField(tfMap map[string]interface{}) *awstypes.Field { if tfMap == nil { return nil } - apiObject := &iot.Field{} + apiObject := &awstypes.Field{} if v, ok := tfMap[names.AttrName].(string); ok && v != "" { apiObject.Name = aws.String(v) } if v, ok := tfMap[names.AttrType].(string); ok && v != "" { - apiObject.Type = aws.String(v) + apiObject.Type = awstypes.FieldType(v) } return apiObject } -func expandFields(tfList []interface{}) []*iot.Field { +func expandFields(tfList []interface{}) []awstypes.Field { if len(tfList) == 0 { return nil } - var apiObjects []*iot.Field + var apiObjects []awstypes.Field for _, tfMapRaw := range tfList { tfMap, ok := tfMapRaw.(map[string]interface{}) @@ -454,7 +435,7 @@ func expandFields(tfList []interface{}) []*iot.Field { continue } - apiObjects = append(apiObjects, apiObject) + apiObjects = append(apiObjects, *apiObject) } return apiObjects diff --git a/internal/service/iot/logging_options.go b/internal/service/iot/logging_options.go index edd184c7c02..6995e5e0edd 100644 --- a/internal/service/iot/logging_options.go +++ b/internal/service/iot/logging_options.go @@ -6,20 +6,21 @@ package iot import ( "context" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/service/iot" + "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/service/iot" + awstypes "github.com/aws/aws-sdk-go-v2/service/iot/types" "github.com/hashicorp/terraform-plugin-sdk/v2/diag" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" - "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" "github.com/hashicorp/terraform-provider-aws/internal/conns" + "github.com/hashicorp/terraform-provider-aws/internal/enum" "github.com/hashicorp/terraform-provider-aws/internal/errs/sdkdiag" "github.com/hashicorp/terraform-provider-aws/internal/tfresource" "github.com/hashicorp/terraform-provider-aws/internal/verify" "github.com/hashicorp/terraform-provider-aws/names" ) -// @SDKResource("aws_iot_logging_options") -func ResourceLoggingOptions() *schema.Resource { +// @SDKResource("aws_iot_logging_options", name="Logging Options") +func resourceLoggingOptions() *schema.Resource { return &schema.Resource{ CreateWithoutTimeout: resourceLoggingOptionsPut, ReadWithoutTimeout: resourceLoggingOptionsRead, @@ -28,9 +29,9 @@ func ResourceLoggingOptions() *schema.Resource { Schema: map[string]*schema.Schema{ "default_log_level": { - Type: schema.TypeString, - Required: true, - ValidateFunc: validation.StringInSlice(iot.LogLevel_Values(), false), + Type: schema.TypeString, + Required: true, + ValidateDiagFunc: enum.Validate[awstypes.LogLevel](), }, "disable_all_logs": { Type: schema.TypeBool, @@ -48,34 +49,33 @@ func ResourceLoggingOptions() *schema.Resource { func resourceLoggingOptionsPut(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { var diags diag.Diagnostics - conn := meta.(*conns.AWSClient).IoTConn(ctx) + conn := meta.(*conns.AWSClient).IoTClient(ctx) input := &iot.SetV2LoggingOptionsInput{} if v, ok := d.GetOk("default_log_level"); ok { - input.DefaultLogLevel = aws.String(v.(string)) + input.DefaultLogLevel = awstypes.LogLevel(v.(string)) } if v, ok := d.GetOk("disable_all_logs"); ok { - input.DisableAllLogs = aws.Bool(v.(bool)) + input.DisableAllLogs = v.(bool) } if v, ok := d.GetOk(names.AttrRoleARN); ok { input.RoleArn = aws.String(v.(string)) } - _, err := tfresource.RetryWhenAWSErrMessageContains(ctx, propagationTimeout, - func() (interface{}, error) { - return conn.SetV2LoggingOptionsWithContext(ctx, input) - }, - iot.ErrCodeInvalidRequestException, "If the role was just created or updated, please try again in a few seconds.", - ) + _, err := tfresource.RetryWhenIsA[*awstypes.InvalidRequestException](ctx, propagationTimeout, func() (interface{}, error) { + return conn.SetV2LoggingOptions(ctx, input) + }) if err != nil { - return sdkdiag.AppendErrorf(diags, "setting IoT logging options: %s", err) + return sdkdiag.AppendErrorf(diags, "setting IoT Logging Options: %s", err) } - d.SetId(meta.(*conns.AWSClient).Region) + if d.IsNewResource() { + d.SetId(meta.(*conns.AWSClient).Region) + } return append(diags, resourceLoggingOptionsRead(ctx, d, meta)...) } @@ -83,12 +83,12 @@ func resourceLoggingOptionsPut(ctx context.Context, d *schema.ResourceData, meta func resourceLoggingOptionsRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { var diags diag.Diagnostics - conn := meta.(*conns.AWSClient).IoTConn(ctx) + conn := meta.(*conns.AWSClient).IoTClient(ctx) - output, err := conn.GetV2LoggingOptionsWithContext(ctx, &iot.GetV2LoggingOptionsInput{}) + output, err := conn.GetV2LoggingOptions(ctx, &iot.GetV2LoggingOptionsInput{}) if err != nil { - return sdkdiag.AppendErrorf(diags, "reading IoT logging options: %s", err) + return sdkdiag.AppendErrorf(diags, "reading IoT Logging Options (%s): %s", d.Id(), err) } d.Set("default_log_level", output.DefaultLogLevel) diff --git a/internal/service/iot/policy.go b/internal/service/iot/policy.go index 7604bb6cb8e..0a0bff650d0 100644 --- a/internal/service/iot/policy.go +++ b/internal/service/iot/policy.go @@ -11,15 +11,16 @@ import ( "strconv" "time" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/service/iot" - "github.com/hashicorp/aws-sdk-go-base/v2/awsv1shim/v2/tfawserr" + "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/service/iot" + awstypes "github.com/aws/aws-sdk-go-v2/service/iot/types" "github.com/hashicorp/terraform-plugin-sdk/v2/diag" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/retry" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/structure" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" "github.com/hashicorp/terraform-provider-aws/internal/conns" + "github.com/hashicorp/terraform-provider-aws/internal/errs" "github.com/hashicorp/terraform-provider-aws/internal/errs/sdkdiag" tftags "github.com/hashicorp/terraform-provider-aws/internal/tags" "github.com/hashicorp/terraform-provider-aws/internal/tfresource" @@ -27,9 +28,9 @@ import ( "github.com/hashicorp/terraform-provider-aws/names" ) -// @SDKResource("aws_iot_policy") +// @SDKResource("aws_iot_policy", name="Policy") // @Tags(identifierAttribute="arn") -func ResourcePolicy() *schema.Resource { +func resourcePolicy() *schema.Resource { return &schema.Resource{ CreateWithoutTimeout: resourcePolicyCreate, ReadWithoutTimeout: resourcePolicyRead, @@ -80,11 +81,11 @@ func ResourcePolicy() *schema.Resource { func resourcePolicyCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { var diags diag.Diagnostics - conn := meta.(*conns.AWSClient).IoTConn(ctx) + conn := meta.(*conns.AWSClient).IoTClient(ctx) policy, err := structure.NormalizeJsonString(d.Get(names.AttrPolicy).(string)) if err != nil { - return sdkdiag.AppendErrorf(diags, "policy (%s) is invalid JSON: %s", policy, err) + return sdkdiag.AppendFromErr(diags, err) } name := d.Get(names.AttrName).(string) @@ -94,22 +95,22 @@ func resourcePolicyCreate(ctx context.Context, d *schema.ResourceData, meta inte Tags: getTagsIn(ctx), } - output, err := conn.CreatePolicyWithContext(ctx, input) + output, err := conn.CreatePolicy(ctx, input) if err != nil { return sdkdiag.AppendErrorf(diags, "creating IoT Policy (%s): %s", name, err) } - d.SetId(aws.StringValue(output.PolicyName)) + d.SetId(aws.ToString(output.PolicyName)) return append(diags, resourcePolicyRead(ctx, d, meta)...) } func resourcePolicyRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { var diags diag.Diagnostics - conn := meta.(*conns.AWSClient).IoTConn(ctx) + conn := meta.(*conns.AWSClient).IoTClient(ctx) - output, err := FindPolicyByName(ctx, conn, d.Id()) + output, err := findPolicyByName(ctx, conn, d.Id()) if !d.IsNewResource() && tfresource.NotFound(err) { log.Printf("[WARN] IoT Policy (%s) not found, removing from state", d.Id()) @@ -125,7 +126,7 @@ func resourcePolicyRead(ctx context.Context, d *schema.ResourceData, meta interf d.Set("default_version_id", output.DefaultVersionId) d.Set(names.AttrName, output.PolicyName) - policyToSet, err := verify.PolicyToSet(d.Get(names.AttrPolicy).(string), aws.StringValue(output.PolicyDocument)) + policyToSet, err := verify.PolicyToSet(d.Get(names.AttrPolicy).(string), aws.ToString(output.PolicyDocument)) if err != nil { return sdkdiag.AppendFromErr(diags, err) } @@ -137,26 +138,26 @@ func resourcePolicyRead(ctx context.Context, d *schema.ResourceData, meta interf func resourcePolicyUpdate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { var diags diag.Diagnostics - conn := meta.(*conns.AWSClient).IoTConn(ctx) + conn := meta.(*conns.AWSClient).IoTClient(ctx) if d.HasChangesExcept(names.AttrTags, names.AttrTagsAll) { policy, err := structure.NormalizeJsonString(d.Get(names.AttrPolicy).(string)) if err != nil { - return sdkdiag.AppendErrorf(diags, "policy (%s) is invalid JSON: %s", policy, err) + return sdkdiag.AppendFromErr(diags, err) } input := &iot.CreatePolicyVersionInput{ PolicyDocument: aws.String(policy), PolicyName: aws.String(d.Id()), - SetAsDefault: aws.Bool(true), + SetAsDefault: true, } - _, errCreate := conn.CreatePolicyVersionWithContext(ctx, input) + _, errCreate := conn.CreatePolicyVersion(ctx, input) // "VersionsLimitExceededException: The policy ... already has the maximum number of versions (5)" - if tfawserr.ErrCodeEquals(errCreate, iot.ErrCodeVersionsLimitExceededException) { + if errs.IsA[*awstypes.VersionsLimitExceededException](errCreate) { // Prune the lowest version and retry. - policyVersions, err := FindPolicyVersionsByName(ctx, conn, d.Id()) + policyVersions, err := findPolicyVersionsByName(ctx, conn, d.Id()) if err != nil { return sdkdiag.AppendErrorf(diags, "reading IoT Policy (%s) versions: %s", d.Id(), err) @@ -165,11 +166,11 @@ func resourcePolicyUpdate(ctx context.Context, d *schema.ResourceData, meta inte var versionIDs []int for _, v := range policyVersions { - if aws.BoolValue(v.IsDefaultVersion) { + if v.IsDefaultVersion { continue } - v, err := strconv.Atoi(aws.StringValue(v.VersionId)) + v, err := strconv.Atoi(aws.ToString(v.VersionId)) if err != nil { continue @@ -183,15 +184,11 @@ func resourcePolicyUpdate(ctx context.Context, d *schema.ResourceData, meta inte slices.Sort(versionIDs) versionID := strconv.Itoa(versionIDs[0]) - if err := deletePolicyVersion(ctx, conn, d.Id(), versionID, d.Timeout(schema.TimeoutUpdate)); err != nil { + if err := deletePolicyVersion(ctx, conn, d.Id(), versionID); err != nil { return sdkdiag.AppendFromErr(diags, err) } - if err != nil { - return sdkdiag.AppendErrorf(diags, "waiting for IoT Policy (%s) version (%s) delete: %s", d.Id(), versionID, err) - } - - _, errCreate = conn.CreatePolicyVersionWithContext(ctx, input) + _, errCreate = conn.CreatePolicyVersion(ctx, input) } } @@ -199,14 +196,15 @@ func resourcePolicyUpdate(ctx context.Context, d *schema.ResourceData, meta inte return sdkdiag.AppendErrorf(diags, "updating IoT Policy (%s): %s", d.Id(), errCreate) } } + return append(diags, resourcePolicyRead(ctx, d, meta)...) } func resourcePolicyDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { var diags diag.Diagnostics - conn := meta.(*conns.AWSClient).IoTConn(ctx) + conn := meta.(*conns.AWSClient).IoTClient(ctx) - policyVersions, err := FindPolicyVersionsByName(ctx, conn, d.Id()) + policyVersions, err := findPolicyVersionsByName(ctx, conn, d.Id()) if tfresource.NotFound(err) { return diags @@ -218,31 +216,31 @@ func resourcePolicyDelete(ctx context.Context, d *schema.ResourceData, meta inte // Delete all non-default versions of the policy. for _, v := range policyVersions { - if aws.BoolValue(v.IsDefaultVersion) { + if v.IsDefaultVersion { continue } - if err := deletePolicyVersion(ctx, conn, d.Id(), aws.StringValue(v.VersionId), d.Timeout(schema.TimeoutDelete)); err != nil { + if err := deletePolicyVersion(ctx, conn, d.Id(), aws.ToString(v.VersionId)); err != nil { return sdkdiag.AppendFromErr(diags, err) } } // Delete default policy version. - if err := deletePolicy(ctx, conn, d.Id(), d.Timeout(schema.TimeoutDelete)); err != nil { + if err := deletePolicy(ctx, conn, d.Id()); err != nil { return sdkdiag.AppendFromErr(diags, err) } return diags } -func FindPolicyByName(ctx context.Context, conn *iot.IoT, name string) (*iot.GetPolicyOutput, error) { +func findPolicyByName(ctx context.Context, conn *iot.Client, name string) (*iot.GetPolicyOutput, error) { input := &iot.GetPolicyInput{ PolicyName: aws.String(name), } - output, err := conn.GetPolicyWithContext(ctx, input) + output, err := conn.GetPolicy(ctx, input) - if tfawserr.ErrCodeEquals(err, iot.ErrCodeResourceNotFoundException) { + if errs.IsA[*awstypes.ResourceNotFoundException](err) { return nil, &retry.NotFoundError{ LastError: err, LastRequest: input, @@ -260,14 +258,14 @@ func FindPolicyByName(ctx context.Context, conn *iot.IoT, name string) (*iot.Get return output, nil } -func FindPolicyVersionsByName(ctx context.Context, conn *iot.IoT, name string) ([]*iot.PolicyVersion, error) { +func findPolicyVersionsByName(ctx context.Context, conn *iot.Client, name string) ([]awstypes.PolicyVersion, error) { input := &iot.ListPolicyVersionsInput{ PolicyName: aws.String(name), } - output, err := conn.ListPolicyVersionsWithContext(ctx, input) + output, err := conn.ListPolicyVersions(ctx, input) - if tfawserr.ErrCodeEquals(err, iot.ErrCodeResourceNotFoundException) { + if errs.IsA[*awstypes.ResourceNotFoundException](err) { return nil, &retry.NotFoundError{ LastError: err, LastRequest: input, @@ -285,16 +283,17 @@ func FindPolicyVersionsByName(ctx context.Context, conn *iot.IoT, name string) ( return output.PolicyVersions, nil } -func deletePolicy(ctx context.Context, conn *iot.IoT, name string, timeout time.Duration) error { +func deletePolicy(ctx context.Context, conn *iot.Client, name string) error { input := &iot.DeletePolicyInput{ PolicyName: aws.String(name), } - _, err := tfresource.RetryWhenAWSErrCodeEquals(ctx, timeout, func() (interface{}, error) { - return conn.DeletePolicyWithContext(ctx, input) - }, iot.ErrCodeDeleteConflictException) + _, err := tfresource.RetryWhenIsA[*awstypes.DeleteConflictException](ctx, propagationTimeout, + func() (interface{}, error) { + return conn.DeletePolicy(ctx, input) + }) - if tfawserr.ErrCodeEquals(err, iot.ErrCodeResourceNotFoundException) { + if errs.IsA[*awstypes.ResourceNotFoundException](err) { return nil } @@ -305,17 +304,18 @@ func deletePolicy(ctx context.Context, conn *iot.IoT, name string, timeout time. return nil } -func deletePolicyVersion(ctx context.Context, conn *iot.IoT, name, versionID string, timeout time.Duration) error { +func deletePolicyVersion(ctx context.Context, conn *iot.Client, name, versionID string) error { input := &iot.DeletePolicyVersionInput{ PolicyName: aws.String(name), PolicyVersionId: aws.String(versionID), } - _, err := tfresource.RetryWhenAWSErrCodeEquals(ctx, timeout, func() (interface{}, error) { - return conn.DeletePolicyVersionWithContext(ctx, input) - }, iot.ErrCodeDeleteConflictException) + _, err := tfresource.RetryWhenIsA[*awstypes.DeleteConflictException](ctx, propagationTimeout, + func() (interface{}, error) { + return conn.DeletePolicyVersion(ctx, input) + }) - if tfawserr.ErrCodeEquals(err, iot.ErrCodeResourceNotFoundException) { + if errs.IsA[*awstypes.ResourceNotFoundException](err) { return nil } diff --git a/internal/service/iot/policy_attachment.go b/internal/service/iot/policy_attachment.go index c57923c5595..2b294b5fea4 100644 --- a/internal/service/iot/policy_attachment.go +++ b/internal/service/iot/policy_attachment.go @@ -9,21 +9,21 @@ import ( "log" "strings" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/service/iot" - "github.com/hashicorp/aws-sdk-go-base/v2/awsv1shim/v2/tfawserr" + "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/service/iot" + awstypes "github.com/aws/aws-sdk-go-v2/service/iot/types" "github.com/hashicorp/terraform-plugin-sdk/v2/diag" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/retry" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/terraform-provider-aws/internal/conns" + "github.com/hashicorp/terraform-provider-aws/internal/errs" "github.com/hashicorp/terraform-provider-aws/internal/errs/sdkdiag" - tfslices "github.com/hashicorp/terraform-provider-aws/internal/slices" "github.com/hashicorp/terraform-provider-aws/internal/tfresource" "github.com/hashicorp/terraform-provider-aws/names" ) -// @SDKResource("aws_iot_policy_attachment") -func ResourcePolicyAttachment() *schema.Resource { +// @SDKResource("aws_iot_policy_attachment", nmw="Policy Attachment") +func resourcePolicyAttachment() *schema.Resource { return &schema.Resource{ CreateWithoutTimeout: resourcePolicyAttachmentCreate, ReadWithoutTimeout: resourcePolicyAttachmentRead, @@ -46,7 +46,7 @@ func ResourcePolicyAttachment() *schema.Resource { func resourcePolicyAttachmentCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { var diags diag.Diagnostics - conn := meta.(*conns.AWSClient).IoTConn(ctx) + conn := meta.(*conns.AWSClient).IoTClient(ctx) policyName := d.Get(names.AttrPolicy).(string) target := d.Get(names.AttrTarget).(string) @@ -56,7 +56,7 @@ func resourcePolicyAttachmentCreate(ctx context.Context, d *schema.ResourceData, Target: aws.String(target), } - _, err := conn.AttachPolicyWithContext(ctx, input) + _, err := conn.AttachPolicy(ctx, input) if err != nil { return sdkdiag.AppendErrorf(diags, "creating IoT Policy Attachment (%s): %s", id, err) @@ -69,14 +69,14 @@ func resourcePolicyAttachmentCreate(ctx context.Context, d *schema.ResourceData, func resourcePolicyAttachmentRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { var diags diag.Diagnostics - conn := meta.(*conns.AWSClient).IoTConn(ctx) + conn := meta.(*conns.AWSClient).IoTClient(ctx) policyName, target, err := policyAttachmentParseResourceID(d.Id()) if err != nil { return sdkdiag.AppendFromErr(diags, err) } - _, err = FindAttachedPolicyByTwoPartKey(ctx, conn, policyName, target) + _, err = findAttachedPolicyByTwoPartKey(ctx, conn, policyName, target) if !d.IsNewResource() && tfresource.NotFound(err) { log.Printf("[WARN] IoT Policy Attachment (%s) not found, removing from state", d.Id()) @@ -93,7 +93,7 @@ func resourcePolicyAttachmentRead(ctx context.Context, d *schema.ResourceData, m func resourcePolicyAttachmentDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { var diags diag.Diagnostics - conn := meta.(*conns.AWSClient).IoTConn(ctx) + conn := meta.(*conns.AWSClient).IoTClient(ctx) policyName, target, err := policyAttachmentParseResourceID(d.Id()) if err != nil { @@ -101,14 +101,12 @@ func resourcePolicyAttachmentDelete(ctx context.Context, d *schema.ResourceData, } log.Printf("[DEBUG] Deleting IoT Policy Attachment: %s", d.Id()) - _, err = conn.DetachPolicyWithContext(ctx, &iot.DetachPolicyInput{ + _, err = conn.DetachPolicy(ctx, &iot.DetachPolicyInput{ PolicyName: aws.String(policyName), Target: aws.String(target), }) - // DetachPolicy doesn't return an error if the policy doesn't exist, - // but it returns an error if the Target is not found. - if tfawserr.ErrMessageContains(err, iot.ErrCodeInvalidRequestException, "Invalid Target") { + if errs.IsA[*awstypes.ResourceNotFoundException](err) { return diags } @@ -119,54 +117,45 @@ func resourcePolicyAttachmentDelete(ctx context.Context, d *schema.ResourceData, return diags } -func FindAttachedPolicyByTwoPartKey(ctx context.Context, conn *iot.IoT, policyName, target string) (*iot.Policy, error) { +func findAttachedPolicyByTwoPartKey(ctx context.Context, conn *iot.Client, policyName, target string) (*awstypes.Policy, error) { input := &iot.ListAttachedPoliciesInput{ - PageSize: aws.Int64(250), - Recursive: aws.Bool(false), + PageSize: aws.Int32(250), + Recursive: false, Target: aws.String(target), } - return findAttachedPolicy(ctx, conn, input, func(v *iot.Policy) bool { - return aws.StringValue(v.PolicyName) == policyName - }) + return findAttachedPolicy(ctx, conn, input) } -func findAttachedPolicy(ctx context.Context, conn *iot.IoT, input *iot.ListAttachedPoliciesInput, filter tfslices.Predicate[*iot.Policy]) (*iot.Policy, error) { - output, err := findAttachedPolicies(ctx, conn, input, filter) +func findAttachedPolicy(ctx context.Context, conn *iot.Client, input *iot.ListAttachedPoliciesInput) (*awstypes.Policy, error) { + output, err := findAttachedPolicies(ctx, conn, input) if err != nil { return nil, err } - return tfresource.AssertSinglePtrResult(output) + return tfresource.AssertFirstValueResult(output) } -func findAttachedPolicies(ctx context.Context, conn *iot.IoT, input *iot.ListAttachedPoliciesInput, filter tfslices.Predicate[*iot.Policy]) ([]*iot.Policy, error) { - var output []*iot.Policy +func findAttachedPolicies(ctx context.Context, conn *iot.Client, input *iot.ListAttachedPoliciesInput) ([]awstypes.Policy, error) { + var output []awstypes.Policy - err := conn.ListAttachedPoliciesPagesWithContext(ctx, input, func(page *iot.ListAttachedPoliciesOutput, lastPage bool) bool { - if page == nil { - return !lastPage - } + pages := iot.NewListAttachedPoliciesPaginator(conn, input) + for pages.HasMorePages() { + page, err := pages.NextPage(ctx) - for _, v := range page.Policies { - if v != nil && filter(v) { - output = append(output, v) + if errs.IsA[*awstypes.ResourceNotFoundException](err) { + return nil, &retry.NotFoundError{ + LastError: err, + LastRequest: input, } } - return !lastPage - }) - - if tfawserr.ErrCodeEquals(err, iot.ErrCodeResourceNotFoundException) { - return nil, &retry.NotFoundError{ - LastError: err, - LastRequest: input, + if err != nil { + return nil, err } - } - if err != nil { - return nil, err + output = append(output, page.Policies...) } return output, nil diff --git a/internal/service/iot/policy_attachment_test.go b/internal/service/iot/policy_attachment_test.go index 96731013e61..6ae5dd40657 100644 --- a/internal/service/iot/policy_attachment_test.go +++ b/internal/service/iot/policy_attachment_test.go @@ -64,7 +64,7 @@ func TestAccIoTPolicyAttachment_basic(t *testing.T) { func testAccCheckPolicyAttchmentDestroy(ctx context.Context) resource.TestCheckFunc { return func(s *terraform.State) error { - conn := acctest.Provider.Meta().(*conns.AWSClient).IoTConn(ctx) + conn := acctest.Provider.Meta().(*conns.AWSClient).IoTClient(ctx) for _, rs := range s.RootModule().Resources { if rs.Type != "aws_iot_policy_attachment" { continue @@ -94,7 +94,7 @@ func testAccCheckPolicyAttachmentExists(ctx context.Context, n string) resource. return fmt.Errorf("Not found: %s", n) } - conn := acctest.Provider.Meta().(*conns.AWSClient).IoTConn(ctx) + conn := acctest.Provider.Meta().(*conns.AWSClient).IoTClient(ctx) _, err := tfiot.FindAttachedPolicyByTwoPartKey(ctx, conn, rs.Primary.Attributes[names.AttrPolicy], rs.Primary.Attributes[names.AttrTarget]) diff --git a/internal/service/iot/policy_test.go b/internal/service/iot/policy_test.go index 3ba87a59794..7e2faab3cf9 100644 --- a/internal/service/iot/policy_test.go +++ b/internal/service/iot/policy_test.go @@ -8,8 +8,9 @@ import ( "fmt" "testing" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/service/iot" + "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/service/iot" + awstypes "github.com/aws/aws-sdk-go-v2/service/iot/types" "github.com/google/go-cmp/cmp" "github.com/google/go-cmp/cmp/cmpopts" sdkacctest "github.com/hashicorp/terraform-plugin-testing/helper/acctest" @@ -244,7 +245,7 @@ func TestAccIoTPolicy_prune(t *testing.T) { func testAccCheckPolicyDestroy(ctx context.Context) resource.TestCheckFunc { return func(s *terraform.State) error { - conn := acctest.Provider.Meta().(*conns.AWSClient).IoTConn(ctx) + conn := acctest.Provider.Meta().(*conns.AWSClient).IoTClient(ctx) for _, rs := range s.RootModule().Resources { if rs.Type != "aws_iot_policy" { @@ -275,7 +276,7 @@ func testAccCheckPolicyExists(ctx context.Context, n string, v *iot.GetPolicyOut return fmt.Errorf("Not found: %s", n) } - conn := acctest.Provider.Meta().(*conns.AWSClient).IoTConn(ctx) + conn := acctest.Provider.Meta().(*conns.AWSClient).IoTClient(ctx) output, err := tfiot.FindPolicyByName(ctx, conn, rs.Primary.ID) @@ -296,7 +297,7 @@ func testAccCheckPolicyVersionIDs(ctx context.Context, n string, want []string) return fmt.Errorf("Not found: %s", n) } - conn := acctest.Provider.Meta().(*conns.AWSClient).IoTConn(ctx) + conn := acctest.Provider.Meta().(*conns.AWSClient).IoTClient(ctx) output, err := tfiot.FindPolicyVersionsByName(ctx, conn, rs.Primary.ID) @@ -304,8 +305,8 @@ func testAccCheckPolicyVersionIDs(ctx context.Context, n string, want []string) return err } - got := tfslices.ApplyToAll(output, func(v *iot.PolicyVersion) string { - return aws.StringValue(v.VersionId) + got := tfslices.ApplyToAll(output, func(v awstypes.PolicyVersion) string { + return aws.ToString(v.VersionId) }) if !cmp.Equal(got, want, cmpopts.SortSlices(func(i, j string) bool { diff --git a/internal/service/iot/provisioning_template.go b/internal/service/iot/provisioning_template.go index d9dccea32fc..dcaa20c0f3f 100644 --- a/internal/service/iot/provisioning_template.go +++ b/internal/service/iot/provisioning_template.go @@ -8,14 +8,16 @@ import ( "log" "github.com/YakDriver/regexache" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/service/iot" - "github.com/hashicorp/aws-sdk-go-base/v2/awsv1shim/v2/tfawserr" + "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/service/iot" + awstypes "github.com/aws/aws-sdk-go-v2/service/iot/types" "github.com/hashicorp/terraform-plugin-sdk/v2/diag" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/retry" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" "github.com/hashicorp/terraform-provider-aws/internal/conns" + "github.com/hashicorp/terraform-provider-aws/internal/enum" + "github.com/hashicorp/terraform-provider-aws/internal/errs" "github.com/hashicorp/terraform-provider-aws/internal/errs/sdkdiag" tftags "github.com/hashicorp/terraform-provider-aws/internal/tags" "github.com/hashicorp/terraform-provider-aws/internal/tfresource" @@ -23,19 +25,21 @@ import ( "github.com/hashicorp/terraform-provider-aws/names" ) +type provisioningHookPayloadVersion string + const ( - provisioningHookPayloadVersion2020_04_01 = "2020-04-01" + provisioningHookPayloadVersion2020_04_01 provisioningHookPayloadVersion = "2020-04-01" ) -func provisioningHookPayloadVersion_Values() []string { - return []string{ +func (provisioningHookPayloadVersion) Values() []provisioningHookPayloadVersion { + return []provisioningHookPayloadVersion{ provisioningHookPayloadVersion2020_04_01, } } // @SDKResource("aws_iot_provisioning_template", name="Provisioning Template") // @Tags(identifierAttribute="arn") -func ResourceProvisioningTemplate() *schema.Resource { +func resourceProvisioningTemplate() *schema.Resource { return &schema.Resource{ CreateWithoutTimeout: resourceProvisioningTemplateCreate, ReadWithoutTimeout: resourceProvisioningTemplateRead, @@ -81,10 +85,10 @@ func ResourceProvisioningTemplate() *schema.Resource { Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ "payload_version": { - Type: schema.TypeString, - Optional: true, - Default: provisioningHookPayloadVersion2020_04_01, - ValidateFunc: validation.StringInSlice(provisioningHookPayloadVersion_Values(), false), + Type: schema.TypeString, + Optional: true, + Default: provisioningHookPayloadVersion2020_04_01, + ValidateDiagFunc: enum.Validate[provisioningHookPayloadVersion](), }, names.AttrTargetARN: { Type: schema.TypeString, @@ -110,11 +114,11 @@ func ResourceProvisioningTemplate() *schema.Resource { ), }, names.AttrType: { - Type: schema.TypeString, - Optional: true, - Computed: true, - ForceNew: true, - ValidateFunc: validation.StringInSlice(iot.TemplateType_Values(), false), + Type: schema.TypeString, + Optional: true, + Computed: true, + ForceNew: true, + ValidateDiagFunc: enum.Validate[awstypes.TemplateType](), }, }, @@ -124,8 +128,7 @@ func ResourceProvisioningTemplate() *schema.Resource { func resourceProvisioningTemplateCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { var diags diag.Diagnostics - - conn := meta.(*conns.AWSClient).IoTConn(ctx) + conn := meta.(*conns.AWSClient).IoTClient(ctx) name := d.Get(names.AttrName).(string) input := &iot.CreateProvisioningTemplateInput{ @@ -150,31 +153,29 @@ func resourceProvisioningTemplateCreate(ctx context.Context, d *schema.ResourceD input.TemplateBody = aws.String(v.(string)) } - if v, ok := d.Get(names.AttrType).(string); ok && v != "" { - input.Type = aws.String(v) + if v, ok := d.Get(names.AttrType).(awstypes.TemplateType); ok && v != "" { + input.Type = v } - outputRaw, err := tfresource.RetryWhenAWSErrMessageContains(ctx, propagationTimeout, + outputRaw, err := tfresource.RetryWhenIsA[*awstypes.InvalidRequestException](ctx, propagationTimeout, func() (interface{}, error) { - return conn.CreateProvisioningTemplateWithContext(ctx, input) - }, - iot.ErrCodeInvalidRequestException, "The provisioning role cannot be assumed by AWS IoT") + return conn.CreateProvisioningTemplate(ctx, input) + }) if err != nil { return sdkdiag.AppendErrorf(diags, "creating IoT Provisioning Template (%s): %s", name, err) } - d.SetId(aws.StringValue(outputRaw.(*iot.CreateProvisioningTemplateOutput).TemplateName)) + d.SetId(aws.ToString(outputRaw.(*iot.CreateProvisioningTemplateOutput).TemplateName)) return append(diags, resourceProvisioningTemplateRead(ctx, d, meta)...) } func resourceProvisioningTemplateRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { var diags diag.Diagnostics + conn := meta.(*conns.AWSClient).IoTClient(ctx) - conn := meta.(*conns.AWSClient).IoTConn(ctx) - - output, err := FindProvisioningTemplateByName(ctx, conn, d.Id()) + output, err := findProvisioningTemplateByName(ctx, conn, d.Id()) if !d.IsNewResource() && tfresource.NotFound(err) { log.Printf("[WARN] IoT Provisioning Template %s not found, removing from state", d.Id()) @@ -207,25 +208,23 @@ func resourceProvisioningTemplateRead(ctx context.Context, d *schema.ResourceDat func resourceProvisioningTemplateUpdate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { var diags diag.Diagnostics - - conn := meta.(*conns.AWSClient).IoTConn(ctx) + conn := meta.(*conns.AWSClient).IoTClient(ctx) if d.HasChange("template_body") { input := &iot.CreateProvisioningTemplateVersionInput{ - SetAsDefault: aws.Bool(true), + SetAsDefault: true, TemplateBody: aws.String(d.Get("template_body").(string)), TemplateName: aws.String(d.Id()), } - log.Printf("[DEBUG] Creating IoT Provisioning Template version: %s", input) - _, err := conn.CreateProvisioningTemplateVersionWithContext(ctx, input) + _, err := conn.CreateProvisioningTemplateVersion(ctx, input) if err != nil { return sdkdiag.AppendErrorf(diags, "creating IoT Provisioning Template (%s) version: %s", d.Id(), err) } } - if d.HasChanges(names.AttrDescription, names.AttrEnabled, "provisioning_role_arn") { + if d.HasChanges(names.AttrDescription, names.AttrEnabled, "provisioning_role_arn", "pre_provisioning_hook") { input := &iot.UpdateProvisioningTemplateInput{ Description: aws.String(d.Get(names.AttrDescription).(string)), Enabled: aws.Bool(d.Get(names.AttrEnabled).(bool)), @@ -233,12 +232,14 @@ func resourceProvisioningTemplateUpdate(ctx context.Context, d *schema.ResourceD TemplateName: aws.String(d.Id()), } - log.Printf("[DEBUG] Updating IoT Provisioning Template: %s", input) - _, err := tfresource.RetryWhenAWSErrMessageContains(ctx, propagationTimeout, + if v, ok := d.GetOk("pre_provisioning_hook"); ok && len(v.([]interface{})) > 0 && v.([]interface{})[0] != nil { + input.PreProvisioningHook = expandProvisioningHook(v.([]interface{})[0].(map[string]interface{})) + } + + _, err := tfresource.RetryWhenIsA[*awstypes.InvalidRequestException](ctx, propagationTimeout, func() (interface{}, error) { - return conn.UpdateProvisioningTemplateWithContext(ctx, input) - }, - iot.ErrCodeInvalidRequestException, "The provisioning role cannot be assumed by AWS IoT") + return conn.UpdateProvisioningTemplate(ctx, input) + }) if err != nil { return sdkdiag.AppendErrorf(diags, "updating IoT Provisioning Template (%s): %s", d.Id(), err) @@ -251,14 +252,14 @@ func resourceProvisioningTemplateUpdate(ctx context.Context, d *schema.ResourceD func resourceProvisioningTemplateDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { var diags diag.Diagnostics - conn := meta.(*conns.AWSClient).IoTConn(ctx) + conn := meta.(*conns.AWSClient).IoTClient(ctx) log.Printf("[INFO] Deleting IoT Provisioning Template: %s", d.Id()) - _, err := conn.DeleteProvisioningTemplateWithContext(ctx, &iot.DeleteProvisioningTemplateInput{ + _, err := conn.DeleteProvisioningTemplate(ctx, &iot.DeleteProvisioningTemplateInput{ TemplateName: aws.String(d.Id()), }) - if tfawserr.ErrCodeEquals(err, iot.ErrCodeResourceNotFoundException) { + if errs.IsA[*awstypes.ResourceNotFoundException](err) { return diags } @@ -269,7 +270,7 @@ func resourceProvisioningTemplateDelete(ctx context.Context, d *schema.ResourceD return diags } -func flattenProvisioningHook(apiObject *iot.ProvisioningHook) map[string]interface{} { +func flattenProvisioningHook(apiObject *awstypes.ProvisioningHook) map[string]interface{} { if apiObject == nil { return nil } @@ -277,22 +278,22 @@ func flattenProvisioningHook(apiObject *iot.ProvisioningHook) map[string]interfa tfMap := map[string]interface{}{} if v := apiObject.PayloadVersion; v != nil { - tfMap["payload_version"] = aws.StringValue(v) + tfMap["payload_version"] = aws.ToString(v) } if v := apiObject.TargetArn; v != nil { - tfMap[names.AttrTargetARN] = aws.StringValue(v) + tfMap[names.AttrTargetARN] = aws.ToString(v) } return tfMap } -func expandProvisioningHook(tfMap map[string]interface{}) *iot.ProvisioningHook { +func expandProvisioningHook(tfMap map[string]interface{}) *awstypes.ProvisioningHook { if tfMap == nil { return nil } - apiObject := &iot.ProvisioningHook{} + apiObject := &awstypes.ProvisioningHook{} if v, ok := tfMap["payload_version"].(string); ok && v != "" { apiObject.PayloadVersion = aws.String(v) @@ -305,14 +306,14 @@ func expandProvisioningHook(tfMap map[string]interface{}) *iot.ProvisioningHook return apiObject } -func FindProvisioningTemplateByName(ctx context.Context, conn *iot.IoT, name string) (*iot.DescribeProvisioningTemplateOutput, error) { +func findProvisioningTemplateByName(ctx context.Context, conn *iot.Client, name string) (*iot.DescribeProvisioningTemplateOutput, error) { input := &iot.DescribeProvisioningTemplateInput{ TemplateName: aws.String(name), } - output, err := conn.DescribeProvisioningTemplateWithContext(ctx, input) + output, err := conn.DescribeProvisioningTemplate(ctx, input) - if tfawserr.ErrCodeEquals(err, iot.ErrCodeResourceNotFoundException) { + if errs.IsA[*awstypes.ResourceNotFoundException](err) { return nil, &retry.NotFoundError{ LastError: err, LastRequest: input, diff --git a/internal/service/iot/provisioning_template_test.go b/internal/service/iot/provisioning_template_test.go index 45848a40716..f4001612a71 100644 --- a/internal/service/iot/provisioning_template_test.go +++ b/internal/service/iot/provisioning_template_test.go @@ -8,8 +8,8 @@ import ( "fmt" "testing" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/service/iot" + "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/service/iot" sdkacctest "github.com/hashicorp/terraform-plugin-testing/helper/acctest" "github.com/hashicorp/terraform-plugin-testing/helper/resource" "github.com/hashicorp/terraform-plugin-testing/terraform" @@ -167,7 +167,7 @@ func TestAccIoTProvisioningTemplate_update(t *testing.T) { resource.TestCheckResourceAttr(resourceName, names.AttrDescription, "For testing"), resource.TestCheckResourceAttr(resourceName, names.AttrEnabled, acctest.CtTrue), resource.TestCheckResourceAttr(resourceName, names.AttrName, rName), - resource.TestCheckResourceAttr(resourceName, "pre_provisioning_hook.#", acctest.Ct0), + resource.TestCheckResourceAttr(resourceName, "pre_provisioning_hook.#", acctest.Ct1), resource.TestCheckResourceAttrSet(resourceName, "provisioning_role_arn"), resource.TestCheckResourceAttr(resourceName, acctest.CtTagsPercent, acctest.Ct0), resource.TestCheckResourceAttrSet(resourceName, "template_body"), @@ -188,7 +188,7 @@ func testAccCheckProvisioningTemplateExists(ctx context.Context, n string) resou return fmt.Errorf("No IoT Provisioning Template ID is set") } - conn := acctest.Provider.Meta().(*conns.AWSClient).IoTConn(ctx) + conn := acctest.Provider.Meta().(*conns.AWSClient).IoTClient(ctx) _, err := tfiot.FindProvisioningTemplateByName(ctx, conn, rs.Primary.ID) @@ -198,7 +198,7 @@ func testAccCheckProvisioningTemplateExists(ctx context.Context, n string) resou func testAccCheckProvisioningTemplateDestroy(ctx context.Context) resource.TestCheckFunc { return func(s *terraform.State) error { - conn := acctest.Provider.Meta().(*conns.AWSClient).IoTConn(ctx) + conn := acctest.Provider.Meta().(*conns.AWSClient).IoTClient(ctx) for _, rs := range s.RootModule().Resources { if rs.Type != "aws_iot_provisioning_template" { @@ -224,25 +224,16 @@ func testAccCheckProvisioningTemplateDestroy(ctx context.Context) resource.TestC func testAccCheckProvisioningTemplateNumVersions(ctx context.Context, name string, want int) resource.TestCheckFunc { return func(s *terraform.State) error { - conn := acctest.Provider.Meta().(*conns.AWSClient).IoTConn(ctx) + conn := acctest.Provider.Meta().(*conns.AWSClient).IoTClient(ctx) var got int - err := conn.ListProvisioningTemplateVersionsPagesWithContext(ctx, &iot.ListProvisioningTemplateVersionsInput{TemplateName: aws.String(name)}, - func(page *iot.ListProvisioningTemplateVersionsOutput, lastPage bool) bool { - if page == nil { - return !lastPage - } - - got += len(page.Versions) - - return !lastPage - }) + out, err := conn.ListProvisioningTemplateVersions(ctx, &iot.ListProvisioningTemplateVersionsInput{TemplateName: aws.String(name)}) if err != nil { return err } - if got != want { + if len(out.Versions) != want { return fmt.Errorf("Incorrect version count for IoT Provisioning Template %s; got: %d, want: %d", name, got, want) } @@ -396,13 +387,20 @@ resource "aws_iot_provisioning_template" "test" { } func testAccProvisioningTemplateConfig_updated(rName string) string { - return acctest.ConfigCompose(testAccProvisioningTemplateBaseConfig(rName), fmt.Sprintf(` + return acctest.ConfigCompose( + testAccProvisioningTemplateBaseConfig(rName), + testAccProvisioningTemplateConfig_preProvisioningHook(rName), + fmt.Sprintf(` resource "aws_iot_provisioning_template" "test" { name = %[1]q provisioning_role_arn = aws_iam_role.test.arn description = "For testing" enabled = true + pre_provisioning_hook { + target_arn = aws_lambda_function.test.arn + } + template_body = jsonencode({ Parameters = { SerialNumber = { Type = "String" } @@ -428,3 +426,43 @@ resource "aws_iot_provisioning_template" "test" { } `, rName)) } + +func testAccProvisioningTemplateConfig_preProvisioningHook(rName string) string { + return fmt.Sprintf(` +resource "aws_iam_role" "test2" { + name = "%[1]s-2" + + assume_role_policy = < 0 { return tags @@ -91,7 +91,7 @@ func getTagsIn(ctx context.Context) []*iot.Tag { } // setTagsOut sets iot service tags in Context. -func setTagsOut(ctx context.Context, tags []*iot.Tag) { +func setTagsOut(ctx context.Context, tags []awstypes.Tag) { if inContext, ok := tftags.FromContext(ctx); ok { inContext.TagsOut = option.Some(KeyValueTags(ctx, tags)) } @@ -100,7 +100,7 @@ func setTagsOut(ctx context.Context, tags []*iot.Tag) { // updateTags updates iot service tags. // The identifier is typically the Amazon Resource Name (ARN), although // it may also be a different identifier depending on the service. -func updateTags(ctx context.Context, conn iotiface.IoTAPI, identifier string, oldTagsMap, newTagsMap any) error { +func updateTags(ctx context.Context, conn *iot.Client, identifier string, oldTagsMap, newTagsMap any, optFns ...func(*iot.Options)) error { oldTags := tftags.New(ctx, oldTagsMap) newTags := tftags.New(ctx, newTagsMap) @@ -111,10 +111,10 @@ func updateTags(ctx context.Context, conn iotiface.IoTAPI, identifier string, ol if len(removedTags) > 0 { input := &iot.UntagResourceInput{ ResourceArn: aws.String(identifier), - TagKeys: aws.StringSlice(removedTags.Keys()), + TagKeys: removedTags.Keys(), } - _, err := conn.UntagResourceWithContext(ctx, input) + _, err := conn.UntagResource(ctx, input, optFns...) if err != nil { return fmt.Errorf("untagging resource (%s): %w", identifier, err) @@ -129,7 +129,7 @@ func updateTags(ctx context.Context, conn iotiface.IoTAPI, identifier string, ol Tags: Tags(updatedTags), } - _, err := conn.TagResourceWithContext(ctx, input) + _, err := conn.TagResource(ctx, input, optFns...) if err != nil { return fmt.Errorf("tagging resource (%s): %w", identifier, err) @@ -142,5 +142,5 @@ func updateTags(ctx context.Context, conn iotiface.IoTAPI, identifier string, ol // UpdateTags updates iot service tags. // It is called from outside this package. func (p *servicePackage) UpdateTags(ctx context.Context, meta any, identifier string, oldTags, newTags any) error { - return updateTags(ctx, meta.(*conns.AWSClient).IoTConn(ctx), identifier, oldTags, newTags) + return updateTags(ctx, meta.(*conns.AWSClient).IoTClient(ctx), identifier, oldTags, newTags) } diff --git a/internal/service/iot/test-fixtures/lambda-preprovisioninghook.js b/internal/service/iot/test-fixtures/lambda-preprovisioninghook.js new file mode 100644 index 00000000000..dfdb45ef98c --- /dev/null +++ b/internal/service/iot/test-fixtures/lambda-preprovisioninghook.js @@ -0,0 +1,16 @@ +/** + * Copyright (c) HashiCorp, Inc. + * SPDX-License-Identifier: MPL-2.0 + */ + +//https://docs.aws.amazon.com/iot/latest/developerguide/pre-provisioning-hook.html#pre-provisioning-example +exports.handler = function (event, context, callback) { + console.log(JSON.stringify(event, null, 2)); + var reply = { + allowProvisioning: true, + parameterOverrides: { + DeviceLocation: 'Seattle' + } + }; + callback(null, reply); +} diff --git a/internal/service/iot/test-fixtures/lambda-preprovisioninghook.zip b/internal/service/iot/test-fixtures/lambda-preprovisioninghook.zip new file mode 100644 index 00000000000..87eb4dcd157 Binary files /dev/null and b/internal/service/iot/test-fixtures/lambda-preprovisioninghook.zip differ diff --git a/internal/service/iot/thing.go b/internal/service/iot/thing.go index bb4bdf9d722..a712f475a97 100644 --- a/internal/service/iot/thing.go +++ b/internal/service/iot/thing.go @@ -7,21 +7,23 @@ import ( "context" "log" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/service/iot" - "github.com/hashicorp/aws-sdk-go-base/v2/awsv1shim/v2/tfawserr" + "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/service/iot" + awstypes "github.com/aws/aws-sdk-go-v2/service/iot/types" "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/retry" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" "github.com/hashicorp/terraform-provider-aws/internal/conns" + "github.com/hashicorp/terraform-provider-aws/internal/errs" "github.com/hashicorp/terraform-provider-aws/internal/errs/sdkdiag" "github.com/hashicorp/terraform-provider-aws/internal/flex" "github.com/hashicorp/terraform-provider-aws/internal/tfresource" "github.com/hashicorp/terraform-provider-aws/names" ) -// @SDKResource("aws_iot_thing") -func ResourceThing() *schema.Resource { +// @SDKResource("aws_iot_thing", name="Thing") +func resourceThing() *schema.Resource { return &schema.Resource{ CreateWithoutTimeout: resourceThingCreate, ReadWithoutTimeout: resourceThingRead, @@ -67,7 +69,7 @@ func ResourceThing() *schema.Resource { func resourceThingCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { var diags diag.Diagnostics - conn := meta.(*conns.AWSClient).IoTConn(ctx) + conn := meta.(*conns.AWSClient).IoTClient(ctx) name := d.Get(names.AttrName).(string) input := &iot.CreateThingInput{ @@ -75,8 +77,8 @@ func resourceThingCreate(ctx context.Context, d *schema.ResourceData, meta inter } if v, ok := d.GetOk(names.AttrAttributes); ok && len(v.(map[string]interface{})) > 0 { - input.AttributePayload = &iot.AttributePayload{ - Attributes: flex.ExpandStringMap(v.(map[string]interface{})), + input.AttributePayload = &awstypes.AttributePayload{ + Attributes: flex.ExpandStringValueMap(v.(map[string]interface{})), } } @@ -84,23 +86,22 @@ func resourceThingCreate(ctx context.Context, d *schema.ResourceData, meta inter input.ThingTypeName = aws.String(v.(string)) } - log.Printf("[DEBUG] Creating IoT Thing: %s", input) - output, err := conn.CreateThingWithContext(ctx, input) + output, err := conn.CreateThing(ctx, input) if err != nil { return sdkdiag.AppendErrorf(diags, "creating IoT Thing (%s): %s", name, err) } - d.SetId(aws.StringValue(output.ThingName)) + d.SetId(aws.ToString(output.ThingName)) return append(diags, resourceThingRead(ctx, d, meta)...) } func resourceThingRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { var diags diag.Diagnostics - conn := meta.(*conns.AWSClient).IoTConn(ctx) + conn := meta.(*conns.AWSClient).IoTClient(ctx) - output, err := FindThingByName(ctx, conn, d.Id()) + output, err := findThingByName(ctx, conn, d.Id()) if !d.IsNewResource() && tfresource.NotFound(err) { log.Printf("[WARN] IoT Thing (%s) not found, removing from state", d.Id()) @@ -115,7 +116,7 @@ func resourceThingRead(ctx context.Context, d *schema.ResourceData, meta interfa d.Set(names.AttrARN, output.ThingArn) d.Set("default_client_id", output.DefaultClientId) d.Set(names.AttrName, output.ThingName) - d.Set(names.AttrAttributes, aws.StringValueMap(output.Attributes)) + d.Set(names.AttrAttributes, aws.StringMap(output.Attributes)) d.Set("thing_type_name", output.ThingTypeName) d.Set(names.AttrVersion, output.Version) @@ -124,20 +125,20 @@ func resourceThingRead(ctx context.Context, d *schema.ResourceData, meta interfa func resourceThingUpdate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { var diags diag.Diagnostics - conn := meta.(*conns.AWSClient).IoTConn(ctx) + conn := meta.(*conns.AWSClient).IoTClient(ctx) input := &iot.UpdateThingInput{ ThingName: aws.String(d.Get(names.AttrName).(string)), } if d.HasChange(names.AttrAttributes) { - attributes := map[string]*string{} + attributes := map[string]string{} if v, ok := d.GetOk(names.AttrAttributes); ok && len(v.(map[string]interface{})) > 0 { - attributes = flex.ExpandStringMap(v.(map[string]interface{})) + attributes = flex.ExpandStringValueMap(v.(map[string]interface{})) } - input.AttributePayload = &iot.AttributePayload{ + input.AttributePayload = &awstypes.AttributePayload{ Attributes: attributes, } } @@ -146,12 +147,11 @@ func resourceThingUpdate(ctx context.Context, d *schema.ResourceData, meta inter if v, ok := d.GetOk("thing_type_name"); ok { input.ThingTypeName = aws.String(v.(string)) } else { - input.RemoveThingType = aws.Bool(true) + input.RemoveThingType = true } } - log.Printf("[DEBUG] Updating IoT Thing: %s", input) - _, err := conn.UpdateThingWithContext(ctx, input) + _, err := conn.UpdateThing(ctx, input) if err != nil { return sdkdiag.AppendErrorf(diags, "updating IoT Thing (%s): %s", d.Id(), err) @@ -162,14 +162,14 @@ func resourceThingUpdate(ctx context.Context, d *schema.ResourceData, meta inter func resourceThingDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { var diags diag.Diagnostics - conn := meta.(*conns.AWSClient).IoTConn(ctx) + conn := meta.(*conns.AWSClient).IoTClient(ctx) log.Printf("[DEBUG] Deleting IoT Thing: %s", d.Id()) - _, err := conn.DeleteThingWithContext(ctx, &iot.DeleteThingInput{ + _, err := conn.DeleteThing(ctx, &iot.DeleteThingInput{ ThingName: aws.String(d.Id()), }) - if tfawserr.ErrCodeEquals(err, iot.ErrCodeResourceNotFoundException) { + if errs.IsA[*awstypes.ResourceNotFoundException](err) { return diags } @@ -179,3 +179,28 @@ func resourceThingDelete(ctx context.Context, d *schema.ResourceData, meta inter return diags } + +func findThingByName(ctx context.Context, conn *iot.Client, name string) (*iot.DescribeThingOutput, error) { + input := &iot.DescribeThingInput{ + ThingName: aws.String(name), + } + + output, err := conn.DescribeThing(ctx, input) + + if errs.IsA[*awstypes.ResourceNotFoundException](err) { + return nil, &retry.NotFoundError{ + LastError: err, + LastRequest: input, + } + } + + if err != nil { + return nil, err + } + + if output == nil { + return nil, tfresource.NewEmptyResultError(input) + } + + return output, nil +} diff --git a/internal/service/iot/thing_group.go b/internal/service/iot/thing_group.go index 4754b294d31..1f1df648503 100644 --- a/internal/service/iot/thing_group.go +++ b/internal/service/iot/thing_group.go @@ -8,13 +8,15 @@ import ( "log" "time" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/service/iot" - "github.com/hashicorp/aws-sdk-go-base/v2/awsv1shim/v2/tfawserr" + "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/service/iot" + awstypes "github.com/aws/aws-sdk-go-v2/service/iot/types" "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/retry" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" "github.com/hashicorp/terraform-provider-aws/internal/conns" + "github.com/hashicorp/terraform-provider-aws/internal/errs" "github.com/hashicorp/terraform-provider-aws/internal/errs/sdkdiag" "github.com/hashicorp/terraform-provider-aws/internal/flex" tftags "github.com/hashicorp/terraform-provider-aws/internal/tags" @@ -25,7 +27,7 @@ import ( // @SDKResource("aws_iot_thing_group", name="Thing Group") // @Tags(identifierAttribute="arn") -func ResourceThingGroup() *schema.Resource { +func resourceThingGroup() *schema.Resource { return &schema.Resource{ CreateWithoutTimeout: resourceThingGroupCreate, ReadWithoutTimeout: resourceThingGroupRead, @@ -124,13 +126,9 @@ func ResourceThingGroup() *schema.Resource { } } -const ( - thingGroupDeleteTimeout = 1 * time.Minute -) - func resourceThingGroupCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { var diags diag.Diagnostics - conn := meta.(*conns.AWSClient).IoTConn(ctx) + conn := meta.(*conns.AWSClient).IoTClient(ctx) name := d.Get(names.AttrName).(string) input := &iot.CreateThingGroupInput{ @@ -146,22 +144,22 @@ func resourceThingGroupCreate(ctx context.Context, d *schema.ResourceData, meta input.ThingGroupProperties = expandThingGroupProperties(v.([]interface{})[0].(map[string]interface{})) } - output, err := conn.CreateThingGroupWithContext(ctx, input) + output, err := conn.CreateThingGroup(ctx, input) if err != nil { return sdkdiag.AppendErrorf(diags, "creating IoT Thing Group (%s): %s", name, err) } - d.SetId(aws.StringValue(output.ThingGroupName)) + d.SetId(aws.ToString(output.ThingGroupName)) return append(diags, resourceThingGroupRead(ctx, d, meta)...) } func resourceThingGroupRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { var diags diag.Diagnostics - conn := meta.(*conns.AWSClient).IoTConn(ctx) + conn := meta.(*conns.AWSClient).IoTClient(ctx) - output, err := FindThingGroupByName(ctx, conn, d.Id()) + output, err := findThingGroupByName(ctx, conn, d.Id()) if !d.IsNewResource() && tfresource.NotFound(err) { log.Printf("[WARN] IoT Thing Group (%s) not found, removing from state", d.Id()) @@ -203,7 +201,7 @@ func resourceThingGroupRead(ctx context.Context, d *schema.ResourceData, meta in func resourceThingGroupUpdate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { var diags diag.Diagnostics - conn := meta.(*conns.AWSClient).IoTConn(ctx) + conn := meta.(*conns.AWSClient).IoTClient(ctx) if d.HasChangesExcept(names.AttrTags, names.AttrTagsAll) { input := &iot.UpdateThingGroupInput{ @@ -214,19 +212,18 @@ func resourceThingGroupUpdate(ctx context.Context, d *schema.ResourceData, meta if v, ok := d.GetOk(names.AttrProperties); ok && len(v.([]interface{})) > 0 && v.([]interface{})[0] != nil { input.ThingGroupProperties = expandThingGroupProperties(v.([]interface{})[0].(map[string]interface{})) } else { - input.ThingGroupProperties = &iot.ThingGroupProperties{} + input.ThingGroupProperties = &awstypes.ThingGroupProperties{} } // https://docs.aws.amazon.com/iot/latest/apireference/API_AttributePayload.html#API_AttributePayload_Contents: // "To remove an attribute, call UpdateThing with an empty attribute value." if input.ThingGroupProperties.AttributePayload == nil { - input.ThingGroupProperties.AttributePayload = &iot.AttributePayload{ - Attributes: map[string]*string{}, + input.ThingGroupProperties.AttributePayload = &awstypes.AttributePayload{ + Attributes: map[string]string{}, } } - log.Printf("[DEBUG] Updating IoT Thing Group: %s", input) - _, err := conn.UpdateThingGroupWithContext(ctx, input) + _, err := conn.UpdateThingGroup(ctx, input) if err != nil { return sdkdiag.AppendErrorf(diags, "updating IoT Thing Group (%s): %s", d.Id(), err) @@ -238,24 +235,20 @@ func resourceThingGroupUpdate(ctx context.Context, d *schema.ResourceData, meta func resourceThingGroupDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { var diags diag.Diagnostics - conn := meta.(*conns.AWSClient).IoTConn(ctx) + conn := meta.(*conns.AWSClient).IoTClient(ctx) log.Printf("[DEBUG] Deleting IoT Thing Group: %s", d.Id()) - _, err := tfresource.RetryWhen(ctx, thingGroupDeleteTimeout, + const ( + timeout = 1 * time.Minute + ) + _, err := tfresource.RetryWhenIsA[*awstypes.InvalidRequestException](ctx, timeout, func() (interface{}, error) { - return conn.DeleteThingGroupWithContext(ctx, &iot.DeleteThingGroupInput{ + return conn.DeleteThingGroup(ctx, &iot.DeleteThingGroupInput{ ThingGroupName: aws.String(d.Id()), }) - }, - func(err error) (bool, error) { - if tfawserr.ErrMessageContains(err, iot.ErrCodeInvalidRequestException, "there are still child groups attached") { - return true, err - } - - return false, err }) - if tfawserr.ErrCodeEquals(err, iot.ErrCodeResourceNotFoundException) { + if errs.IsA[*awstypes.ResourceNotFoundException](err) { return diags } @@ -266,12 +259,37 @@ func resourceThingGroupDelete(ctx context.Context, d *schema.ResourceData, meta return diags } -func expandThingGroupProperties(tfMap map[string]interface{}) *iot.ThingGroupProperties { +func findThingGroupByName(ctx context.Context, conn *iot.Client, name string) (*iot.DescribeThingGroupOutput, error) { + input := &iot.DescribeThingGroupInput{ + ThingGroupName: aws.String(name), + } + + output, err := conn.DescribeThingGroup(ctx, input) + + if errs.IsA[*awstypes.ResourceNotFoundException](err) { + return nil, &retry.NotFoundError{ + LastError: err, + LastRequest: input, + } + } + + if err != nil { + return nil, err + } + + if output == nil { + return nil, tfresource.NewEmptyResultError(input) + } + + return output, nil +} + +func expandThingGroupProperties(tfMap map[string]interface{}) *awstypes.ThingGroupProperties { if tfMap == nil { return nil } - apiObject := &iot.ThingGroupProperties{} + apiObject := &awstypes.ThingGroupProperties{} if v, ok := tfMap["attribute_payload"].([]interface{}); ok && len(v) > 0 { apiObject.AttributePayload = expandAttributePayload(v[0].(map[string]interface{})) @@ -284,21 +302,21 @@ func expandThingGroupProperties(tfMap map[string]interface{}) *iot.ThingGroupPro return apiObject } -func expandAttributePayload(tfMap map[string]interface{}) *iot.AttributePayload { +func expandAttributePayload(tfMap map[string]interface{}) *awstypes.AttributePayload { if tfMap == nil { return nil } - apiObject := &iot.AttributePayload{} + apiObject := &awstypes.AttributePayload{} if v, ok := tfMap[names.AttrAttributes].(map[string]interface{}); ok && len(v) > 0 { - apiObject.Attributes = flex.ExpandStringMap(v) + apiObject.Attributes = flex.ExpandStringValueMap(v) } return apiObject } -func flattenThingGroupMetadata(apiObject *iot.ThingGroupMetadata) map[string]interface{} { +func flattenThingGroupMetadata(apiObject *awstypes.ThingGroupMetadata) map[string]interface{} { if apiObject == nil { return nil } @@ -306,11 +324,11 @@ func flattenThingGroupMetadata(apiObject *iot.ThingGroupMetadata) map[string]int tfMap := map[string]interface{}{} if v := apiObject.CreationDate; v != nil { - tfMap[names.AttrCreationDate] = aws.TimeValue(v).Format(time.RFC3339) + tfMap[names.AttrCreationDate] = aws.ToTime(v).Format(time.RFC3339) } if v := apiObject.ParentGroupName; v != nil { - tfMap["parent_group_name"] = aws.StringValue(v) + tfMap["parent_group_name"] = aws.ToString(v) } if v := apiObject.RootToParentThingGroups; v != nil { @@ -320,25 +338,21 @@ func flattenThingGroupMetadata(apiObject *iot.ThingGroupMetadata) map[string]int return tfMap } -func flattenGroupNameAndARN(apiObject *iot.GroupNameAndArn) map[string]interface{} { - if apiObject == nil { - return nil - } - +func flattenGroupNameAndARN(apiObject awstypes.GroupNameAndArn) map[string]interface{} { tfMap := map[string]interface{}{} if v := apiObject.GroupArn; v != nil { - tfMap["group_arn"] = aws.StringValue(v) + tfMap["group_arn"] = aws.ToString(v) } if v := apiObject.GroupName; v != nil { - tfMap[names.AttrGroupName] = aws.StringValue(v) + tfMap[names.AttrGroupName] = aws.ToString(v) } return tfMap } -func flattenGroupNameAndARNs(apiObjects []*iot.GroupNameAndArn) []interface{} { +func flattenGroupNameAndARNs(apiObjects []awstypes.GroupNameAndArn) []interface{} { if len(apiObjects) == 0 { return nil } @@ -346,17 +360,13 @@ func flattenGroupNameAndARNs(apiObjects []*iot.GroupNameAndArn) []interface{} { var tfList []interface{} for _, apiObject := range apiObjects { - if apiObject == nil { - continue - } - tfList = append(tfList, flattenGroupNameAndARN(apiObject)) } return tfList } -func flattenThingGroupProperties(apiObject *iot.ThingGroupProperties) map[string]interface{} { +func flattenThingGroupProperties(apiObject *awstypes.ThingGroupProperties) map[string]interface{} { if apiObject == nil { return nil } @@ -368,13 +378,13 @@ func flattenThingGroupProperties(apiObject *iot.ThingGroupProperties) map[string } if v := apiObject.ThingGroupDescription; v != nil { - tfMap[names.AttrDescription] = aws.StringValue(v) + tfMap[names.AttrDescription] = aws.ToString(v) } return tfMap } -func flattenAttributePayload(apiObject *iot.AttributePayload) map[string]interface{} { +func flattenAttributePayload(apiObject *awstypes.AttributePayload) map[string]interface{} { if apiObject == nil { return nil } @@ -382,7 +392,7 @@ func flattenAttributePayload(apiObject *iot.AttributePayload) map[string]interfa tfMap := map[string]interface{}{} if v := apiObject.Attributes; v != nil { - tfMap[names.AttrAttributes] = aws.StringValueMap(v) + tfMap[names.AttrAttributes] = aws.StringMap(v) } return tfMap diff --git a/internal/service/iot/thing_group_membership.go b/internal/service/iot/thing_group_membership.go index df611d6e663..d7fad058e59 100644 --- a/internal/service/iot/thing_group_membership.go +++ b/internal/service/iot/thing_group_membership.go @@ -9,18 +9,21 @@ import ( "log" "strings" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/service/iot" - "github.com/hashicorp/aws-sdk-go-base/v2/awsv1shim/v2/tfawserr" + "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/service/iot" + awstypes "github.com/aws/aws-sdk-go-v2/service/iot/types" "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/retry" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/terraform-provider-aws/internal/conns" + "github.com/hashicorp/terraform-provider-aws/internal/errs" "github.com/hashicorp/terraform-provider-aws/internal/errs/sdkdiag" + tfslices "github.com/hashicorp/terraform-provider-aws/internal/slices" "github.com/hashicorp/terraform-provider-aws/internal/tfresource" ) -// @SDKResource("aws_iot_thing_group_membership") -func ResourceThingGroupMembership() *schema.Resource { +// @SDKResource("aws_iot_thing_group_membership", name="Thing Group Membership") +func resourceThingGroupMembership() *schema.Resource { return &schema.Resource{ CreateWithoutTimeout: resourceThingGroupMembershipCreate, ReadWithoutTimeout: resourceThingGroupMembershipRead, @@ -52,7 +55,7 @@ func ResourceThingGroupMembership() *schema.Resource { func resourceThingGroupMembershipCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { var diags diag.Diagnostics - conn := meta.(*conns.AWSClient).IoTConn(ctx) + conn := meta.(*conns.AWSClient).IoTClient(ctx) thingGroupName := d.Get("thing_group_name").(string) thingName := d.Get("thing_name").(string) @@ -62,32 +65,30 @@ func resourceThingGroupMembershipCreate(ctx context.Context, d *schema.ResourceD } if v, ok := d.GetOk("override_dynamic_group"); ok { - input.OverrideDynamicGroups = aws.Bool(v.(bool)) + input.OverrideDynamicGroups = v.(bool) } - log.Printf("[DEBUG] Creating IoT Thing Group Membership: %s", input) - _, err := conn.AddThingToThingGroupWithContext(ctx, input) + _, err := conn.AddThingToThingGroup(ctx, input) if err != nil { return sdkdiag.AppendErrorf(diags, "adding IoT Thing (%s) to IoT Thing Group (%s): %s", thingName, thingGroupName, err) } - d.SetId(ThingGroupMembershipCreateResourceID(thingGroupName, thingName)) + d.SetId(thingGroupMembershipCreateResourceID(thingGroupName, thingName)) return append(diags, resourceThingGroupMembershipRead(ctx, d, meta)...) } func resourceThingGroupMembershipRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { var diags diag.Diagnostics - conn := meta.(*conns.AWSClient).IoTConn(ctx) - - thingGroupName, thingName, err := ThingGroupMembershipParseResourceID(d.Id()) + conn := meta.(*conns.AWSClient).IoTClient(ctx) + thingGroupName, thingName, err := thingGroupMembershipParseResourceID(d.Id()) if err != nil { - return sdkdiag.AppendErrorf(diags, "reading IoT Thing Group Membership (%s): %s", d.Id(), err) + return sdkdiag.AppendFromErr(diags, err) } - err = FindThingGroupMembership(ctx, conn, thingGroupName, thingName) + _, err = findThingGroupMembershipByTwoPartKey(ctx, conn, thingGroupName, thingName) if !d.IsNewResource() && tfresource.NotFound(err) { log.Printf("[WARN] IoT Thing Group Membership (%s) not found, removing from state", d.Id()) @@ -107,21 +108,20 @@ func resourceThingGroupMembershipRead(ctx context.Context, d *schema.ResourceDat func resourceThingGroupMembershipDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { var diags diag.Diagnostics - conn := meta.(*conns.AWSClient).IoTConn(ctx) - - thingGroupName, thingName, err := ThingGroupMembershipParseResourceID(d.Id()) + conn := meta.(*conns.AWSClient).IoTClient(ctx) + thingGroupName, thingName, err := thingGroupMembershipParseResourceID(d.Id()) if err != nil { - return sdkdiag.AppendErrorf(diags, "deleting IoT Thing Group Membership (%s): %s", d.Id(), err) + return sdkdiag.AppendFromErr(diags, err) } log.Printf("[DEBUG] Deleting IoT Thing Group Membership: %s", d.Id()) - _, err = conn.RemoveThingFromThingGroupWithContext(ctx, &iot.RemoveThingFromThingGroupInput{ + _, err = conn.RemoveThingFromThingGroup(ctx, &iot.RemoveThingFromThingGroupInput{ ThingGroupName: aws.String(thingGroupName), ThingName: aws.String(thingName), }) - if tfawserr.ErrCodeEquals(err, iot.ErrCodeResourceNotFoundException) { + if errs.IsA[*awstypes.ResourceNotFoundException](err) { return diags } @@ -132,16 +132,64 @@ func resourceThingGroupMembershipDelete(ctx context.Context, d *schema.ResourceD return diags } +func findThingGroupMembershipByTwoPartKey(ctx context.Context, conn *iot.Client, thingGroupName, thingName string) (*awstypes.GroupNameAndArn, error) { + input := &iot.ListThingGroupsForThingInput{ + ThingName: aws.String(thingName), + } + + return findThingGroup(ctx, conn, input, func(v *awstypes.GroupNameAndArn) bool { + return aws.ToString(v.GroupName) == thingGroupName + }) +} + +func findThingGroup(ctx context.Context, conn *iot.Client, input *iot.ListThingGroupsForThingInput, filter tfslices.Predicate[*awstypes.GroupNameAndArn]) (*awstypes.GroupNameAndArn, error) { + output, err := findThingGroups(ctx, conn, input, filter) + + if err != nil { + return nil, err + } + + return tfresource.AssertSingleValueResult(output) +} + +func findThingGroups(ctx context.Context, conn *iot.Client, input *iot.ListThingGroupsForThingInput, filter tfslices.Predicate[*awstypes.GroupNameAndArn]) ([]awstypes.GroupNameAndArn, error) { + var output []awstypes.GroupNameAndArn + + pages := iot.NewListThingGroupsForThingPaginator(conn, input) + for pages.HasMorePages() { + page, err := pages.NextPage(ctx) + + if errs.IsA[*awstypes.ResourceNotFoundException](err) { + return nil, &retry.NotFoundError{ + LastError: err, + LastRequest: input, + } + } + + if err != nil { + return nil, err + } + + for _, v := range page.ThingGroups { + if filter(&v) { + output = append(output, v) + } + } + } + + return output, nil +} + const thingGroupMembershipResourceIDSeparator = "/" -func ThingGroupMembershipCreateResourceID(thingGroupName, thingName string) string { +func thingGroupMembershipCreateResourceID(thingGroupName, thingName string) string { parts := []string{thingGroupName, thingName} id := strings.Join(parts, thingGroupMembershipResourceIDSeparator) return id } -func ThingGroupMembershipParseResourceID(id string) (string, string, error) { +func thingGroupMembershipParseResourceID(id string) (string, string, error) { parts := strings.Split(id, thingGroupMembershipResourceIDSeparator) if len(parts) == 2 && parts[0] != "" && parts[1] != "" { diff --git a/internal/service/iot/thing_group_membership_test.go b/internal/service/iot/thing_group_membership_test.go index 123277359fc..5fc7d6b0283 100644 --- a/internal/service/iot/thing_group_membership_test.go +++ b/internal/service/iot/thing_group_membership_test.go @@ -160,38 +160,24 @@ func testAccCheckThingGroupMembershipExists(ctx context.Context, n string) resou return fmt.Errorf("Not found: %s", n) } - if rs.Primary.ID == "" { - return fmt.Errorf("No IoT Thing Group Membership ID is set") - } - - thingGroupName, thingName, err := tfiot.ThingGroupMembershipParseResourceID(rs.Primary.ID) + conn := acctest.Provider.Meta().(*conns.AWSClient).IoTClient(ctx) - if err != nil { - return err - } + _, err := tfiot.FindThingGroupMembershipByTwoPartKey(ctx, conn, rs.Primary.Attributes["thing_group_name"], rs.Primary.Attributes["thing_name"]) - conn := acctest.Provider.Meta().(*conns.AWSClient).IoTConn(ctx) - - return tfiot.FindThingGroupMembership(ctx, conn, thingGroupName, thingName) + return err } } func testAccCheckThingGroupMembershipDestroy(ctx context.Context) resource.TestCheckFunc { return func(s *terraform.State) error { - conn := acctest.Provider.Meta().(*conns.AWSClient).IoTConn(ctx) + conn := acctest.Provider.Meta().(*conns.AWSClient).IoTClient(ctx) for _, rs := range s.RootModule().Resources { if rs.Type != "aws_iot_thing_group_membership" { continue } - thingGroupName, thingName, err := tfiot.ThingGroupMembershipParseResourceID(rs.Primary.ID) - - if err != nil { - return err - } - - err = tfiot.FindThingGroupMembership(ctx, conn, thingGroupName, thingName) + _, err := tfiot.FindThingGroupMembershipByTwoPartKey(ctx, conn, rs.Primary.Attributes["thing_group_name"], rs.Primary.Attributes["thing_name"]) if tfresource.NotFound(err) { continue diff --git a/internal/service/iot/thing_group_test.go b/internal/service/iot/thing_group_test.go index 2a1779f9b22..b2130d39081 100644 --- a/internal/service/iot/thing_group_test.go +++ b/internal/service/iot/thing_group_test.go @@ -9,7 +9,6 @@ import ( "testing" "github.com/YakDriver/regexache" - "github.com/aws/aws-sdk-go/service/iot" sdkacctest "github.com/hashicorp/terraform-plugin-testing/helper/acctest" "github.com/hashicorp/terraform-plugin-testing/helper/resource" "github.com/hashicorp/terraform-plugin-testing/terraform" @@ -22,7 +21,6 @@ import ( func TestAccIoTThingGroup_basic(t *testing.T) { ctx := acctest.Context(t) - var thingGroup iot.DescribeThingGroupOutput rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) resourceName := "aws_iot_thing_group.test" @@ -35,7 +33,7 @@ func TestAccIoTThingGroup_basic(t *testing.T) { { Config: testAccThingGroupConfig_basic(rName), Check: resource.ComposeTestCheckFunc( - testAccCheckThingGroupExists(ctx, resourceName, &thingGroup), + testAccCheckThingGroupExists(ctx, resourceName), acctest.MatchResourceAttrRegionalARN(resourceName, names.AttrARN, "iot", regexache.MustCompile(fmt.Sprintf("thinggroup/%s$", rName))), resource.TestCheckResourceAttr(resourceName, "metadata.#", acctest.Ct1), resource.TestCheckResourceAttrSet(resourceName, "metadata.0.creation_date"), @@ -59,7 +57,6 @@ func TestAccIoTThingGroup_basic(t *testing.T) { func TestAccIoTThingGroup_disappears(t *testing.T) { ctx := acctest.Context(t) - var thingGroup iot.DescribeThingGroupOutput rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) resourceName := "aws_iot_thing_group.test" @@ -72,7 +69,7 @@ func TestAccIoTThingGroup_disappears(t *testing.T) { { Config: testAccThingGroupConfig_basic(rName), Check: resource.ComposeTestCheckFunc( - testAccCheckThingGroupExists(ctx, resourceName, &thingGroup), + testAccCheckThingGroupExists(ctx, resourceName), acctest.CheckResourceDisappears(ctx, acctest.Provider, tfiot.ResourceThingGroup(), resourceName), ), ExpectNonEmptyPlan: true, @@ -83,7 +80,6 @@ func TestAccIoTThingGroup_disappears(t *testing.T) { func TestAccIoTThingGroup_tags(t *testing.T) { ctx := acctest.Context(t) - var thingGroup iot.DescribeThingGroupOutput rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) resourceName := "aws_iot_thing_group.test" @@ -96,7 +92,7 @@ func TestAccIoTThingGroup_tags(t *testing.T) { { Config: testAccThingGroupConfig_tags1(rName, acctest.CtKey1, acctest.CtValue1), Check: resource.ComposeTestCheckFunc( - testAccCheckThingGroupExists(ctx, resourceName, &thingGroup), + testAccCheckThingGroupExists(ctx, resourceName), resource.TestCheckResourceAttr(resourceName, acctest.CtTagsPercent, acctest.Ct1), resource.TestCheckResourceAttr(resourceName, acctest.CtTagsKey1, acctest.CtValue1), ), @@ -109,7 +105,7 @@ func TestAccIoTThingGroup_tags(t *testing.T) { { Config: testAccThingGroupConfig_tags2(rName, acctest.CtKey1, acctest.CtValue1Updated, acctest.CtKey2, acctest.CtValue2), Check: resource.ComposeTestCheckFunc( - testAccCheckThingGroupExists(ctx, resourceName, &thingGroup), + testAccCheckThingGroupExists(ctx, resourceName), resource.TestCheckResourceAttr(resourceName, acctest.CtTagsPercent, acctest.Ct2), resource.TestCheckResourceAttr(resourceName, acctest.CtTagsKey1, acctest.CtValue1Updated), resource.TestCheckResourceAttr(resourceName, acctest.CtTagsKey2, acctest.CtValue2), @@ -118,7 +114,7 @@ func TestAccIoTThingGroup_tags(t *testing.T) { { Config: testAccThingGroupConfig_tags1(rName, acctest.CtKey2, acctest.CtValue2), Check: resource.ComposeTestCheckFunc( - testAccCheckThingGroupExists(ctx, resourceName, &thingGroup), + testAccCheckThingGroupExists(ctx, resourceName), resource.TestCheckResourceAttr(resourceName, acctest.CtTagsPercent, acctest.Ct1), resource.TestCheckResourceAttr(resourceName, acctest.CtTagsKey2, acctest.CtValue2), ), @@ -129,7 +125,6 @@ func TestAccIoTThingGroup_tags(t *testing.T) { func TestAccIoTThingGroup_parentGroup(t *testing.T) { ctx := acctest.Context(t) - var thingGroup iot.DescribeThingGroupOutput rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) resourceName := "aws_iot_thing_group.test" parentResourceName := "aws_iot_thing_group.parent" @@ -144,7 +139,7 @@ func TestAccIoTThingGroup_parentGroup(t *testing.T) { { Config: testAccThingGroupConfig_parent(rName), Check: resource.ComposeTestCheckFunc( - testAccCheckThingGroupExists(ctx, resourceName, &thingGroup), + testAccCheckThingGroupExists(ctx, resourceName), resource.TestCheckResourceAttrPair(resourceName, "parent_group_name", parentResourceName, names.AttrName), resource.TestCheckResourceAttr(resourceName, "metadata.#", acctest.Ct1), resource.TestCheckResourceAttrPair(resourceName, "metadata.0.parent_group_name", parentResourceName, names.AttrName), @@ -166,7 +161,6 @@ func TestAccIoTThingGroup_parentGroup(t *testing.T) { func TestAccIoTThingGroup_properties(t *testing.T) { ctx := acctest.Context(t) - var thingGroup iot.DescribeThingGroupOutput rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) resourceName := "aws_iot_thing_group.test" @@ -179,7 +173,7 @@ func TestAccIoTThingGroup_properties(t *testing.T) { { Config: testAccThingGroupConfig_properties(rName), Check: resource.ComposeTestCheckFunc( - testAccCheckThingGroupExists(ctx, resourceName, &thingGroup), + testAccCheckThingGroupExists(ctx, resourceName), resource.TestCheckResourceAttr(resourceName, "properties.#", acctest.Ct1), resource.TestCheckResourceAttr(resourceName, "properties.0.attribute_payload.#", acctest.Ct1), resource.TestCheckResourceAttr(resourceName, "properties.0.attribute_payload.0.attributes.%", acctest.Ct1), @@ -196,7 +190,7 @@ func TestAccIoTThingGroup_properties(t *testing.T) { { Config: testAccThingGroupConfig_propertiesUpdated(rName), Check: resource.ComposeTestCheckFunc( - testAccCheckThingGroupExists(ctx, resourceName, &thingGroup), + testAccCheckThingGroupExists(ctx, resourceName), resource.TestCheckResourceAttr(resourceName, "properties.#", acctest.Ct1), resource.TestCheckResourceAttr(resourceName, "properties.0.attribute_payload.#", acctest.Ct1), resource.TestCheckResourceAttr(resourceName, "properties.0.attribute_payload.0.attributes.%", acctest.Ct2), @@ -210,7 +204,7 @@ func TestAccIoTThingGroup_properties(t *testing.T) { }) } -func testAccCheckThingGroupExists(ctx context.Context, n string, v *iot.DescribeThingGroupOutput) resource.TestCheckFunc { +func testAccCheckThingGroupExists(ctx context.Context, n string) resource.TestCheckFunc { return func(s *terraform.State) error { rs, ok := s.RootModule().Resources[n] if !ok { @@ -221,23 +215,17 @@ func testAccCheckThingGroupExists(ctx context.Context, n string, v *iot.Describe return fmt.Errorf("No IoT Thing Group ID is set") } - conn := acctest.Provider.Meta().(*conns.AWSClient).IoTConn(ctx) + conn := acctest.Provider.Meta().(*conns.AWSClient).IoTClient(ctx) - output, err := tfiot.FindThingGroupByName(ctx, conn, rs.Primary.ID) + _, err := tfiot.FindThingGroupByName(ctx, conn, rs.Primary.ID) - if err != nil { - return err - } - - *v = *output - - return nil + return err } } func testAccCheckThingGroupDestroy(ctx context.Context) resource.TestCheckFunc { return func(s *terraform.State) error { - conn := acctest.Provider.Meta().(*conns.AWSClient).IoTConn(ctx) + conn := acctest.Provider.Meta().(*conns.AWSClient).IoTClient(ctx) for _, rs := range s.RootModule().Resources { if rs.Type != "aws_iot_thing_group" { diff --git a/internal/service/iot/thing_principal_attachment.go b/internal/service/iot/thing_principal_attachment.go index 856fcf2e0a3..b59ab492580 100644 --- a/internal/service/iot/thing_principal_attachment.go +++ b/internal/service/iot/thing_principal_attachment.go @@ -8,18 +8,22 @@ import ( "fmt" "log" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/service/iot" - "github.com/hashicorp/aws-sdk-go-base/v2/awsv1shim/v2/tfawserr" + "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/service/iot" + awstypes "github.com/aws/aws-sdk-go-v2/service/iot/types" "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/retry" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/terraform-provider-aws/internal/conns" + "github.com/hashicorp/terraform-provider-aws/internal/errs" "github.com/hashicorp/terraform-provider-aws/internal/errs/sdkdiag" + tfslices "github.com/hashicorp/terraform-provider-aws/internal/slices" + "github.com/hashicorp/terraform-provider-aws/internal/tfresource" "github.com/hashicorp/terraform-provider-aws/names" ) -// @SDKResource("aws_iot_thing_principal_attachment") -func ResourceThingPrincipalAttachment() *schema.Resource { +// @SDKResource("aws_iot_thing_principal_attachment", name="Thing Principal Attachment") +func resourceThingPrincipalAttachment() *schema.Resource { return &schema.Resource{ CreateWithoutTimeout: resourceThingPrincipalAttachmentCreate, ReadWithoutTimeout: resourceThingPrincipalAttachmentRead, @@ -42,59 +46,44 @@ func ResourceThingPrincipalAttachment() *schema.Resource { func resourceThingPrincipalAttachmentCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { var diags diag.Diagnostics - conn := meta.(*conns.AWSClient).IoTConn(ctx) + conn := meta.(*conns.AWSClient).IoTClient(ctx) principal := d.Get(names.AttrPrincipal).(string) thing := d.Get("thing").(string) - - _, err := conn.AttachThingPrincipalWithContext(ctx, &iot.AttachThingPrincipalInput{ + id := fmt.Sprintf("%s|%s", thing, principal) + input := &iot.AttachThingPrincipalInput{ Principal: aws.String(principal), ThingName: aws.String(thing), - }) + } + + _, err := conn.AttachThingPrincipal(ctx, input) if err != nil { - return sdkdiag.AppendErrorf(diags, "attaching principal %s to thing %s: %s", principal, thing, err) + return sdkdiag.AppendErrorf(diags, "creating IoT Thing Principal Attachment (%s): %s", id, err) } - d.SetId(fmt.Sprintf("%s|%s", thing, principal)) - return append(diags, resourceThingPrincipalAttachmentRead(ctx, d, meta)...) -} + d.SetId(id) -func GetThingPricipalAttachment(ctx context.Context, conn *iot.IoT, thing, principal string) (bool, error) { - out, err := conn.ListThingPrincipalsWithContext(ctx, &iot.ListThingPrincipalsInput{ - ThingName: aws.String(thing), - }) - if tfawserr.ErrCodeEquals(err, iot.ErrCodeResourceNotFoundException) { - return false, nil - } else if err != nil { - return false, err - } - found := false - for _, name := range out.Principals { - if principal == aws.StringValue(name) { - found = true - break - } - } - return found, nil + return append(diags, resourceThingPrincipalAttachmentRead(ctx, d, meta)...) } func resourceThingPrincipalAttachmentRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { var diags diag.Diagnostics - conn := meta.(*conns.AWSClient).IoTConn(ctx) + conn := meta.(*conns.AWSClient).IoTClient(ctx) principal := d.Get(names.AttrPrincipal).(string) thing := d.Get("thing").(string) - found, err := GetThingPricipalAttachment(ctx, conn, thing, principal) + _, err := findThingPrincipalAttachmentByTwoPartKey(ctx, conn, thing, principal) - if err != nil { - return sdkdiag.AppendErrorf(diags, "listing principals for thing %s: %s", thing, err) - } - - if !found { + if !d.IsNewResource() && tfresource.NotFound(err) { log.Printf("[WARN] IoT Thing Principal Attachment (%s) not found, removing from state", d.Id()) d.SetId("") + return diags + } + + if err != nil { + return sdkdiag.AppendErrorf(diags, "reading IoT Thing Principal Attachment (%s): %s", d.Id(), err) } return diags @@ -102,21 +91,69 @@ func resourceThingPrincipalAttachmentRead(ctx context.Context, d *schema.Resourc func resourceThingPrincipalAttachmentDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { var diags diag.Diagnostics - conn := meta.(*conns.AWSClient).IoTConn(ctx) + conn := meta.(*conns.AWSClient).IoTClient(ctx) - principal := d.Get(names.AttrPrincipal).(string) - thing := d.Get("thing").(string) + log.Printf("[DEBUG] Deleting IoT Thing Principal Attachment: %s", d.Id()) + _, err := conn.DetachThingPrincipal(ctx, &iot.DetachThingPrincipalInput{ + Principal: aws.String(d.Get(names.AttrPrincipal).(string)), + ThingName: aws.String(d.Get("thing").(string)), + }) - _, err := conn.DetachThingPrincipalWithContext(ctx, &iot.DetachThingPrincipalInput{ - Principal: aws.String(principal), + if errs.IsA[*awstypes.ResourceNotFoundException](err) { + return diags + } + + if err != nil { + return sdkdiag.AppendErrorf(diags, "deleting IoT Thing Principal Attachment (%s): %s", d.Id(), err) + } + + return diags +} + +func findThingPrincipalAttachmentByTwoPartKey(ctx context.Context, conn *iot.Client, thing, principal string) (*string, error) { + input := &iot.ListThingPrincipalsInput{ ThingName: aws.String(thing), + } + + return findThingPrincipal(ctx, conn, input, func(v string) bool { + return principal == v }) +} - if tfawserr.ErrCodeEquals(err, iot.ErrCodeResourceNotFoundException) { - log.Printf("[WARN] IoT Principal %s or Thing %s not found, removing from state", principal, thing) - } else if err != nil { - return sdkdiag.AppendErrorf(diags, "detaching principal %s from thing %s: %s", principal, thing, err) +func findThingPrincipal(ctx context.Context, conn *iot.Client, input *iot.ListThingPrincipalsInput, filter tfslices.Predicate[string]) (*string, error) { + output, err := findThingPrincipals(ctx, conn, input, filter) + + if err != nil { + return nil, err } - return diags + return tfresource.AssertSingleValueResult(output) +} + +func findThingPrincipals(ctx context.Context, conn *iot.Client, input *iot.ListThingPrincipalsInput, filter tfslices.Predicate[string]) ([]string, error) { + var output []string + + pages := iot.NewListThingPrincipalsPaginator(conn, input) + for pages.HasMorePages() { + page, err := pages.NextPage(ctx) + + if errs.IsA[*awstypes.ResourceNotFoundException](err) { + return nil, &retry.NotFoundError{ + LastError: err, + LastRequest: input, + } + } + + if err != nil { + return nil, err + } + + for _, v := range page.Principals { + if filter(v) { + output = append(output, v) + } + } + } + + return output, nil } diff --git a/internal/service/iot/thing_principal_attachment_test.go b/internal/service/iot/thing_principal_attachment_test.go index bdd8d587339..544649b7d69 100644 --- a/internal/service/iot/thing_principal_attachment_test.go +++ b/internal/service/iot/thing_principal_attachment_test.go @@ -8,15 +8,17 @@ import ( "fmt" "testing" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/service/iot" - "github.com/hashicorp/aws-sdk-go-base/v2/awsv1shim/v2/tfawserr" + "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/service/iot" + awstypes "github.com/aws/aws-sdk-go-v2/service/iot/types" sdkacctest "github.com/hashicorp/terraform-plugin-testing/helper/acctest" "github.com/hashicorp/terraform-plugin-testing/helper/resource" "github.com/hashicorp/terraform-plugin-testing/terraform" "github.com/hashicorp/terraform-provider-aws/internal/acctest" "github.com/hashicorp/terraform-provider-aws/internal/conns" + "github.com/hashicorp/terraform-provider-aws/internal/errs" tfiot "github.com/hashicorp/terraform-provider-aws/internal/service/iot" + "github.com/hashicorp/terraform-provider-aws/internal/tfresource" "github.com/hashicorp/terraform-provider-aws/names" ) @@ -77,27 +79,24 @@ func TestAccIoTThingPrincipalAttachment_basic(t *testing.T) { func testAccCheckThingPrincipalAttachmentDestroy(ctx context.Context) resource.TestCheckFunc { return func(s *terraform.State) error { - conn := acctest.Provider.Meta().(*conns.AWSClient).IoTConn(ctx) + conn := acctest.Provider.Meta().(*conns.AWSClient).IoTClient(ctx) for _, rs := range s.RootModule().Resources { if rs.Type != "aws_iot_thing_principal_attachment" { continue } - principal := rs.Primary.Attributes[names.AttrPrincipal] - thing := rs.Primary.Attributes["thing"] + _, err := tfiot.FindThingPrincipalAttachmentByTwoPartKey(ctx, conn, rs.Primary.Attributes["thing"], rs.Primary.Attributes[names.AttrPrincipal]) - found, err := tfiot.GetThingPricipalAttachment(ctx, conn, thing, principal) - - if err != nil { - return fmt.Errorf("Error: Failed listing principals for thing (%s): %s", thing, err) + if tfresource.NotFound(err) { + continue } - if !found { - continue + if err != nil { + return err } - return fmt.Errorf("IOT Thing Principal Attachment (%s) still exists", rs.Primary.Attributes[names.AttrID]) + return fmt.Errorf("IoT Thing Principal Attachment %s still exists", rs.Primary.ID) } return nil @@ -111,31 +110,17 @@ func testAccCheckThingPrincipalAttachmentExists(ctx context.Context, n string) r return fmt.Errorf("Not found: %s", n) } - if rs.Primary.ID == "" { - return fmt.Errorf("No attachment") - } - - conn := acctest.Provider.Meta().(*conns.AWSClient).IoTConn(ctx) - thing := rs.Primary.Attributes["thing"] - principal := rs.Primary.Attributes[names.AttrPrincipal] + conn := acctest.Provider.Meta().(*conns.AWSClient).IoTClient(ctx) - found, err := tfiot.GetThingPricipalAttachment(ctx, conn, thing, principal) + _, err := tfiot.FindThingPrincipalAttachmentByTwoPartKey(ctx, conn, rs.Primary.Attributes["thing"], rs.Primary.Attributes[names.AttrPrincipal]) - if err != nil { - return fmt.Errorf("Error: Failed listing principals for thing (%s), resource (%s): %s", thing, n, err) - } - - if !found { - return fmt.Errorf("Error: Principal (%s) is not attached to thing (%s), resource (%s)", principal, thing, n) - } - - return nil + return err } } func testAccCheckThingPrincipalAttachmentStatus(ctx context.Context, thingName string, exists bool, principals []string) resource.TestCheckFunc { return func(s *terraform.State) error { - conn := acctest.Provider.Meta().(*conns.AWSClient).IoTConn(ctx) + conn := acctest.Provider.Meta().(*conns.AWSClient).IoTClient(ctx) principalARNs := make(map[string]string) @@ -147,11 +132,11 @@ func testAccCheckThingPrincipalAttachmentStatus(ctx context.Context, thingName s principalARNs[pr.Primary.Attributes[names.AttrARN]] = p } - thing, err := conn.DescribeThingWithContext(ctx, &iot.DescribeThingInput{ + _, err := conn.DescribeThing(ctx, &iot.DescribeThingInput{ ThingName: aws.String(thingName), }) - if tfawserr.ErrCodeEquals(err, iot.ErrCodeResourceNotFoundException) { + if errs.IsA[*awstypes.ResourceNotFoundException](err) { if exists { return fmt.Errorf("Error: Thing (%s) exists, but expected to be removed", thingName) } else { @@ -163,7 +148,7 @@ func testAccCheckThingPrincipalAttachmentStatus(ctx context.Context, thingName s return fmt.Errorf("Error: Thing (%s) does not exist, but expected to be", thingName) } - res, err := conn.ListThingPrincipalsWithContext(ctx, &iot.ListThingPrincipalsInput{ + res, err := conn.ListThingPrincipals(ctx, &iot.ListThingPrincipalsInput{ ThingName: aws.String(thingName), }) @@ -172,11 +157,11 @@ func testAccCheckThingPrincipalAttachmentStatus(ctx context.Context, thingName s } if len(res.Principals) != len(principalARNs) { - return fmt.Errorf("Error: Thing (%s) has wrong number of principals attached", thing) + return fmt.Errorf("Error: Thing (%s) has wrong number of principals attached", thingName) } for _, p := range res.Principals { - if principal, ok := principalARNs[aws.StringValue(p)]; !ok { + if principal, ok := principalARNs[p]; !ok { return fmt.Errorf("Error: Principal %s is not attached to thing %s", principal, thingName) } } diff --git a/internal/service/iot/thing_test.go b/internal/service/iot/thing_test.go index ad12901befd..b2deeab7e91 100644 --- a/internal/service/iot/thing_test.go +++ b/internal/service/iot/thing_test.go @@ -8,7 +8,7 @@ import ( "fmt" "testing" - "github.com/aws/aws-sdk-go/service/iot" + "github.com/aws/aws-sdk-go-v2/service/iot" sdkacctest "github.com/hashicorp/terraform-plugin-testing/helper/acctest" "github.com/hashicorp/terraform-plugin-testing/helper/resource" "github.com/hashicorp/terraform-plugin-testing/terraform" @@ -103,7 +103,7 @@ func TestAccIoTThing_full(t *testing.T) { ), }, { // Remove thing type association - Config: testAccThingConfig_basic(thingName), + Config: testAccThingConfig_fullUpdated(thingName, typeName), Check: resource.ComposeTestCheckFunc( testAccCheckThingExists(ctx, resourceName, &thing), resource.TestCheckResourceAttr(resourceName, names.AttrName, thingName), @@ -129,7 +129,7 @@ func testAccCheckThingExists(ctx context.Context, n string, v *iot.DescribeThing return fmt.Errorf("No IoT Thing ID is set") } - conn := acctest.Provider.Meta().(*conns.AWSClient).IoTConn(ctx) + conn := acctest.Provider.Meta().(*conns.AWSClient).IoTClient(ctx) output, err := tfiot.FindThingByName(ctx, conn, rs.Primary.ID) @@ -145,7 +145,7 @@ func testAccCheckThingExists(ctx context.Context, n string, v *iot.DescribeThing func testAccCheckThingDestroy(ctx context.Context) resource.TestCheckFunc { return func(s *terraform.State) error { - conn := acctest.Provider.Meta().(*conns.AWSClient).IoTConn(ctx) + conn := acctest.Provider.Meta().(*conns.AWSClient).IoTClient(ctx) for _, rs := range s.RootModule().Resources { if rs.Type != "aws_iot_thing" { @@ -196,3 +196,15 @@ resource "aws_iot_thing_type" "test" { } `, thingName, answer, typeName) } + +func testAccThingConfig_fullUpdated(thingName, typeName string) string { + return fmt.Sprintf(` +resource "aws_iot_thing" "test" { + name = %[1]q +} + +resource "aws_iot_thing_type" "test" { + name = %[2]q +} +`, thingName, typeName) +} diff --git a/internal/service/iot/thing_type.go b/internal/service/iot/thing_type.go index a0d20a4a6ed..f8a17f5349a 100644 --- a/internal/service/iot/thing_type.go +++ b/internal/service/iot/thing_type.go @@ -6,16 +6,17 @@ package iot import ( "context" "log" - "time" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/service/iot" - "github.com/hashicorp/aws-sdk-go-base/v2/awsv1shim/v2/tfawserr" + "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/service/iot" + awstypes "github.com/aws/aws-sdk-go-v2/service/iot/types" "github.com/hashicorp/terraform-plugin-sdk/v2/diag" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/retry" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/terraform-provider-aws/internal/conns" + "github.com/hashicorp/terraform-provider-aws/internal/errs" "github.com/hashicorp/terraform-provider-aws/internal/errs/sdkdiag" + "github.com/hashicorp/terraform-provider-aws/internal/flex" tftags "github.com/hashicorp/terraform-provider-aws/internal/tags" "github.com/hashicorp/terraform-provider-aws/internal/tfresource" "github.com/hashicorp/terraform-provider-aws/internal/verify" @@ -24,7 +25,7 @@ import ( // @SDKResource("aws_iot_thing_type", name="Thing Type") // @Tags(identifierAttribute="arn") -func ResourceThingType() *schema.Resource { +func resourceThingType() *schema.Resource { return &schema.Resource{ CreateWithoutTimeout: resourceThingTypeCreate, ReadWithoutTimeout: resourceThingTypeRead, @@ -91,7 +92,7 @@ func ResourceThingType() *schema.Resource { func resourceThingTypeCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { var diags diag.Diagnostics - conn := meta.(*conns.AWSClient).IoTConn(ctx) + conn := meta.(*conns.AWSClient).IoTClient(ctx) name := d.Get(names.AttrName).(string) input := &iot.CreateThingTypeInput{ @@ -106,21 +107,21 @@ func resourceThingTypeCreate(ctx context.Context, d *schema.ResourceData, meta i } } - out, err := conn.CreateThingTypeWithContext(ctx, input) + out, err := conn.CreateThingType(ctx, input) if err != nil { return sdkdiag.AppendErrorf(diags, "creating IoT Thing Type (%s): %s", name, err) } - d.SetId(aws.StringValue(out.ThingTypeName)) + d.SetId(aws.ToString(out.ThingTypeName)) if v := d.Get("deprecated").(bool); v { input := &iot.DeprecateThingTypeInput{ ThingTypeName: aws.String(d.Id()), - UndoDeprecate: aws.Bool(false), + UndoDeprecate: false, } - _, err := conn.DeprecateThingTypeWithContext(ctx, input) + _, err := conn.DeprecateThingType(ctx, input) if err != nil { return sdkdiag.AppendErrorf(diags, "deprecating IoT Thing Type (%s): %s", d.Id(), err) @@ -132,9 +133,9 @@ func resourceThingTypeCreate(ctx context.Context, d *schema.ResourceData, meta i func resourceThingTypeRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { var diags diag.Diagnostics - conn := meta.(*conns.AWSClient).IoTConn(ctx) + conn := meta.(*conns.AWSClient).IoTClient(ctx) - output, err := FindThingTypeByName(ctx, conn, d.Id()) + output, err := findThingTypeByName(ctx, conn, d.Id()) if !d.IsNewResource() && tfresource.NotFound(err) { log.Printf("[WARN] IoT Thing Type (%s) not found, removing from state", d.Id()) @@ -159,15 +160,15 @@ func resourceThingTypeRead(ctx context.Context, d *schema.ResourceData, meta int func resourceThingTypeUpdate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { var diags diag.Diagnostics - conn := meta.(*conns.AWSClient).IoTConn(ctx) + conn := meta.(*conns.AWSClient).IoTClient(ctx) if d.HasChange("deprecated") { input := &iot.DeprecateThingTypeInput{ ThingTypeName: aws.String(d.Id()), - UndoDeprecate: aws.Bool(!d.Get("deprecated").(bool)), + UndoDeprecate: !d.Get("deprecated").(bool), } - _, err := conn.DeprecateThingTypeWithContext(ctx, input) + _, err := conn.DeprecateThingType(ctx, input) if err != nil { return sdkdiag.AppendErrorf(diags, "deprecating IoT Thing Type (%s): %s", d.Id(), err) @@ -179,14 +180,14 @@ func resourceThingTypeUpdate(ctx context.Context, d *schema.ResourceData, meta i func resourceThingTypeDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { var diags diag.Diagnostics - conn := meta.(*conns.AWSClient).IoTConn(ctx) + conn := meta.(*conns.AWSClient).IoTClient(ctx) // In order to delete an IoT Thing Type, you must deprecate it first and wait at least 5 minutes. - _, err := conn.DeprecateThingTypeWithContext(ctx, &iot.DeprecateThingTypeInput{ + _, err := conn.DeprecateThingType(ctx, &iot.DeprecateThingTypeInput{ ThingTypeName: aws.String(d.Id()), }) - if tfawserr.ErrCodeEquals(err, iot.ErrCodeResourceNotFoundException) { + if errs.IsA[*awstypes.ResourceNotFoundException](err) { return diags } @@ -195,13 +196,14 @@ func resourceThingTypeDelete(ctx context.Context, d *schema.ResourceData, meta i } log.Printf("[DEBUG] Deleting IoT Thing Type: %s", d.Id()) - _, err = tfresource.RetryWhenAWSErrMessageContains(ctx, 6*time.Minute, func() (interface{}, error) { - return conn.DeleteThingTypeWithContext(ctx, &iot.DeleteThingTypeInput{ - ThingTypeName: aws.String(d.Id()), + _, err = tfresource.RetryWhenIsA[*awstypes.InvalidRequestException](ctx, deprecatePropagationTimeout, + func() (interface{}, error) { + return conn.DeleteThingType(ctx, &iot.DeleteThingTypeInput{ + ThingTypeName: aws.String(d.Id()), + }) }) - }, iot.ErrCodeInvalidRequestException, "Please wait for 5 minutes after deprecation and then retry") - if tfawserr.ErrCodeEquals(err, iot.ErrCodeResourceNotFoundException) { + if errs.IsA[*awstypes.ResourceNotFoundException](err) { return diags } @@ -212,14 +214,14 @@ func resourceThingTypeDelete(ctx context.Context, d *schema.ResourceData, meta i return diags } -func FindThingTypeByName(ctx context.Context, conn *iot.IoT, name string) (*iot.DescribeThingTypeOutput, error) { +func findThingTypeByName(ctx context.Context, conn *iot.Client, name string) (*iot.DescribeThingTypeOutput, error) { input := &iot.DescribeThingTypeInput{ ThingTypeName: aws.String(name), } - output, err := conn.DescribeThingTypeWithContext(ctx, input) + output, err := conn.DescribeThingType(ctx, input) - if tfawserr.ErrCodeEquals(err, iot.ErrCodeResourceNotFoundException) { + if errs.IsA[*awstypes.ResourceNotFoundException](err) { return nil, &retry.NotFoundError{ LastError: err, LastRequest: input, @@ -236,3 +238,31 @@ func FindThingTypeByName(ctx context.Context, conn *iot.IoT, name string) (*iot. return output, nil } + +func expandThingTypeProperties(config map[string]interface{}) *awstypes.ThingTypeProperties { + properties := &awstypes.ThingTypeProperties{ + SearchableAttributes: flex.ExpandStringValueSet(config["searchable_attributes"].(*schema.Set)), + } + + if v, ok := config[names.AttrDescription]; ok && v.(string) != "" { + properties.ThingTypeDescription = aws.String(v.(string)) + } + + return properties +} + +func flattenThingTypeProperties(s *awstypes.ThingTypeProperties) []map[string]interface{} { + m := map[string]interface{}{ + names.AttrDescription: "", + "searchable_attributes": flex.FlattenStringSet(nil), + } + + if s == nil { + return []map[string]interface{}{m} + } + + m[names.AttrDescription] = aws.ToString(s.ThingTypeDescription) + m["searchable_attributes"] = s.SearchableAttributes + + return []map[string]interface{}{m} +} diff --git a/internal/service/iot/thing_type_test.go b/internal/service/iot/thing_type_test.go index 4cc235ed879..a3391405902 100644 --- a/internal/service/iot/thing_type_test.go +++ b/internal/service/iot/thing_type_test.go @@ -162,7 +162,7 @@ func testAccCheckThingTypeExists(ctx context.Context, n string) resource.TestChe return fmt.Errorf("Not found: %s", n) } - conn := acctest.Provider.Meta().(*conns.AWSClient).IoTConn(ctx) + conn := acctest.Provider.Meta().(*conns.AWSClient).IoTClient(ctx) _, err := tfiot.FindThingTypeByName(ctx, conn, rs.Primary.ID) @@ -172,7 +172,7 @@ func testAccCheckThingTypeExists(ctx context.Context, n string) resource.TestChe func testAccCheckThingTypeDestroy(ctx context.Context) resource.TestCheckFunc { return func(s *terraform.State) error { - conn := acctest.Provider.Meta().(*conns.AWSClient).IoTConn(ctx) + conn := acctest.Provider.Meta().(*conns.AWSClient).IoTClient(ctx) for _, rs := range s.RootModule().Resources { if rs.Type != "aws_iot_thing_type" { diff --git a/internal/service/iot/topic_rule.go b/internal/service/iot/topic_rule.go index 60556106799..07bf2a4888e 100644 --- a/internal/service/iot/topic_rule.go +++ b/internal/service/iot/topic_rule.go @@ -8,12 +8,16 @@ import ( "log" "reflect" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/service/iot" + "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/service/iot" + awstypes "github.com/aws/aws-sdk-go-v2/service/iot/types" "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/retry" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" "github.com/hashicorp/terraform-provider-aws/internal/conns" + "github.com/hashicorp/terraform-provider-aws/internal/enum" + "github.com/hashicorp/terraform-provider-aws/internal/errs" "github.com/hashicorp/terraform-provider-aws/internal/errs/sdkdiag" "github.com/hashicorp/terraform-provider-aws/internal/flex" tftags "github.com/hashicorp/terraform-provider-aws/internal/tags" @@ -24,7 +28,7 @@ import ( // @SDKResource("aws_iot_topic_rule", name="Topic Rule") // @Tags(identifierAttribute="arn") -func ResourceTopicRule() *schema.Resource { +func resourceTopicRule() *schema.Resource { return &schema.Resource{ CreateWithoutTimeout: resourceTopicRuleCreate, ReadWithoutTimeout: resourceTopicRuleRead, @@ -35,1204 +39,1208 @@ func ResourceTopicRule() *schema.Resource { StateContext: schema.ImportStatePassthroughContext, }, - Schema: map[string]*schema.Schema{ - names.AttrARN: { - Type: schema.TypeString, - Computed: true, - }, - "cloudwatch_alarm": { - Type: schema.TypeSet, - Optional: true, - Elem: &schema.Resource{ + SchemaFunc: func() map[string]*schema.Schema { + topicRuleErrorActionExactlyOneOf := []string{ + "error_action.0.cloudwatch_alarm", + "error_action.0.cloudwatch_logs", + "error_action.0.cloudwatch_metric", + "error_action.0.dynamodb", + "error_action.0.dynamodbv2", + "error_action.0.elasticsearch", + "error_action.0.firehose", + "error_action.0.http", + "error_action.0.iot_analytics", + "error_action.0.iot_events", + "error_action.0.kafka", + "error_action.0.kinesis", + "error_action.0.lambda", + "error_action.0.republish", + "error_action.0.s3", + "error_action.0.sns", + "error_action.0.sqs", + "error_action.0.step_functions", + "error_action.0.timestream", + } + + timestreamDimensionResource := func() *schema.Resource { + return &schema.Resource{ Schema: map[string]*schema.Schema{ - "alarm_name": { + names.AttrName: { Type: schema.TypeString, Required: true, }, - names.AttrRoleARN: { - Type: schema.TypeString, - Required: true, - ValidateFunc: verify.ValidARN, - }, - "state_reason": { + names.AttrValue: { Type: schema.TypeString, Required: true, }, - "state_value": { - Type: schema.TypeString, - Required: true, - ValidateFunc: validTopicRuleCloudWatchAlarmStateValue, - }, }, + } + } + + return map[string]*schema.Schema{ + names.AttrARN: { + Type: schema.TypeString, + Computed: true, }, - }, - names.AttrCloudWatchLogs: { - Type: schema.TypeSet, - Optional: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - names.AttrLogGroupName: { - Type: schema.TypeString, - Required: true, - }, - names.AttrRoleARN: { - Type: schema.TypeString, - Required: true, - ValidateFunc: verify.ValidARN, + "cloudwatch_alarm": { + Type: schema.TypeSet, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "alarm_name": { + Type: schema.TypeString, + Required: true, + }, + names.AttrRoleARN: { + Type: schema.TypeString, + Required: true, + ValidateFunc: verify.ValidARN, + }, + "state_reason": { + Type: schema.TypeString, + Required: true, + }, + "state_value": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validTopicRuleCloudWatchAlarmStateValue, + }, }, }, }, - }, - "cloudwatch_metric": { - Type: schema.TypeSet, - Optional: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - names.AttrMetricName: { - Type: schema.TypeString, - Required: true, - }, - "metric_namespace": { - Type: schema.TypeString, - Required: true, - }, - "metric_timestamp": { - Type: schema.TypeString, - Optional: true, - ValidateFunc: verify.ValidUTCTimestamp, - }, - "metric_unit": { - Type: schema.TypeString, - Required: true, - }, - "metric_value": { - Type: schema.TypeString, - Required: true, - }, - names.AttrRoleARN: { - Type: schema.TypeString, - Required: true, - ValidateFunc: verify.ValidARN, + names.AttrCloudWatchLogs: { + Type: schema.TypeSet, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + names.AttrLogGroupName: { + Type: schema.TypeString, + Required: true, + }, + names.AttrRoleARN: { + Type: schema.TypeString, + Required: true, + ValidateFunc: verify.ValidARN, + }, }, }, }, - }, - names.AttrDescription: { - Type: schema.TypeString, - Optional: true, - }, - "dynamodb": { - Type: schema.TypeSet, - Optional: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "hash_key_field": { - Type: schema.TypeString, - Required: true, - }, - "hash_key_value": { - Type: schema.TypeString, - Required: true, - }, - "hash_key_type": { - Type: schema.TypeString, - Optional: true, - }, - "operation": { - Type: schema.TypeString, - Optional: true, - ValidateFunc: validation.StringInSlice([]string{ - "DELETE", - "INSERT", - "UPDATE", - }, false), - }, - "payload_field": { - Type: schema.TypeString, - Optional: true, - }, - "range_key_field": { - Type: schema.TypeString, - Optional: true, - }, - "range_key_value": { - Type: schema.TypeString, - Optional: true, - }, - "range_key_type": { - Type: schema.TypeString, - Optional: true, - }, - names.AttrRoleARN: { - Type: schema.TypeString, - Required: true, - ValidateFunc: verify.ValidARN, + "cloudwatch_metric": { + Type: schema.TypeSet, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + names.AttrMetricName: { + Type: schema.TypeString, + Required: true, + }, + "metric_namespace": { + Type: schema.TypeString, + Required: true, + }, + "metric_timestamp": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: verify.ValidUTCTimestamp, + }, + "metric_unit": { + Type: schema.TypeString, + Required: true, + }, + "metric_value": { + Type: schema.TypeString, + Required: true, + }, + names.AttrRoleARN: { + Type: schema.TypeString, + Required: true, + ValidateFunc: verify.ValidARN, + }, }, - names.AttrTableName: { - Type: schema.TypeString, - Required: true, + }, + }, + names.AttrDescription: { + Type: schema.TypeString, + Optional: true, + }, + "dynamodb": { + Type: schema.TypeSet, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "hash_key_field": { + Type: schema.TypeString, + Required: true, + }, + "hash_key_value": { + Type: schema.TypeString, + Required: true, + }, + "hash_key_type": { + Type: schema.TypeString, + Optional: true, + }, + "operation": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.StringInSlice([]string{ + "DELETE", + "INSERT", + "UPDATE", + }, false), + }, + "payload_field": { + Type: schema.TypeString, + Optional: true, + }, + "range_key_field": { + Type: schema.TypeString, + Optional: true, + }, + "range_key_value": { + Type: schema.TypeString, + Optional: true, + }, + "range_key_type": { + Type: schema.TypeString, + Optional: true, + }, + names.AttrRoleARN: { + Type: schema.TypeString, + Required: true, + ValidateFunc: verify.ValidARN, + }, + names.AttrTableName: { + Type: schema.TypeString, + Required: true, + }, }, }, }, - }, - "dynamodbv2": { - Type: schema.TypeSet, - Optional: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "put_item": { - Type: schema.TypeList, - Optional: true, - MaxItems: 1, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - names.AttrTableName: { - Type: schema.TypeString, - Required: true, + "dynamodbv2": { + Type: schema.TypeSet, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "put_item": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + names.AttrTableName: { + Type: schema.TypeString, + Required: true, + }, }, }, }, - }, - names.AttrRoleARN: { - Type: schema.TypeString, - Required: true, - ValidateFunc: verify.ValidARN, + names.AttrRoleARN: { + Type: schema.TypeString, + Required: true, + ValidateFunc: verify.ValidARN, + }, }, }, }, - }, - "elasticsearch": { - Type: schema.TypeSet, - Optional: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - names.AttrEndpoint: { - Type: schema.TypeString, - Required: true, - ValidateFunc: validTopicRuleElasticsearchEndpoint, - }, - names.AttrID: { - Type: schema.TypeString, - Required: true, - }, - "index": { - Type: schema.TypeString, - Required: true, - }, - names.AttrRoleARN: { - Type: schema.TypeString, - Required: true, - ValidateFunc: verify.ValidARN, - }, - names.AttrType: { - Type: schema.TypeString, - Required: true, + "elasticsearch": { + Type: schema.TypeSet, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + names.AttrEndpoint: { + Type: schema.TypeString, + Required: true, + ValidateFunc: validTopicRuleElasticsearchEndpoint, + }, + names.AttrID: { + Type: schema.TypeString, + Required: true, + }, + "index": { + Type: schema.TypeString, + Required: true, + }, + names.AttrRoleARN: { + Type: schema.TypeString, + Required: true, + ValidateFunc: verify.ValidARN, + }, + names.AttrType: { + Type: schema.TypeString, + Required: true, + }, }, }, }, - }, - names.AttrEnabled: { - Type: schema.TypeBool, - Required: true, - }, - "error_action": { - Type: schema.TypeList, - Optional: true, - MaxItems: 1, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "cloudwatch_alarm": { - Type: schema.TypeList, - Optional: true, - MaxItems: 1, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "alarm_name": { - Type: schema.TypeString, - Required: true, - }, - names.AttrRoleARN: { - Type: schema.TypeString, - Required: true, - ValidateFunc: verify.ValidARN, - }, - "state_reason": { - Type: schema.TypeString, - Required: true, - }, - "state_value": { - Type: schema.TypeString, - Required: true, - ValidateFunc: validTopicRuleCloudWatchAlarmStateValue, + names.AttrEnabled: { + Type: schema.TypeBool, + Required: true, + }, + "error_action": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "cloudwatch_alarm": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "alarm_name": { + Type: schema.TypeString, + Required: true, + }, + names.AttrRoleARN: { + Type: schema.TypeString, + Required: true, + ValidateFunc: verify.ValidARN, + }, + "state_reason": { + Type: schema.TypeString, + Required: true, + }, + "state_value": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validTopicRuleCloudWatchAlarmStateValue, + }, }, }, + ExactlyOneOf: topicRuleErrorActionExactlyOneOf, }, - ExactlyOneOf: topicRuleErrorActionExactlyOneOf, - }, - names.AttrCloudWatchLogs: { - Type: schema.TypeList, - Optional: true, - MaxItems: 1, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - names.AttrLogGroupName: { - Type: schema.TypeString, - Required: true, - }, - names.AttrRoleARN: { - Type: schema.TypeString, - Required: true, - ValidateFunc: verify.ValidARN, + names.AttrCloudWatchLogs: { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + names.AttrLogGroupName: { + Type: schema.TypeString, + Required: true, + }, + names.AttrRoleARN: { + Type: schema.TypeString, + Required: true, + ValidateFunc: verify.ValidARN, + }, }, }, + ExactlyOneOf: topicRuleErrorActionExactlyOneOf, }, - ExactlyOneOf: topicRuleErrorActionExactlyOneOf, - }, - "cloudwatch_metric": { - Type: schema.TypeList, - Optional: true, - MaxItems: 1, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - names.AttrMetricName: { - Type: schema.TypeString, - Required: true, - }, - "metric_namespace": { - Type: schema.TypeString, - Required: true, - }, - "metric_timestamp": { - Type: schema.TypeString, - Optional: true, - ValidateFunc: verify.ValidUTCTimestamp, - }, - "metric_unit": { - Type: schema.TypeString, - Required: true, - }, - "metric_value": { - Type: schema.TypeString, - Required: true, - }, - names.AttrRoleARN: { - Type: schema.TypeString, - Required: true, - ValidateFunc: verify.ValidARN, + "cloudwatch_metric": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + names.AttrMetricName: { + Type: schema.TypeString, + Required: true, + }, + "metric_namespace": { + Type: schema.TypeString, + Required: true, + }, + "metric_timestamp": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: verify.ValidUTCTimestamp, + }, + "metric_unit": { + Type: schema.TypeString, + Required: true, + }, + "metric_value": { + Type: schema.TypeString, + Required: true, + }, + names.AttrRoleARN: { + Type: schema.TypeString, + Required: true, + ValidateFunc: verify.ValidARN, + }, }, }, + ExactlyOneOf: topicRuleErrorActionExactlyOneOf, }, - ExactlyOneOf: topicRuleErrorActionExactlyOneOf, - }, - "dynamodb": { - Type: schema.TypeList, - Optional: true, - MaxItems: 1, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "hash_key_field": { - Type: schema.TypeString, - Required: true, - }, - "hash_key_value": { - Type: schema.TypeString, - Required: true, - }, - "hash_key_type": { - Type: schema.TypeString, - Optional: true, - }, - "operation": { - Type: schema.TypeString, - Optional: true, - ValidateFunc: validation.StringInSlice([]string{ - "DELETE", - "INSERT", - "UPDATE", - }, false), - }, - "payload_field": { - Type: schema.TypeString, - Optional: true, - }, - "range_key_field": { - Type: schema.TypeString, - Optional: true, - }, - "range_key_value": { - Type: schema.TypeString, - Optional: true, - }, - "range_key_type": { - Type: schema.TypeString, - Optional: true, - }, - names.AttrRoleARN: { - Type: schema.TypeString, - Required: true, - ValidateFunc: verify.ValidARN, - }, - names.AttrTableName: { - Type: schema.TypeString, - Required: true, + "dynamodb": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "hash_key_field": { + Type: schema.TypeString, + Required: true, + }, + "hash_key_value": { + Type: schema.TypeString, + Required: true, + }, + "hash_key_type": { + Type: schema.TypeString, + Optional: true, + }, + "operation": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.StringInSlice([]string{ + "DELETE", + "INSERT", + "UPDATE", + }, false), + }, + "payload_field": { + Type: schema.TypeString, + Optional: true, + }, + "range_key_field": { + Type: schema.TypeString, + Optional: true, + }, + "range_key_value": { + Type: schema.TypeString, + Optional: true, + }, + "range_key_type": { + Type: schema.TypeString, + Optional: true, + }, + names.AttrRoleARN: { + Type: schema.TypeString, + Required: true, + ValidateFunc: verify.ValidARN, + }, + names.AttrTableName: { + Type: schema.TypeString, + Required: true, + }, }, }, + ExactlyOneOf: topicRuleErrorActionExactlyOneOf, }, - ExactlyOneOf: topicRuleErrorActionExactlyOneOf, - }, - "dynamodbv2": { - Type: schema.TypeList, - Optional: true, - MaxItems: 1, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "put_item": { - Type: schema.TypeList, - Optional: true, - MaxItems: 1, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - names.AttrTableName: { - Type: schema.TypeString, - Required: true, + "dynamodbv2": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "put_item": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + names.AttrTableName: { + Type: schema.TypeString, + Required: true, + }, }, }, }, - }, - names.AttrRoleARN: { - Type: schema.TypeString, - Required: true, - ValidateFunc: verify.ValidARN, + names.AttrRoleARN: { + Type: schema.TypeString, + Required: true, + ValidateFunc: verify.ValidARN, + }, }, }, + ExactlyOneOf: topicRuleErrorActionExactlyOneOf, }, - ExactlyOneOf: topicRuleErrorActionExactlyOneOf, - }, - "elasticsearch": { - Type: schema.TypeList, - Optional: true, - MaxItems: 1, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - names.AttrEndpoint: { - Type: schema.TypeString, - Required: true, - ValidateFunc: validTopicRuleElasticsearchEndpoint, - }, - names.AttrID: { - Type: schema.TypeString, - Required: true, - }, - "index": { - Type: schema.TypeString, - Required: true, - }, - names.AttrRoleARN: { - Type: schema.TypeString, - Required: true, - ValidateFunc: verify.ValidARN, - }, - names.AttrType: { - Type: schema.TypeString, - Required: true, + "elasticsearch": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + names.AttrEndpoint: { + Type: schema.TypeString, + Required: true, + ValidateFunc: validTopicRuleElasticsearchEndpoint, + }, + names.AttrID: { + Type: schema.TypeString, + Required: true, + }, + "index": { + Type: schema.TypeString, + Required: true, + }, + names.AttrRoleARN: { + Type: schema.TypeString, + Required: true, + ValidateFunc: verify.ValidARN, + }, + names.AttrType: { + Type: schema.TypeString, + Required: true, + }, }, }, + ExactlyOneOf: topicRuleErrorActionExactlyOneOf, }, - ExactlyOneOf: topicRuleErrorActionExactlyOneOf, - }, - "firehose": { - Type: schema.TypeList, - Optional: true, - MaxItems: 1, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "batch_mode": { - Type: schema.TypeBool, - Optional: true, - Default: false, - }, - "delivery_stream_name": { - Type: schema.TypeString, - Required: true, - }, - names.AttrRoleARN: { - Type: schema.TypeString, - Required: true, - ValidateFunc: verify.ValidARN, - }, - "separator": { - Type: schema.TypeString, - Optional: true, - ValidateFunc: validTopicRuleFirehoseSeparator, + "firehose": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "batch_mode": { + Type: schema.TypeBool, + Optional: true, + Default: false, + }, + "delivery_stream_name": { + Type: schema.TypeString, + Required: true, + }, + names.AttrRoleARN: { + Type: schema.TypeString, + Required: true, + ValidateFunc: verify.ValidARN, + }, + "separator": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validTopicRuleFirehoseSeparator, + }, }, }, + ExactlyOneOf: topicRuleErrorActionExactlyOneOf, }, - ExactlyOneOf: topicRuleErrorActionExactlyOneOf, - }, - "http": { - Type: schema.TypeList, - Optional: true, - MaxItems: 1, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "confirmation_url": { - Type: schema.TypeString, - Optional: true, - ValidateFunc: validation.IsURLWithHTTPS, - }, - "http_header": { - Type: schema.TypeList, - Optional: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - names.AttrKey: { - Type: schema.TypeString, - Required: true, - }, - names.AttrValue: { - Type: schema.TypeString, - Required: true, + "http": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "confirmation_url": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.IsURLWithHTTPS, + }, + "http_header": { + Type: schema.TypeList, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + names.AttrKey: { + Type: schema.TypeString, + Required: true, + }, + names.AttrValue: { + Type: schema.TypeString, + Required: true, + }, }, }, }, - }, - names.AttrURL: { - Type: schema.TypeString, - Required: true, - ValidateFunc: validation.IsURLWithHTTPS, + names.AttrURL: { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.IsURLWithHTTPS, + }, }, }, + ExactlyOneOf: topicRuleErrorActionExactlyOneOf, }, - ExactlyOneOf: topicRuleErrorActionExactlyOneOf, - }, - "iot_analytics": { - Type: schema.TypeList, - Optional: true, - MaxItems: 1, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "batch_mode": { - Type: schema.TypeBool, - Optional: true, - Default: false, - }, - "channel_name": { - Type: schema.TypeString, - Required: true, - }, - names.AttrRoleARN: { - Type: schema.TypeString, - Required: true, - ValidateFunc: verify.ValidARN, + "iot_analytics": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "batch_mode": { + Type: schema.TypeBool, + Optional: true, + Default: false, + }, + "channel_name": { + Type: schema.TypeString, + Required: true, + }, + names.AttrRoleARN: { + Type: schema.TypeString, + Required: true, + ValidateFunc: verify.ValidARN, + }, }, }, + ExactlyOneOf: topicRuleErrorActionExactlyOneOf, }, - ExactlyOneOf: topicRuleErrorActionExactlyOneOf, - }, - "iot_events": { - Type: schema.TypeList, - Optional: true, - MaxItems: 1, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "batch_mode": { - Type: schema.TypeBool, - Optional: true, - Default: false, - }, - "input_name": { - Type: schema.TypeString, - Required: true, - }, - "message_id": { - Type: schema.TypeString, - Optional: true, - }, - names.AttrRoleARN: { - Type: schema.TypeString, - Required: true, - ValidateFunc: verify.ValidARN, + "iot_events": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "batch_mode": { + Type: schema.TypeBool, + Optional: true, + Default: false, + }, + "input_name": { + Type: schema.TypeString, + Required: true, + }, + "message_id": { + Type: schema.TypeString, + Optional: true, + }, + names.AttrRoleARN: { + Type: schema.TypeString, + Required: true, + ValidateFunc: verify.ValidARN, + }, }, }, + ExactlyOneOf: topicRuleErrorActionExactlyOneOf, }, - ExactlyOneOf: topicRuleErrorActionExactlyOneOf, - }, - "kafka": { - Type: schema.TypeList, - Optional: true, - MaxItems: 1, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "client_properties": { - Type: schema.TypeMap, - Required: true, - Elem: &schema.Schema{Type: schema.TypeString}, - }, - names.AttrDestinationARN: { - Type: schema.TypeString, - Required: true, - ValidateFunc: verify.ValidARN, - }, - names.AttrHeader: { - Type: schema.TypeList, - Optional: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - names.AttrKey: { - Type: schema.TypeString, - Required: true, - }, - names.AttrValue: { - Type: schema.TypeString, - Required: true, + "kafka": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "client_properties": { + Type: schema.TypeMap, + Required: true, + Elem: &schema.Schema{Type: schema.TypeString}, + }, + names.AttrDestinationARN: { + Type: schema.TypeString, + Required: true, + ValidateFunc: verify.ValidARN, + }, + names.AttrHeader: { + Type: schema.TypeList, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + names.AttrKey: { + Type: schema.TypeString, + Required: true, + }, + names.AttrValue: { + Type: schema.TypeString, + Required: true, + }, }, }, }, - }, - names.AttrKey: { - Type: schema.TypeString, - Optional: true, - }, - "partition": { - Type: schema.TypeString, - Optional: true, - }, - "topic": { - Type: schema.TypeString, - Required: true, + names.AttrKey: { + Type: schema.TypeString, + Optional: true, + }, + "partition": { + Type: schema.TypeString, + Optional: true, + }, + "topic": { + Type: schema.TypeString, + Required: true, + }, }, }, + ExactlyOneOf: topicRuleErrorActionExactlyOneOf, }, - ExactlyOneOf: topicRuleErrorActionExactlyOneOf, - }, - "kinesis": { - Type: schema.TypeList, - Optional: true, - MaxItems: 1, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "partition_key": { - Type: schema.TypeString, - Optional: true, - }, - names.AttrRoleARN: { - Type: schema.TypeString, - Required: true, - ValidateFunc: verify.ValidARN, - }, - "stream_name": { - Type: schema.TypeString, - Required: true, + "kinesis": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "partition_key": { + Type: schema.TypeString, + Optional: true, + }, + names.AttrRoleARN: { + Type: schema.TypeString, + Required: true, + ValidateFunc: verify.ValidARN, + }, + "stream_name": { + Type: schema.TypeString, + Required: true, + }, }, }, + ExactlyOneOf: topicRuleErrorActionExactlyOneOf, }, - ExactlyOneOf: topicRuleErrorActionExactlyOneOf, - }, - "lambda": { - Type: schema.TypeList, - Optional: true, - MaxItems: 1, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - names.AttrFunctionARN: { - Type: schema.TypeString, - Required: true, - ValidateFunc: verify.ValidARN, + "lambda": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + names.AttrFunctionARN: { + Type: schema.TypeString, + Required: true, + ValidateFunc: verify.ValidARN, + }, }, }, + ExactlyOneOf: topicRuleErrorActionExactlyOneOf, }, - ExactlyOneOf: topicRuleErrorActionExactlyOneOf, - }, - "republish": { - Type: schema.TypeList, - Optional: true, - MaxItems: 1, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "qos": { - Type: schema.TypeInt, - Optional: true, - Default: 0, - ValidateFunc: validation.IntBetween(0, 1), - }, - names.AttrRoleARN: { - Type: schema.TypeString, - Required: true, - ValidateFunc: verify.ValidARN, - }, - "topic": { - Type: schema.TypeString, - Required: true, + "republish": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "qos": { + Type: schema.TypeInt, + Optional: true, + Default: 0, + ValidateFunc: validation.IntBetween(0, 1), + }, + names.AttrRoleARN: { + Type: schema.TypeString, + Required: true, + ValidateFunc: verify.ValidARN, + }, + "topic": { + Type: schema.TypeString, + Required: true, + }, }, }, + ExactlyOneOf: topicRuleErrorActionExactlyOneOf, }, - ExactlyOneOf: topicRuleErrorActionExactlyOneOf, - }, - "s3": { - Type: schema.TypeList, - Optional: true, - MaxItems: 1, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - names.AttrBucketName: { - Type: schema.TypeString, - Required: true, - }, - "canned_acl": { - Type: schema.TypeString, - Optional: true, - ValidateFunc: validation.StringInSlice(iot.CannedAccessControlList_Values(), false), - }, - names.AttrKey: { - Type: schema.TypeString, - Required: true, - }, - names.AttrRoleARN: { - Type: schema.TypeString, - Required: true, - ValidateFunc: verify.ValidARN, + "s3": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + names.AttrBucketName: { + Type: schema.TypeString, + Required: true, + }, + "canned_acl": { + Type: schema.TypeString, + Optional: true, + ValidateDiagFunc: enum.Validate[awstypes.CannedAccessControlList](), + }, + names.AttrKey: { + Type: schema.TypeString, + Required: true, + }, + names.AttrRoleARN: { + Type: schema.TypeString, + Required: true, + ValidateFunc: verify.ValidARN, + }, }, }, + ExactlyOneOf: topicRuleErrorActionExactlyOneOf, }, - ExactlyOneOf: topicRuleErrorActionExactlyOneOf, - }, - "sns": { - Type: schema.TypeList, - Optional: true, - MaxItems: 1, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "message_format": { - Type: schema.TypeString, - Default: iot.MessageFormatRaw, - Optional: true, - }, - names.AttrRoleARN: { - Type: schema.TypeString, - Required: true, - ValidateFunc: verify.ValidARN, - }, - names.AttrTargetARN: { - Type: schema.TypeString, - Required: true, - ValidateFunc: verify.ValidARN, + "sns": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "message_format": { + Type: schema.TypeString, + Default: awstypes.MessageFormatRaw, + Optional: true, + }, + names.AttrRoleARN: { + Type: schema.TypeString, + Required: true, + ValidateFunc: verify.ValidARN, + }, + names.AttrTargetARN: { + Type: schema.TypeString, + Required: true, + ValidateFunc: verify.ValidARN, + }, }, }, + ExactlyOneOf: topicRuleErrorActionExactlyOneOf, }, - ExactlyOneOf: topicRuleErrorActionExactlyOneOf, - }, - "sqs": { - Type: schema.TypeList, - Optional: true, - MaxItems: 1, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "queue_url": { - Type: schema.TypeString, - Required: true, - }, - names.AttrRoleARN: { - Type: schema.TypeString, - Required: true, - ValidateFunc: verify.ValidARN, - }, - "use_base64": { - Type: schema.TypeBool, - Required: true, + "sqs": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "queue_url": { + Type: schema.TypeString, + Required: true, + }, + names.AttrRoleARN: { + Type: schema.TypeString, + Required: true, + ValidateFunc: verify.ValidARN, + }, + "use_base64": { + Type: schema.TypeBool, + Required: true, + }, }, }, + ExactlyOneOf: topicRuleErrorActionExactlyOneOf, }, - ExactlyOneOf: topicRuleErrorActionExactlyOneOf, - }, - "step_functions": { - Type: schema.TypeList, - Optional: true, - MaxItems: 1, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "execution_name_prefix": { - Type: schema.TypeString, - Optional: true, - }, - names.AttrRoleARN: { - Type: schema.TypeString, - Required: true, - ValidateFunc: verify.ValidARN, - }, - "state_machine_name": { - Type: schema.TypeString, - Required: true, + "step_functions": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "execution_name_prefix": { + Type: schema.TypeString, + Optional: true, + }, + names.AttrRoleARN: { + Type: schema.TypeString, + Required: true, + ValidateFunc: verify.ValidARN, + }, + "state_machine_name": { + Type: schema.TypeString, + Required: true, + }, }, }, + ExactlyOneOf: topicRuleErrorActionExactlyOneOf, }, - ExactlyOneOf: topicRuleErrorActionExactlyOneOf, - }, - "timestream": { - Type: schema.TypeList, - Optional: true, - MaxItems: 1, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - names.AttrDatabaseName: { - Type: schema.TypeString, - Required: true, - }, - "dimension": { - Type: schema.TypeSet, - Required: true, - Elem: timestreamDimensionResource, - }, - names.AttrRoleARN: { - Type: schema.TypeString, - Required: true, - ValidateFunc: verify.ValidARN, - }, - names.AttrTableName: { - Type: schema.TypeString, - Required: true, - }, - "timestamp": { - Type: schema.TypeList, - Optional: true, - MaxItems: 1, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - names.AttrUnit: { - Type: schema.TypeString, - Required: true, - ValidateFunc: validation.StringInSlice([]string{ - "SECONDS", - "MILLISECONDS", - "MICROSECONDS", - "NANOSECONDS", - }, false), - }, - names.AttrValue: { - Type: schema.TypeString, - Required: true, + "timestream": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + names.AttrDatabaseName: { + Type: schema.TypeString, + Required: true, + }, + "dimension": { + Type: schema.TypeSet, + Required: true, + Elem: timestreamDimensionResource(), + }, + names.AttrRoleARN: { + Type: schema.TypeString, + Required: true, + ValidateFunc: verify.ValidARN, + }, + names.AttrTableName: { + Type: schema.TypeString, + Required: true, + }, + "timestamp": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + names.AttrUnit: { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringInSlice([]string{ + "SECONDS", + "MILLISECONDS", + "MICROSECONDS", + "NANOSECONDS", + }, false), + }, + names.AttrValue: { + Type: schema.TypeString, + Required: true, + }, }, }, }, }, }, + ExactlyOneOf: topicRuleErrorActionExactlyOneOf, }, - ExactlyOneOf: topicRuleErrorActionExactlyOneOf, }, }, }, - }, - "firehose": { - Type: schema.TypeSet, - Optional: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "batch_mode": { - Type: schema.TypeBool, - Optional: true, - Default: false, - }, - "delivery_stream_name": { - Type: schema.TypeString, - Required: true, - }, - names.AttrRoleARN: { - Type: schema.TypeString, - Required: true, - ValidateFunc: verify.ValidARN, - }, - "separator": { - Type: schema.TypeString, - Optional: true, - ValidateFunc: validTopicRuleFirehoseSeparator, + "firehose": { + Type: schema.TypeSet, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "batch_mode": { + Type: schema.TypeBool, + Optional: true, + Default: false, + }, + "delivery_stream_name": { + Type: schema.TypeString, + Required: true, + }, + names.AttrRoleARN: { + Type: schema.TypeString, + Required: true, + ValidateFunc: verify.ValidARN, + }, + "separator": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validTopicRuleFirehoseSeparator, + }, }, }, }, - }, - "http": { - Type: schema.TypeSet, - Optional: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "confirmation_url": { - Type: schema.TypeString, - Optional: true, - ValidateFunc: validation.IsURLWithHTTPS, - }, - "http_header": { - Type: schema.TypeList, - Optional: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - names.AttrKey: { - Type: schema.TypeString, - Required: true, - }, - names.AttrValue: { - Type: schema.TypeString, - Required: true, + "http": { + Type: schema.TypeSet, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "confirmation_url": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.IsURLWithHTTPS, + }, + "http_header": { + Type: schema.TypeList, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + names.AttrKey: { + Type: schema.TypeString, + Required: true, + }, + names.AttrValue: { + Type: schema.TypeString, + Required: true, + }, }, }, }, - }, - names.AttrURL: { - Type: schema.TypeString, - Required: true, - ValidateFunc: validation.IsURLWithHTTPS, + names.AttrURL: { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.IsURLWithHTTPS, + }, }, }, }, - }, - "iot_analytics": { - Type: schema.TypeSet, - Optional: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "batch_mode": { - Type: schema.TypeBool, - Optional: true, - Default: false, - }, - "channel_name": { - Type: schema.TypeString, - Required: true, - }, - names.AttrRoleARN: { - Type: schema.TypeString, - Required: true, - ValidateFunc: verify.ValidARN, + "iot_analytics": { + Type: schema.TypeSet, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "batch_mode": { + Type: schema.TypeBool, + Optional: true, + Default: false, + }, + "channel_name": { + Type: schema.TypeString, + Required: true, + }, + names.AttrRoleARN: { + Type: schema.TypeString, + Required: true, + ValidateFunc: verify.ValidARN, + }, }, }, }, - }, - "iot_events": { - Type: schema.TypeSet, - Optional: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "batch_mode": { - Type: schema.TypeBool, - Optional: true, - Default: false, - }, - "input_name": { - Type: schema.TypeString, - Required: true, - }, - "message_id": { - Type: schema.TypeString, - Optional: true, - }, - names.AttrRoleARN: { - Type: schema.TypeString, - Required: true, - ValidateFunc: verify.ValidARN, + "iot_events": { + Type: schema.TypeSet, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "batch_mode": { + Type: schema.TypeBool, + Optional: true, + Default: false, + }, + "input_name": { + Type: schema.TypeString, + Required: true, + }, + "message_id": { + Type: schema.TypeString, + Optional: true, + }, + names.AttrRoleARN: { + Type: schema.TypeString, + Required: true, + ValidateFunc: verify.ValidARN, + }, }, }, }, - }, - "kafka": { - Type: schema.TypeSet, - Optional: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "client_properties": { - Type: schema.TypeMap, - Required: true, - Elem: &schema.Schema{Type: schema.TypeString}, - }, - names.AttrDestinationARN: { - Type: schema.TypeString, - Required: true, - ValidateFunc: verify.ValidARN, - }, - names.AttrHeader: { - Type: schema.TypeList, - Optional: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - names.AttrKey: { - Type: schema.TypeString, - Required: true, - }, - names.AttrValue: { - Type: schema.TypeString, - Required: true, + "kafka": { + Type: schema.TypeSet, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "client_properties": { + Type: schema.TypeMap, + Required: true, + Elem: &schema.Schema{Type: schema.TypeString}, + }, + names.AttrDestinationARN: { + Type: schema.TypeString, + Required: true, + ValidateFunc: verify.ValidARN, + }, + names.AttrHeader: { + Type: schema.TypeList, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + names.AttrKey: { + Type: schema.TypeString, + Required: true, + }, + names.AttrValue: { + Type: schema.TypeString, + Required: true, + }, }, }, }, - }, - names.AttrKey: { - Type: schema.TypeString, - Optional: true, - }, - "partition": { - Type: schema.TypeString, - Optional: true, - }, - "topic": { - Type: schema.TypeString, - Required: true, + names.AttrKey: { + Type: schema.TypeString, + Optional: true, + }, + "partition": { + Type: schema.TypeString, + Optional: true, + }, + "topic": { + Type: schema.TypeString, + Required: true, + }, }, }, }, - }, - "kinesis": { - Type: schema.TypeSet, - Optional: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "partition_key": { - Type: schema.TypeString, - Optional: true, - }, - names.AttrRoleARN: { - Type: schema.TypeString, - Required: true, - ValidateFunc: verify.ValidARN, - }, - "stream_name": { - Type: schema.TypeString, - Required: true, + "kinesis": { + Type: schema.TypeSet, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "partition_key": { + Type: schema.TypeString, + Optional: true, + }, + names.AttrRoleARN: { + Type: schema.TypeString, + Required: true, + ValidateFunc: verify.ValidARN, + }, + "stream_name": { + Type: schema.TypeString, + Required: true, + }, }, }, }, - }, - "lambda": { - Type: schema.TypeSet, - Optional: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - names.AttrFunctionARN: { - Type: schema.TypeString, - Required: true, - ValidateFunc: verify.ValidARN, + "lambda": { + Type: schema.TypeSet, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + names.AttrFunctionARN: { + Type: schema.TypeString, + Required: true, + ValidateFunc: verify.ValidARN, + }, }, }, }, - }, - names.AttrName: { - Type: schema.TypeString, - Required: true, - ForceNew: true, - ValidateFunc: validTopicRuleName, - }, - "republish": { - Type: schema.TypeSet, - Optional: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "qos": { - Type: schema.TypeInt, - Optional: true, - Default: 0, - ValidateFunc: validation.IntBetween(0, 1), - }, - names.AttrRoleARN: { - Type: schema.TypeString, - Required: true, - ValidateFunc: verify.ValidARN, - }, - "topic": { - Type: schema.TypeString, - Required: true, + names.AttrName: { + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validTopicRuleName, + }, + "republish": { + Type: schema.TypeSet, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "qos": { + Type: schema.TypeInt, + Optional: true, + Default: 0, + ValidateFunc: validation.IntBetween(0, 1), + }, + names.AttrRoleARN: { + Type: schema.TypeString, + Required: true, + ValidateFunc: verify.ValidARN, + }, + "topic": { + Type: schema.TypeString, + Required: true, + }, }, }, }, - }, - "s3": { - Type: schema.TypeSet, - Optional: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - names.AttrBucketName: { - Type: schema.TypeString, - Required: true, - }, - "canned_acl": { - Type: schema.TypeString, - Optional: true, - ValidateFunc: validation.StringInSlice(iot.CannedAccessControlList_Values(), false), - }, - names.AttrKey: { - Type: schema.TypeString, - Required: true, - }, - names.AttrRoleARN: { - Type: schema.TypeString, - Required: true, - ValidateFunc: verify.ValidARN, + "s3": { + Type: schema.TypeSet, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + names.AttrBucketName: { + Type: schema.TypeString, + Required: true, + }, + "canned_acl": { + Type: schema.TypeString, + Optional: true, + ValidateDiagFunc: enum.Validate[awstypes.CannedAccessControlList](), + }, + names.AttrKey: { + Type: schema.TypeString, + Required: true, + }, + names.AttrRoleARN: { + Type: schema.TypeString, + Required: true, + ValidateFunc: verify.ValidARN, + }, }, }, }, - }, - "sns": { - Type: schema.TypeSet, - Optional: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "message_format": { - Type: schema.TypeString, - Optional: true, - Default: iot.MessageFormatRaw, - }, - names.AttrRoleARN: { - Type: schema.TypeString, - Required: true, - ValidateFunc: verify.ValidARN, - }, - names.AttrTargetARN: { - Type: schema.TypeString, - Required: true, - ValidateFunc: verify.ValidARN, + "sns": { + Type: schema.TypeSet, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "message_format": { + Type: schema.TypeString, + Optional: true, + Default: awstypes.MessageFormatRaw, + }, + names.AttrRoleARN: { + Type: schema.TypeString, + Required: true, + ValidateFunc: verify.ValidARN, + }, + names.AttrTargetARN: { + Type: schema.TypeString, + Required: true, + ValidateFunc: verify.ValidARN, + }, }, }, }, - }, - "sql": { - Type: schema.TypeString, - Required: true, - }, - "sql_version": { - Type: schema.TypeString, - Required: true, - }, - "sqs": { - Type: schema.TypeSet, - Optional: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "queue_url": { - Type: schema.TypeString, - Required: true, - }, - names.AttrRoleARN: { - Type: schema.TypeString, - Required: true, - ValidateFunc: verify.ValidARN, - }, - "use_base64": { - Type: schema.TypeBool, - Required: true, + "sql": { + Type: schema.TypeString, + Required: true, + }, + "sql_version": { + Type: schema.TypeString, + Required: true, + }, + "sqs": { + Type: schema.TypeSet, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "queue_url": { + Type: schema.TypeString, + Required: true, + }, + names.AttrRoleARN: { + Type: schema.TypeString, + Required: true, + ValidateFunc: verify.ValidARN, + }, + "use_base64": { + Type: schema.TypeBool, + Required: true, + }, }, }, }, - }, - "step_functions": { - Type: schema.TypeSet, - Optional: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "execution_name_prefix": { - Type: schema.TypeString, - Optional: true, - }, - names.AttrRoleARN: { - Type: schema.TypeString, - Required: true, - ValidateFunc: verify.ValidARN, - }, - "state_machine_name": { - Type: schema.TypeString, - Required: true, + "step_functions": { + Type: schema.TypeSet, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "execution_name_prefix": { + Type: schema.TypeString, + Optional: true, + }, + names.AttrRoleARN: { + Type: schema.TypeString, + Required: true, + ValidateFunc: verify.ValidARN, + }, + "state_machine_name": { + Type: schema.TypeString, + Required: true, + }, }, }, }, - }, - names.AttrTags: tftags.TagsSchema(), - names.AttrTagsAll: tftags.TagsSchemaComputed(), - "timestream": { - Type: schema.TypeSet, - Optional: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - names.AttrDatabaseName: { - Type: schema.TypeString, - Required: true, - }, - "dimension": { - Type: schema.TypeSet, - Required: true, - Elem: timestreamDimensionResource, - }, - names.AttrRoleARN: { - Type: schema.TypeString, - Required: true, - ValidateFunc: verify.ValidARN, - }, - names.AttrTableName: { - Type: schema.TypeString, - Required: true, - }, - "timestamp": { - Type: schema.TypeList, - Optional: true, - MaxItems: 1, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - names.AttrUnit: { - Type: schema.TypeString, - Required: true, - ValidateFunc: validation.StringInSlice([]string{ - "SECONDS", - "MILLISECONDS", - "MICROSECONDS", - "NANOSECONDS", - }, false), - }, - names.AttrValue: { - Type: schema.TypeString, - Required: true, + names.AttrTags: tftags.TagsSchema(), + names.AttrTagsAll: tftags.TagsSchemaComputed(), + "timestream": { + Type: schema.TypeSet, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + names.AttrDatabaseName: { + Type: schema.TypeString, + Required: true, + }, + "dimension": { + Type: schema.TypeSet, + Required: true, + Elem: timestreamDimensionResource(), + }, + names.AttrRoleARN: { + Type: schema.TypeString, + Required: true, + ValidateFunc: verify.ValidARN, + }, + names.AttrTableName: { + Type: schema.TypeString, + Required: true, + }, + "timestamp": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + names.AttrUnit: { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringInSlice([]string{ + "SECONDS", + "MILLISECONDS", + "MICROSECONDS", + "NANOSECONDS", + }, false), + }, + names.AttrValue: { + Type: schema.TypeString, + Required: true, + }, }, }, }, }, }, }, - }, + } }, CustomizeDiff: verify.SetTagsDiff, } } -var topicRuleErrorActionExactlyOneOf = []string{ - "error_action.0.cloudwatch_alarm", - "error_action.0.cloudwatch_logs", - "error_action.0.cloudwatch_metric", - "error_action.0.dynamodb", - "error_action.0.dynamodbv2", - "error_action.0.elasticsearch", - "error_action.0.firehose", - "error_action.0.http", - "error_action.0.iot_analytics", - "error_action.0.iot_events", - "error_action.0.kafka", - "error_action.0.kinesis", - "error_action.0.lambda", - "error_action.0.republish", - "error_action.0.s3", - "error_action.0.sns", - "error_action.0.sqs", - "error_action.0.step_functions", - "error_action.0.timestream", -} - -var timestreamDimensionResource *schema.Resource = &schema.Resource{ - Schema: map[string]*schema.Schema{ - names.AttrName: { - Type: schema.TypeString, - Required: true, - }, - names.AttrValue: { - Type: schema.TypeString, - Required: true, - }, - }, -} - func resourceTopicRuleCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { var diags diag.Diagnostics - conn := meta.(*conns.AWSClient).IoTConn(ctx) + conn := meta.(*conns.AWSClient).IoTClient(ctx) ruleName := d.Get(names.AttrName).(string) input := &iot.CreateTopicRuleInput{ @@ -1241,11 +1249,10 @@ func resourceTopicRuleCreate(ctx context.Context, d *schema.ResourceData, meta i TopicRulePayload: expandTopicRulePayload(d), } - _, err := tfresource.RetryWhenAWSErrMessageContains(ctx, propagationTimeout, + _, err := tfresource.RetryWhenIsA[*awstypes.InvalidRequestException](ctx, propagationTimeout, func() (interface{}, error) { - return conn.CreateTopicRuleWithContext(ctx, input) - }, - iot.ErrCodeInvalidRequestException, "sts:AssumeRole") + return conn.CreateTopicRule(ctx, input) + }) if err != nil { return sdkdiag.AppendErrorf(diags, "creating IoT Topic Rule (%s): %s", ruleName, err) @@ -1258,9 +1265,9 @@ func resourceTopicRuleCreate(ctx context.Context, d *schema.ResourceData, meta i func resourceTopicRuleRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { var diags diag.Diagnostics - conn := meta.(*conns.AWSClient).IoTConn(ctx) + conn := meta.(*conns.AWSClient).IoTClient(ctx) - output, err := FindTopicRuleByName(ctx, conn, d.Id()) + output, err := findTopicRuleByName(ctx, conn, d.Id()) if !d.IsNewResource() && tfresource.NotFound(err) { log.Printf("[WARN] IoT Topic Rule %s not found, removing from state", d.Id()) @@ -1275,7 +1282,7 @@ func resourceTopicRuleRead(ctx context.Context, d *schema.ResourceData, meta int d.Set(names.AttrARN, output.RuleArn) d.Set(names.AttrName, output.Rule.RuleName) d.Set(names.AttrDescription, output.Rule.Description) - d.Set(names.AttrEnabled, !aws.BoolValue(output.Rule.RuleDisabled)) + d.Set(names.AttrEnabled, !aws.ToBool(output.Rule.RuleDisabled)) d.Set("sql", output.Rule.Sql) d.Set("sql_version", output.Rule.AwsIotSqlVersion) @@ -1364,7 +1371,7 @@ func resourceTopicRuleRead(ctx context.Context, d *schema.ResourceData, meta int func resourceTopicRuleUpdate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { var diags diag.Diagnostics - conn := meta.(*conns.AWSClient).IoTConn(ctx) + conn := meta.(*conns.AWSClient).IoTClient(ctx) if d.HasChangesExcept(names.AttrTags, names.AttrTagsAll) { input := &iot.ReplaceTopicRuleInput{ @@ -1372,7 +1379,7 @@ func resourceTopicRuleUpdate(ctx context.Context, d *schema.ResourceData, meta i TopicRulePayload: expandTopicRulePayload(d), } - _, err := conn.ReplaceTopicRuleWithContext(ctx, input) + _, err := conn.ReplaceTopicRule(ctx, input) if err != nil { return sdkdiag.AppendErrorf(diags, "replacing IoT Topic Rule (%s): %s", d.Id(), err) @@ -1384,10 +1391,10 @@ func resourceTopicRuleUpdate(ctx context.Context, d *schema.ResourceData, meta i func resourceTopicRuleDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { var diags diag.Diagnostics - conn := meta.(*conns.AWSClient).IoTConn(ctx) + conn := meta.(*conns.AWSClient).IoTClient(ctx) log.Printf("[INFO] Deleting IoT Topic Rule: %s", d.Id()) - _, err := conn.DeleteTopicRuleWithContext(ctx, &iot.DeleteTopicRuleInput{ + _, err := conn.DeleteTopicRule(ctx, &iot.DeleteTopicRuleInput{ RuleName: aws.String(d.Id()), }) @@ -1398,12 +1405,65 @@ func resourceTopicRuleDelete(ctx context.Context, d *schema.ResourceData, meta i return diags } -func expandPutItemInput(tfList []interface{}) *iot.PutItemInput { +func findTopicRuleByName(ctx context.Context, conn *iot.Client, name string) (*iot.GetTopicRuleOutput, error) { + // GetTopicRule returns unhelpful errors such as + // "An error occurred (UnauthorizedException) when calling the GetTopicRule operation: Access to topic rule 'xxxxxxxx' was denied" + // when querying for a rule that doesn't exist. + inputL := &iot.ListTopicRulesInput{} + var rule *awstypes.TopicRuleListItem + + pages := iot.NewListTopicRulesPaginator(conn, inputL) +pageLoop: + for pages.HasMorePages() { + page, err := pages.NextPage(ctx) + + if err != nil { + return nil, err + } + + for _, v := range page.Rules { + v := v + if aws.ToString(v.RuleName) == name { + rule = &v + break pageLoop + } + } + } + + if rule == nil { + return nil, tfresource.NewEmptyResultError(nil) + } + + inputG := &iot.GetTopicRuleInput{ + RuleName: aws.String(name), + } + + output, err := conn.GetTopicRule(ctx, inputG) + + if errs.IsA[*awstypes.ResourceNotFoundException](err) { + return nil, &retry.NotFoundError{ + LastError: err, + LastRequest: inputG, + } + } + + if err != nil { + return nil, err + } + + if output == nil { + return nil, tfresource.NewEmptyResultError(inputG) + } + + return output, nil +} + +func expandPutItemInput(tfList []interface{}) *awstypes.PutItemInput { if len(tfList) == 0 || tfList[0] == nil { return nil } - apiObject := &iot.PutItemInput{} + apiObject := &awstypes.PutItemInput{} tfMap := tfList[0].(map[string]interface{}) if v, ok := tfMap[names.AttrTableName].(string); ok && v != "" { @@ -1413,12 +1473,12 @@ func expandPutItemInput(tfList []interface{}) *iot.PutItemInput { return apiObject } -func expandCloudWatchAlarmAction(tfList []interface{}) *iot.CloudwatchAlarmAction { +func expandCloudWatchAlarmAction(tfList []interface{}) *awstypes.CloudwatchAlarmAction { if len(tfList) == 0 || tfList[0] == nil { return nil } - apiObject := &iot.CloudwatchAlarmAction{} + apiObject := &awstypes.CloudwatchAlarmAction{} tfMap := tfList[0].(map[string]interface{}) if v, ok := tfMap["alarm_name"].(string); ok && v != "" { @@ -1440,12 +1500,12 @@ func expandCloudWatchAlarmAction(tfList []interface{}) *iot.CloudwatchAlarmActio return apiObject } -func expandCloudWatchLogsAction(tfList []interface{}) *iot.CloudwatchLogsAction { +func expandCloudWatchLogsAction(tfList []interface{}) *awstypes.CloudwatchLogsAction { if len(tfList) == 0 || tfList[0] == nil { return nil } - apiObject := &iot.CloudwatchLogsAction{} + apiObject := &awstypes.CloudwatchLogsAction{} tfMap := tfList[0].(map[string]interface{}) if v, ok := tfMap[names.AttrLogGroupName].(string); ok && v != "" { @@ -1459,12 +1519,12 @@ func expandCloudWatchLogsAction(tfList []interface{}) *iot.CloudwatchLogsAction return apiObject } -func expandCloudWatchMetricAction(tfList []interface{}) *iot.CloudwatchMetricAction { +func expandCloudWatchMetricAction(tfList []interface{}) *awstypes.CloudwatchMetricAction { if len(tfList) == 0 || tfList[0] == nil { return nil } - apiObject := &iot.CloudwatchMetricAction{} + apiObject := &awstypes.CloudwatchMetricAction{} tfMap := tfList[0].(map[string]interface{}) if v, ok := tfMap[names.AttrMetricName].(string); ok && v != "" { @@ -1494,12 +1554,12 @@ func expandCloudWatchMetricAction(tfList []interface{}) *iot.CloudwatchMetricAct return apiObject } -func expandDynamoDBAction(tfList []interface{}) *iot.DynamoDBAction { +func expandDynamoDBAction(tfList []interface{}) *awstypes.DynamoDBAction { if len(tfList) == 0 || tfList[0] == nil { return nil } - apiObject := &iot.DynamoDBAction{} + apiObject := &awstypes.DynamoDBAction{} tfMap := tfList[0].(map[string]interface{}) if v, ok := tfMap["hash_key_field"].(string); ok && v != "" { @@ -1507,7 +1567,7 @@ func expandDynamoDBAction(tfList []interface{}) *iot.DynamoDBAction { } if v, ok := tfMap["hash_key_type"].(string); ok && v != "" { - apiObject.HashKeyType = aws.String(v) + apiObject.HashKeyType = awstypes.DynamoKeyType(v) } if v, ok := tfMap["hash_key_value"].(string); ok && v != "" { @@ -1527,7 +1587,7 @@ func expandDynamoDBAction(tfList []interface{}) *iot.DynamoDBAction { } if v, ok := tfMap["range_key_type"].(string); ok && v != "" { - apiObject.RangeKeyType = aws.String(v) + apiObject.RangeKeyType = awstypes.DynamoKeyType(v) } if v, ok := tfMap["range_key_value"].(string); ok && v != "" { @@ -1545,12 +1605,12 @@ func expandDynamoDBAction(tfList []interface{}) *iot.DynamoDBAction { return apiObject } -func expandDynamoDBv2Action(tfList []interface{}) *iot.DynamoDBv2Action { +func expandDynamoDBv2Action(tfList []interface{}) *awstypes.DynamoDBv2Action { if len(tfList) == 0 || tfList[0] == nil { return nil } - apiObject := &iot.DynamoDBv2Action{} + apiObject := &awstypes.DynamoDBv2Action{} tfMap := tfList[0].(map[string]interface{}) if v, ok := tfMap["put_item"].([]interface{}); ok { @@ -1564,12 +1624,12 @@ func expandDynamoDBv2Action(tfList []interface{}) *iot.DynamoDBv2Action { return apiObject } -func expandElasticsearchAction(tfList []interface{}) *iot.ElasticsearchAction { +func expandElasticsearchAction(tfList []interface{}) *awstypes.ElasticsearchAction { if len(tfList) == 0 || tfList[0] == nil { return nil } - apiObject := &iot.ElasticsearchAction{} + apiObject := &awstypes.ElasticsearchAction{} tfMap := tfList[0].(map[string]interface{}) if v, ok := tfMap[names.AttrEndpoint].(string); ok && v != "" { @@ -1595,12 +1655,12 @@ func expandElasticsearchAction(tfList []interface{}) *iot.ElasticsearchAction { return apiObject } -func expandFirehoseAction(tfList []interface{}) *iot.FirehoseAction { +func expandFirehoseAction(tfList []interface{}) *awstypes.FirehoseAction { if len(tfList) == 0 || tfList[0] == nil { return nil } - apiObject := &iot.FirehoseAction{} + apiObject := &awstypes.FirehoseAction{} tfMap := tfList[0].(map[string]interface{}) if v, ok := tfMap["batch_mode"].(bool); ok { @@ -1622,12 +1682,12 @@ func expandFirehoseAction(tfList []interface{}) *iot.FirehoseAction { return apiObject } -func expandHTTPAction(tfList []interface{}) *iot.HttpAction { +func expandHTTPAction(tfList []interface{}) *awstypes.HttpAction { if len(tfList) == 0 || tfList[0] == nil { return nil } - apiObject := &iot.HttpAction{} + apiObject := &awstypes.HttpAction{} tfMap := tfList[0].(map[string]interface{}) if v, ok := tfMap[names.AttrURL].(string); ok && v != "" { @@ -1639,10 +1699,10 @@ func expandHTTPAction(tfList []interface{}) *iot.HttpAction { } if v, ok := tfMap["http_header"].([]interface{}); ok { - headerObjs := []*iot.HttpActionHeader{} + headerObjs := []awstypes.HttpActionHeader{} for _, val := range v { if m, ok := val.(map[string]interface{}); ok { - headerObj := &iot.HttpActionHeader{} + headerObj := awstypes.HttpActionHeader{} if v, ok := m[names.AttrKey].(string); ok && v != "" { headerObj.Key = aws.String(v) } @@ -1658,12 +1718,12 @@ func expandHTTPAction(tfList []interface{}) *iot.HttpAction { return apiObject } -func expandAnalyticsAction(tfList []interface{}) *iot.IotAnalyticsAction { +func expandAnalyticsAction(tfList []interface{}) *awstypes.IotAnalyticsAction { if len(tfList) == 0 || tfList[0] == nil { return nil } - apiObject := &iot.IotAnalyticsAction{} + apiObject := &awstypes.IotAnalyticsAction{} tfMap := tfList[0].(map[string]interface{}) if v, ok := tfMap["batch_mode"].(bool); ok { @@ -1681,12 +1741,12 @@ func expandAnalyticsAction(tfList []interface{}) *iot.IotAnalyticsAction { return apiObject } -func expandEventsAction(tfList []interface{}) *iot.IotEventsAction { +func expandEventsAction(tfList []interface{}) *awstypes.IotEventsAction { if len(tfList) == 0 || tfList[0] == nil { return nil } - apiObject := &iot.IotEventsAction{} + apiObject := &awstypes.IotEventsAction{} tfMap := tfList[0].(map[string]interface{}) if v, ok := tfMap["batch_mode"].(bool); ok { @@ -1708,16 +1768,16 @@ func expandEventsAction(tfList []interface{}) *iot.IotEventsAction { return apiObject } -func expandKafkaAction(tfList []interface{}) *iot.KafkaAction { +func expandKafkaAction(tfList []interface{}) *awstypes.KafkaAction { if len(tfList) == 0 || tfList[0] == nil { return nil } - apiObject := &iot.KafkaAction{} + apiObject := &awstypes.KafkaAction{} tfMap := tfList[0].(map[string]interface{}) if v, ok := tfMap["client_properties"].(map[string]interface{}); ok && len(v) > 0 { - apiObject.ClientProperties = flex.ExpandStringMap(v) + apiObject.ClientProperties = flex.ExpandStringValueMap(v) } if v, ok := tfMap[names.AttrDestinationARN].(string); ok && v != "" { @@ -1740,19 +1800,19 @@ func expandKafkaAction(tfList []interface{}) *iot.KafkaAction { apiObject.Topic = aws.String(v) } - if reflect.DeepEqual(&iot.KafkaAction{}, apiObject) { + if reflect.DeepEqual(&awstypes.KafkaAction{}, apiObject) { return nil } return apiObject } -func expandKafkaHeader(tfList []interface{}) []*iot.KafkaActionHeader { - var apiObjects []*iot.KafkaActionHeader +func expandKafkaHeader(tfList []interface{}) []awstypes.KafkaActionHeader { + var apiObjects []awstypes.KafkaActionHeader for _, elem := range tfList { tfMap := elem.(map[string]interface{}) - apiObject := &iot.KafkaActionHeader{} + apiObject := awstypes.KafkaActionHeader{} if v, ok := tfMap[names.AttrKey].(string); ok && v != "" { apiObject.Key = aws.String(v) } @@ -1767,12 +1827,12 @@ func expandKafkaHeader(tfList []interface{}) []*iot.KafkaActionHeader { return apiObjects } -func expandKinesisAction(tfList []interface{}) *iot.KinesisAction { +func expandKinesisAction(tfList []interface{}) *awstypes.KinesisAction { if len(tfList) == 0 || tfList[0] == nil { return nil } - apiObject := &iot.KinesisAction{} + apiObject := &awstypes.KinesisAction{} tfMap := tfList[0].(map[string]interface{}) if v, ok := tfMap["partition_key"].(string); ok && v != "" { @@ -1790,12 +1850,12 @@ func expandKinesisAction(tfList []interface{}) *iot.KinesisAction { return apiObject } -func expandLambdaAction(tfList []interface{}) *iot.LambdaAction { +func expandLambdaAction(tfList []interface{}) *awstypes.LambdaAction { if len(tfList) == 0 || tfList[0] == nil { return nil } - apiObject := &iot.LambdaAction{} + apiObject := &awstypes.LambdaAction{} tfMap := tfList[0].(map[string]interface{}) if v, ok := tfMap[names.AttrFunctionARN].(string); ok && v != "" { @@ -1805,16 +1865,16 @@ func expandLambdaAction(tfList []interface{}) *iot.LambdaAction { return apiObject } -func expandRepublishAction(tfList []interface{}) *iot.RepublishAction { +func expandRepublishAction(tfList []interface{}) *awstypes.RepublishAction { if len(tfList) == 0 || tfList[0] == nil { return nil } - apiObject := &iot.RepublishAction{} + apiObject := &awstypes.RepublishAction{} tfMap := tfList[0].(map[string]interface{}) if v, ok := tfMap["qos"].(int); ok { - apiObject.Qos = aws.Int64(int64(v)) + apiObject.Qos = aws.Int32(int32(v)) } if v, ok := tfMap[names.AttrRoleARN].(string); ok && v != "" { @@ -1828,12 +1888,12 @@ func expandRepublishAction(tfList []interface{}) *iot.RepublishAction { return apiObject } -func expandS3Action(tfList []interface{}) *iot.S3Action { +func expandS3Action(tfList []interface{}) *awstypes.S3Action { if len(tfList) == 0 || tfList[0] == nil { return nil } - apiObject := &iot.S3Action{} + apiObject := &awstypes.S3Action{} tfMap := tfList[0].(map[string]interface{}) if v, ok := tfMap[names.AttrBucketName].(string); ok && v != "" { @@ -1841,7 +1901,7 @@ func expandS3Action(tfList []interface{}) *iot.S3Action { } if v, ok := tfMap["canned_acl"].(string); ok && v != "" { - apiObject.CannedAcl = aws.String(v) + apiObject.CannedAcl = awstypes.CannedAccessControlList(v) } if v, ok := tfMap[names.AttrKey].(string); ok && v != "" { @@ -1855,16 +1915,16 @@ func expandS3Action(tfList []interface{}) *iot.S3Action { return apiObject } -func expandSNSAction(tfList []interface{}) *iot.SnsAction { +func expandSNSAction(tfList []interface{}) *awstypes.SnsAction { if len(tfList) == 0 || tfList[0] == nil { return nil } - apiObject := &iot.SnsAction{} + apiObject := &awstypes.SnsAction{} tfMap := tfList[0].(map[string]interface{}) if v, ok := tfMap["message_format"].(string); ok && v != "" { - apiObject.MessageFormat = aws.String(v) + apiObject.MessageFormat = awstypes.MessageFormat(v) } if v, ok := tfMap[names.AttrRoleARN].(string); ok && v != "" { @@ -1878,12 +1938,12 @@ func expandSNSAction(tfList []interface{}) *iot.SnsAction { return apiObject } -func expandSQSAction(tfList []interface{}) *iot.SqsAction { +func expandSQSAction(tfList []interface{}) *awstypes.SqsAction { if len(tfList) == 0 || tfList[0] == nil { return nil } - apiObject := &iot.SqsAction{} + apiObject := &awstypes.SqsAction{} tfMap := tfList[0].(map[string]interface{}) if v, ok := tfMap["queue_url"].(string); ok && v != "" { @@ -1901,12 +1961,12 @@ func expandSQSAction(tfList []interface{}) *iot.SqsAction { return apiObject } -func expandStepFunctionsAction(tfList []interface{}) *iot.StepFunctionsAction { +func expandStepFunctionsAction(tfList []interface{}) *awstypes.StepFunctionsAction { if len(tfList) == 0 || tfList[0] == nil { return nil } - apiObject := &iot.StepFunctionsAction{} + apiObject := &awstypes.StepFunctionsAction{} tfMap := tfList[0].(map[string]interface{}) if v, ok := tfMap["execution_name_prefix"].(string); ok && v != "" { @@ -1924,12 +1984,12 @@ func expandStepFunctionsAction(tfList []interface{}) *iot.StepFunctionsAction { return apiObject } -func expandTimestreamAction(tfList []interface{}) *iot.TimestreamAction { +func expandTimestreamAction(tfList []interface{}) *awstypes.TimestreamAction { if len(tfList) == 0 || tfList[0] == nil { return nil } - apiObject := &iot.TimestreamAction{} + apiObject := &awstypes.TimestreamAction{} tfMap := tfList[0].(map[string]interface{}) if v, ok := tfMap[names.AttrDatabaseName].(string); ok && v != "" { @@ -1955,15 +2015,15 @@ func expandTimestreamAction(tfList []interface{}) *iot.TimestreamAction { return apiObject } -func expandTimestreamDimensions(tfSet *schema.Set) []*iot.TimestreamDimension { +func expandTimestreamDimensions(tfSet *schema.Set) []awstypes.TimestreamDimension { if tfSet == nil || tfSet.Len() == 0 { return nil } - apiObjects := make([]*iot.TimestreamDimension, tfSet.Len()) + apiObjects := make([]awstypes.TimestreamDimension, tfSet.Len()) for i, elem := range tfSet.List() { if tfMap, ok := elem.(map[string]interface{}); ok { - apiObject := &iot.TimestreamDimension{} + apiObject := awstypes.TimestreamDimension{} if v, ok := tfMap[names.AttrName].(string); ok && v != "" { apiObject.Name = aws.String(v) @@ -1980,12 +2040,12 @@ func expandTimestreamDimensions(tfSet *schema.Set) []*iot.TimestreamDimension { return apiObjects } -func expandTimestreamTimestamp(tfList []interface{}) *iot.TimestreamTimestamp { +func expandTimestreamTimestamp(tfList []interface{}) *awstypes.TimestreamTimestamp { if len(tfList) == 0 || tfList[0] == nil { return nil } - apiObject := &iot.TimestreamTimestamp{} + apiObject := &awstypes.TimestreamTimestamp{} tfMap := tfList[0].(map[string]interface{}) if v, ok := tfMap[names.AttrUnit].(string); ok && v != "" { @@ -1999,8 +2059,8 @@ func expandTimestreamTimestamp(tfList []interface{}) *iot.TimestreamTimestamp { return apiObject } -func expandTopicRulePayload(d *schema.ResourceData) *iot.TopicRulePayload { - var actions []*iot.Action +func expandTopicRulePayload(d *schema.ResourceData) *awstypes.TopicRulePayload { + var actions []awstypes.Action // Legacy root attribute handling for _, tfMapRaw := range d.Get("cloudwatch_alarm").(*schema.Set).List() { @@ -2010,7 +2070,7 @@ func expandTopicRulePayload(d *schema.ResourceData) *iot.TopicRulePayload { continue } - actions = append(actions, &iot.Action{CloudwatchAlarm: action}) + actions = append(actions, awstypes.Action{CloudwatchAlarm: action}) } // Legacy root attribute handling @@ -2021,7 +2081,7 @@ func expandTopicRulePayload(d *schema.ResourceData) *iot.TopicRulePayload { continue } - actions = append(actions, &iot.Action{CloudwatchLogs: action}) + actions = append(actions, awstypes.Action{CloudwatchLogs: action}) } // Legacy root attribute handling @@ -2032,7 +2092,7 @@ func expandTopicRulePayload(d *schema.ResourceData) *iot.TopicRulePayload { continue } - actions = append(actions, &iot.Action{CloudwatchMetric: action}) + actions = append(actions, awstypes.Action{CloudwatchMetric: action}) } // Legacy root attribute handling @@ -2043,7 +2103,7 @@ func expandTopicRulePayload(d *schema.ResourceData) *iot.TopicRulePayload { continue } - actions = append(actions, &iot.Action{DynamoDB: action}) + actions = append(actions, awstypes.Action{DynamoDB: action}) } // Legacy root attribute handling @@ -2054,7 +2114,7 @@ func expandTopicRulePayload(d *schema.ResourceData) *iot.TopicRulePayload { continue } - actions = append(actions, &iot.Action{DynamoDBv2: action}) + actions = append(actions, awstypes.Action{DynamoDBv2: action}) } // Legacy root attribute handling @@ -2065,7 +2125,7 @@ func expandTopicRulePayload(d *schema.ResourceData) *iot.TopicRulePayload { continue } - actions = append(actions, &iot.Action{Elasticsearch: action}) + actions = append(actions, awstypes.Action{Elasticsearch: action}) } // Legacy root attribute handling @@ -2076,7 +2136,7 @@ func expandTopicRulePayload(d *schema.ResourceData) *iot.TopicRulePayload { continue } - actions = append(actions, &iot.Action{Firehose: action}) + actions = append(actions, awstypes.Action{Firehose: action}) } // Legacy root attribute handling @@ -2087,7 +2147,7 @@ func expandTopicRulePayload(d *schema.ResourceData) *iot.TopicRulePayload { continue } - actions = append(actions, &iot.Action{Http: action}) + actions = append(actions, awstypes.Action{Http: action}) } // Legacy root attribute handling @@ -2098,7 +2158,7 @@ func expandTopicRulePayload(d *schema.ResourceData) *iot.TopicRulePayload { continue } - actions = append(actions, &iot.Action{IotAnalytics: action}) + actions = append(actions, awstypes.Action{IotAnalytics: action}) } // Legacy root attribute handling @@ -2109,7 +2169,7 @@ func expandTopicRulePayload(d *schema.ResourceData) *iot.TopicRulePayload { continue } - actions = append(actions, &iot.Action{IotEvents: action}) + actions = append(actions, awstypes.Action{IotEvents: action}) } // Legacy root attribute handling @@ -2120,7 +2180,7 @@ func expandTopicRulePayload(d *schema.ResourceData) *iot.TopicRulePayload { continue } - actions = append(actions, &iot.Action{Kafka: action}) + actions = append(actions, awstypes.Action{Kafka: action}) } // Legacy root attribute handling @@ -2131,7 +2191,7 @@ func expandTopicRulePayload(d *schema.ResourceData) *iot.TopicRulePayload { continue } - actions = append(actions, &iot.Action{Kinesis: action}) + actions = append(actions, awstypes.Action{Kinesis: action}) } // Legacy root attribute handling @@ -2142,7 +2202,7 @@ func expandTopicRulePayload(d *schema.ResourceData) *iot.TopicRulePayload { continue } - actions = append(actions, &iot.Action{Lambda: action}) + actions = append(actions, awstypes.Action{Lambda: action}) } // Legacy root attribute handling @@ -2153,7 +2213,7 @@ func expandTopicRulePayload(d *schema.ResourceData) *iot.TopicRulePayload { continue } - actions = append(actions, &iot.Action{Republish: action}) + actions = append(actions, awstypes.Action{Republish: action}) } // Legacy root attribute handling @@ -2164,7 +2224,7 @@ func expandTopicRulePayload(d *schema.ResourceData) *iot.TopicRulePayload { continue } - actions = append(actions, &iot.Action{S3: action}) + actions = append(actions, awstypes.Action{S3: action}) } // Legacy root attribute handling @@ -2175,7 +2235,7 @@ func expandTopicRulePayload(d *schema.ResourceData) *iot.TopicRulePayload { continue } - actions = append(actions, &iot.Action{Sns: action}) + actions = append(actions, awstypes.Action{Sns: action}) } // Legacy root attribute handling @@ -2186,7 +2246,7 @@ func expandTopicRulePayload(d *schema.ResourceData) *iot.TopicRulePayload { continue } - actions = append(actions, &iot.Action{Sqs: action}) + actions = append(actions, awstypes.Action{Sqs: action}) } // Legacy root attribute handling @@ -2197,7 +2257,7 @@ func expandTopicRulePayload(d *schema.ResourceData) *iot.TopicRulePayload { continue } - actions = append(actions, &iot.Action{StepFunctions: action}) + actions = append(actions, awstypes.Action{StepFunctions: action}) } // Legacy root attribute handling @@ -2208,16 +2268,16 @@ func expandTopicRulePayload(d *schema.ResourceData) *iot.TopicRulePayload { continue } - actions = append(actions, &iot.Action{Timestream: action}) + actions = append(actions, awstypes.Action{Timestream: action}) } // Prevent sending empty Actions: // - missing required field, CreateTopicRuleInput.TopicRulePayload.Actions if len(actions) == 0 { - actions = []*iot.Action{} + actions = []awstypes.Action{} } - var iotErrorAction *iot.Action + var iotErrorAction *awstypes.Action errorAction := d.Get("error_action").([]interface{}) if len(errorAction) > 0 { for k, v := range errorAction[0].(map[string]interface{}) { @@ -2229,7 +2289,7 @@ func expandTopicRulePayload(d *schema.ResourceData) *iot.TopicRulePayload { continue } - iotErrorAction = &iot.Action{CloudwatchAlarm: action} + iotErrorAction = &awstypes.Action{CloudwatchAlarm: action} } case "cloudwatch_logs": for _, tfMapRaw := range v.([]interface{}) { @@ -2239,7 +2299,7 @@ func expandTopicRulePayload(d *schema.ResourceData) *iot.TopicRulePayload { continue } - iotErrorAction = &iot.Action{CloudwatchLogs: action} + iotErrorAction = &awstypes.Action{CloudwatchLogs: action} } case "cloudwatch_metric": for _, tfMapRaw := range v.([]interface{}) { @@ -2249,7 +2309,7 @@ func expandTopicRulePayload(d *schema.ResourceData) *iot.TopicRulePayload { continue } - iotErrorAction = &iot.Action{CloudwatchMetric: action} + iotErrorAction = &awstypes.Action{CloudwatchMetric: action} } case "dynamodb": for _, tfMapRaw := range v.([]interface{}) { @@ -2259,7 +2319,7 @@ func expandTopicRulePayload(d *schema.ResourceData) *iot.TopicRulePayload { continue } - iotErrorAction = &iot.Action{DynamoDB: action} + iotErrorAction = &awstypes.Action{DynamoDB: action} } case "dynamodbv2": for _, tfMapRaw := range v.([]interface{}) { @@ -2269,7 +2329,7 @@ func expandTopicRulePayload(d *schema.ResourceData) *iot.TopicRulePayload { continue } - iotErrorAction = &iot.Action{DynamoDBv2: action} + iotErrorAction = &awstypes.Action{DynamoDBv2: action} } case "elasticsearch": for _, tfMapRaw := range v.([]interface{}) { @@ -2279,7 +2339,7 @@ func expandTopicRulePayload(d *schema.ResourceData) *iot.TopicRulePayload { continue } - iotErrorAction = &iot.Action{Elasticsearch: action} + iotErrorAction = &awstypes.Action{Elasticsearch: action} } case "firehose": for _, tfMapRaw := range v.([]interface{}) { @@ -2289,7 +2349,7 @@ func expandTopicRulePayload(d *schema.ResourceData) *iot.TopicRulePayload { continue } - iotErrorAction = &iot.Action{Firehose: action} + iotErrorAction = &awstypes.Action{Firehose: action} } case "http": for _, tfMapRaw := range v.([]interface{}) { @@ -2299,7 +2359,7 @@ func expandTopicRulePayload(d *schema.ResourceData) *iot.TopicRulePayload { continue } - iotErrorAction = &iot.Action{Http: action} + iotErrorAction = &awstypes.Action{Http: action} } case "iot_analytics": for _, tfMapRaw := range v.([]interface{}) { @@ -2309,7 +2369,7 @@ func expandTopicRulePayload(d *schema.ResourceData) *iot.TopicRulePayload { continue } - iotErrorAction = &iot.Action{IotAnalytics: action} + iotErrorAction = &awstypes.Action{IotAnalytics: action} } case "iot_events": for _, tfMapRaw := range v.([]interface{}) { @@ -2319,7 +2379,7 @@ func expandTopicRulePayload(d *schema.ResourceData) *iot.TopicRulePayload { continue } - iotErrorAction = &iot.Action{IotEvents: action} + iotErrorAction = &awstypes.Action{IotEvents: action} } case "kafka": for _, tfMapRaw := range v.([]interface{}) { @@ -2329,7 +2389,7 @@ func expandTopicRulePayload(d *schema.ResourceData) *iot.TopicRulePayload { continue } - iotErrorAction = &iot.Action{Kafka: action} + iotErrorAction = &awstypes.Action{Kafka: action} } case "kinesis": for _, tfMapRaw := range v.([]interface{}) { @@ -2339,7 +2399,7 @@ func expandTopicRulePayload(d *schema.ResourceData) *iot.TopicRulePayload { continue } - iotErrorAction = &iot.Action{Kinesis: action} + iotErrorAction = &awstypes.Action{Kinesis: action} } case "lambda": for _, tfMapRaw := range v.([]interface{}) { @@ -2349,7 +2409,7 @@ func expandTopicRulePayload(d *schema.ResourceData) *iot.TopicRulePayload { continue } - iotErrorAction = &iot.Action{Lambda: action} + iotErrorAction = &awstypes.Action{Lambda: action} } case "republish": for _, tfMapRaw := range v.([]interface{}) { @@ -2359,7 +2419,7 @@ func expandTopicRulePayload(d *schema.ResourceData) *iot.TopicRulePayload { continue } - iotErrorAction = &iot.Action{Republish: action} + iotErrorAction = &awstypes.Action{Republish: action} } case "s3": for _, tfMapRaw := range v.([]interface{}) { @@ -2369,7 +2429,7 @@ func expandTopicRulePayload(d *schema.ResourceData) *iot.TopicRulePayload { continue } - iotErrorAction = &iot.Action{S3: action} + iotErrorAction = &awstypes.Action{S3: action} } case "sns": for _, tfMapRaw := range v.([]interface{}) { @@ -2379,7 +2439,7 @@ func expandTopicRulePayload(d *schema.ResourceData) *iot.TopicRulePayload { continue } - iotErrorAction = &iot.Action{Sns: action} + iotErrorAction = &awstypes.Action{Sns: action} } case "sqs": for _, tfMapRaw := range v.([]interface{}) { @@ -2389,7 +2449,7 @@ func expandTopicRulePayload(d *schema.ResourceData) *iot.TopicRulePayload { continue } - iotErrorAction = &iot.Action{Sqs: action} + iotErrorAction = &awstypes.Action{Sqs: action} } case "step_functions": for _, tfMapRaw := range v.([]interface{}) { @@ -2399,7 +2459,7 @@ func expandTopicRulePayload(d *schema.ResourceData) *iot.TopicRulePayload { continue } - iotErrorAction = &iot.Action{StepFunctions: action} + iotErrorAction = &awstypes.Action{StepFunctions: action} } case "timestream": for _, tfMapRaw := range v.([]interface{}) { @@ -2409,13 +2469,13 @@ func expandTopicRulePayload(d *schema.ResourceData) *iot.TopicRulePayload { continue } - iotErrorAction = &iot.Action{Timestream: action} + iotErrorAction = &awstypes.Action{Timestream: action} } } } } - return &iot.TopicRulePayload{ + return &awstypes.TopicRulePayload{ Actions: actions, AwsIotSqlVersion: aws.String(d.Get("sql_version").(string)), Description: aws.String(d.Get(names.AttrDescription).(string)), @@ -2425,7 +2485,7 @@ func expandTopicRulePayload(d *schema.ResourceData) *iot.TopicRulePayload { } } -func flattenCloudWatchAlarmAction(apiObject *iot.CloudwatchAlarmAction) []interface{} { +func flattenCloudWatchAlarmAction(apiObject *awstypes.CloudwatchAlarmAction) []interface{} { if apiObject == nil { return nil } @@ -2433,33 +2493,29 @@ func flattenCloudWatchAlarmAction(apiObject *iot.CloudwatchAlarmAction) []interf tfMap := make(map[string]interface{}) if v := apiObject.AlarmName; v != nil { - tfMap["alarm_name"] = aws.StringValue(v) + tfMap["alarm_name"] = aws.ToString(v) } if v := apiObject.RoleArn; v != nil { - tfMap[names.AttrRoleARN] = aws.StringValue(v) + tfMap[names.AttrRoleARN] = aws.ToString(v) } if v := apiObject.StateReason; v != nil { - tfMap["state_reason"] = aws.StringValue(v) + tfMap["state_reason"] = aws.ToString(v) } if v := apiObject.StateValue; v != nil { - tfMap["state_value"] = aws.StringValue(v) + tfMap["state_value"] = aws.ToString(v) } return []interface{}{tfMap} } // Legacy root attribute handling -func flattenCloudWatchAlarmActions(actions []*iot.Action) []interface{} { +func flattenCloudWatchAlarmActions(actions []awstypes.Action) []interface{} { results := make([]interface{}, 0) for _, action := range actions { - if action == nil { - continue - } - if v := action.CloudwatchAlarm; v != nil { results = append(results, flattenCloudWatchAlarmAction(v)...) } @@ -2468,7 +2524,7 @@ func flattenCloudWatchAlarmActions(actions []*iot.Action) []interface{} { return results } -func flattenCloudWatchLogsAction(apiObject *iot.CloudwatchLogsAction) []interface{} { +func flattenCloudWatchLogsAction(apiObject *awstypes.CloudwatchLogsAction) []interface{} { if apiObject == nil { return nil } @@ -2476,25 +2532,21 @@ func flattenCloudWatchLogsAction(apiObject *iot.CloudwatchLogsAction) []interfac tfMap := make(map[string]interface{}) if v := apiObject.LogGroupName; v != nil { - tfMap[names.AttrLogGroupName] = aws.StringValue(v) + tfMap[names.AttrLogGroupName] = aws.ToString(v) } if v := apiObject.RoleArn; v != nil { - tfMap[names.AttrRoleARN] = aws.StringValue(v) + tfMap[names.AttrRoleARN] = aws.ToString(v) } return []interface{}{tfMap} } // Legacy root attribute handling -func flattenCloudWatchLogsActions(actions []*iot.Action) []interface{} { +func flattenCloudWatchLogsActions(actions []awstypes.Action) []interface{} { results := make([]interface{}, 0) for _, action := range actions { - if action == nil { - continue - } - if v := action.CloudwatchLogs; v != nil { results = append(results, flattenCloudWatchLogsAction(v)...) } @@ -2504,14 +2556,10 @@ func flattenCloudWatchLogsActions(actions []*iot.Action) []interface{} { } // Legacy root attribute handling -func flattenCloudWatchMetricActions(actions []*iot.Action) []interface{} { +func flattenCloudWatchMetricActions(actions []awstypes.Action) []interface{} { results := make([]interface{}, 0) for _, action := range actions { - if action == nil { - continue - } - if v := action.CloudwatchMetric; v != nil { results = append(results, flattenCloudWatchMetricAction(v)...) } @@ -2520,7 +2568,7 @@ func flattenCloudWatchMetricActions(actions []*iot.Action) []interface{} { return results } -func flattenCloudWatchMetricAction(apiObject *iot.CloudwatchMetricAction) []interface{} { +func flattenCloudWatchMetricAction(apiObject *awstypes.CloudwatchMetricAction) []interface{} { if apiObject == nil { return nil } @@ -2528,41 +2576,37 @@ func flattenCloudWatchMetricAction(apiObject *iot.CloudwatchMetricAction) []inte tfMap := make(map[string]interface{}) if v := apiObject.MetricName; v != nil { - tfMap[names.AttrMetricName] = aws.StringValue(v) + tfMap[names.AttrMetricName] = aws.ToString(v) } if v := apiObject.MetricNamespace; v != nil { - tfMap["metric_namespace"] = aws.StringValue(v) + tfMap["metric_namespace"] = aws.ToString(v) } if v := apiObject.MetricTimestamp; v != nil { - tfMap["metric_timestamp"] = aws.StringValue(v) + tfMap["metric_timestamp"] = aws.ToString(v) } if v := apiObject.MetricUnit; v != nil { - tfMap["metric_unit"] = aws.StringValue(v) + tfMap["metric_unit"] = aws.ToString(v) } if v := apiObject.MetricValue; v != nil { - tfMap["metric_value"] = aws.StringValue(v) + tfMap["metric_value"] = aws.ToString(v) } if v := apiObject.RoleArn; v != nil { - tfMap[names.AttrRoleARN] = aws.StringValue(v) + tfMap[names.AttrRoleARN] = aws.ToString(v) } return []interface{}{tfMap} } // Legacy root attribute handling -func flattenDynamoDBActions(actions []*iot.Action) []interface{} { +func flattenDynamoDBActions(actions []awstypes.Action) []interface{} { results := make([]interface{}, 0) for _, action := range actions { - if action == nil { - continue - } - if v := action.DynamoDB; v != nil { results = append(results, flattenDynamoDBAction(v)...) } @@ -2571,7 +2615,7 @@ func flattenDynamoDBActions(actions []*iot.Action) []interface{} { return results } -func flattenDynamoDBAction(apiObject *iot.DynamoDBAction) []interface{} { +func flattenDynamoDBAction(apiObject *awstypes.DynamoDBAction) []interface{} { if apiObject == nil { return nil } @@ -2579,57 +2623,49 @@ func flattenDynamoDBAction(apiObject *iot.DynamoDBAction) []interface{} { tfMap := make(map[string]interface{}) if v := apiObject.HashKeyField; v != nil { - tfMap["hash_key_field"] = aws.StringValue(v) + tfMap["hash_key_field"] = aws.ToString(v) } - if v := apiObject.HashKeyType; v != nil { - tfMap["hash_key_type"] = aws.StringValue(v) - } + tfMap["hash_key_type"] = apiObject.HashKeyType if v := apiObject.HashKeyValue; v != nil { - tfMap["hash_key_value"] = aws.StringValue(v) + tfMap["hash_key_value"] = aws.ToString(v) } if v := apiObject.PayloadField; v != nil { - tfMap["payload_field"] = aws.StringValue(v) + tfMap["payload_field"] = aws.ToString(v) } if v := apiObject.Operation; v != nil { - tfMap["operation"] = aws.StringValue(v) + tfMap["operation"] = aws.ToString(v) } if v := apiObject.RangeKeyField; v != nil { - tfMap["range_key_field"] = aws.StringValue(v) + tfMap["range_key_field"] = aws.ToString(v) } - if v := apiObject.RangeKeyType; v != nil { - tfMap["range_key_type"] = aws.StringValue(v) - } + tfMap["range_key_type"] = apiObject.RangeKeyType if v := apiObject.RangeKeyValue; v != nil { - tfMap["range_key_value"] = aws.StringValue(v) + tfMap["range_key_value"] = aws.ToString(v) } if v := apiObject.RoleArn; v != nil { - tfMap[names.AttrRoleARN] = aws.StringValue(v) + tfMap[names.AttrRoleARN] = aws.ToString(v) } if v := apiObject.TableName; v != nil { - tfMap[names.AttrTableName] = aws.StringValue(v) + tfMap[names.AttrTableName] = aws.ToString(v) } return []interface{}{tfMap} } // Legacy root attribute handling -func flattenDynamoDBv2Actions(actions []*iot.Action) []interface{} { +func flattenDynamoDBv2Actions(actions []awstypes.Action) []interface{} { results := make([]interface{}, 0) for _, action := range actions { - if action == nil { - continue - } - if v := action.DynamoDBv2; v != nil { results = append(results, flattenDynamoDBv2Action(v)...) } @@ -2638,7 +2674,7 @@ func flattenDynamoDBv2Actions(actions []*iot.Action) []interface{} { return results } -func flattenDynamoDBv2Action(apiObject *iot.DynamoDBv2Action) []interface{} { +func flattenDynamoDBv2Action(apiObject *awstypes.DynamoDBv2Action) []interface{} { if apiObject == nil { return nil } @@ -2650,21 +2686,17 @@ func flattenDynamoDBv2Action(apiObject *iot.DynamoDBv2Action) []interface{} { } if v := apiObject.RoleArn; v != nil { - tfMap[names.AttrRoleARN] = aws.StringValue(v) + tfMap[names.AttrRoleARN] = aws.ToString(v) } return []interface{}{tfMap} } // Legacy root attribute handling -func flattenElasticsearchActions(actions []*iot.Action) []interface{} { +func flattenElasticsearchActions(actions []awstypes.Action) []interface{} { results := make([]interface{}, 0) for _, action := range actions { - if action == nil { - continue - } - if v := action.Elasticsearch; v != nil { results = append(results, flattenElasticsearchAction(v)...) } @@ -2673,7 +2705,7 @@ func flattenElasticsearchActions(actions []*iot.Action) []interface{} { return results } -func flattenElasticsearchAction(apiObject *iot.ElasticsearchAction) []interface{} { +func flattenElasticsearchAction(apiObject *awstypes.ElasticsearchAction) []interface{} { if apiObject == nil { return nil } @@ -2681,37 +2713,33 @@ func flattenElasticsearchAction(apiObject *iot.ElasticsearchAction) []interface{ tfMap := make(map[string]interface{}) if v := apiObject.Endpoint; v != nil { - tfMap[names.AttrEndpoint] = aws.StringValue(v) + tfMap[names.AttrEndpoint] = aws.ToString(v) } if v := apiObject.Id; v != nil { - tfMap[names.AttrID] = aws.StringValue(v) + tfMap[names.AttrID] = aws.ToString(v) } if v := apiObject.Index; v != nil { - tfMap["index"] = aws.StringValue(v) + tfMap["index"] = aws.ToString(v) } if v := apiObject.Type; v != nil { - tfMap[names.AttrType] = aws.StringValue(v) + tfMap[names.AttrType] = aws.ToString(v) } if v := apiObject.RoleArn; v != nil { - tfMap[names.AttrRoleARN] = aws.StringValue(v) + tfMap[names.AttrRoleARN] = aws.ToString(v) } return []interface{}{tfMap} } // Legacy root attribute handling -func flattenFirehoseActions(actions []*iot.Action) []interface{} { +func flattenFirehoseActions(actions []awstypes.Action) []interface{} { results := make([]interface{}, 0) for _, action := range actions { - if action == nil { - continue - } - if v := action.Firehose; v != nil { results = append(results, flattenFirehoseAction(v)...) } @@ -2720,7 +2748,7 @@ func flattenFirehoseActions(actions []*iot.Action) []interface{} { return results } -func flattenFirehoseAction(apiObject *iot.FirehoseAction) []interface{} { +func flattenFirehoseAction(apiObject *awstypes.FirehoseAction) []interface{} { if apiObject == nil { return nil } @@ -2728,33 +2756,29 @@ func flattenFirehoseAction(apiObject *iot.FirehoseAction) []interface{} { tfMap := make(map[string]interface{}) if v := apiObject.BatchMode; v != nil { - tfMap["batch_mode"] = aws.BoolValue(v) + tfMap["batch_mode"] = aws.ToBool(v) } if v := apiObject.DeliveryStreamName; v != nil { - tfMap["delivery_stream_name"] = aws.StringValue(v) + tfMap["delivery_stream_name"] = aws.ToString(v) } if v := apiObject.RoleArn; v != nil { - tfMap[names.AttrRoleARN] = aws.StringValue(v) + tfMap[names.AttrRoleARN] = aws.ToString(v) } if v := apiObject.Separator; v != nil { - tfMap["separator"] = aws.StringValue(v) + tfMap["separator"] = aws.ToString(v) } return []interface{}{tfMap} } // Legacy root attribute handling -func flattenHTTPActions(actions []*iot.Action) []interface{} { +func flattenHTTPActions(actions []awstypes.Action) []interface{} { results := make([]interface{}, 0) for _, action := range actions { - if action == nil { - continue - } - if v := action.Http; v != nil { results = append(results, flattenHTTPAction(v)...) } @@ -2763,7 +2787,7 @@ func flattenHTTPActions(actions []*iot.Action) []interface{} { return results } -func flattenHTTPAction(apiObject *iot.HttpAction) []interface{} { +func flattenHTTPAction(apiObject *awstypes.HttpAction) []interface{} { if apiObject == nil { return nil } @@ -2771,11 +2795,11 @@ func flattenHTTPAction(apiObject *iot.HttpAction) []interface{} { tfMap := make(map[string]interface{}) if v := apiObject.Url; v != nil { - tfMap[names.AttrURL] = aws.StringValue(v) + tfMap[names.AttrURL] = aws.ToString(v) } if v := apiObject.ConfirmationUrl; v != nil { - tfMap["confirmation_url"] = aws.StringValue(v) + tfMap["confirmation_url"] = aws.ToString(v) } if v := apiObject.Headers; v != nil { @@ -2783,8 +2807,8 @@ func flattenHTTPAction(apiObject *iot.HttpAction) []interface{} { for _, h := range v { m := map[string]string{ - names.AttrKey: aws.StringValue(h.Key), - names.AttrValue: aws.StringValue(h.Value), + names.AttrKey: aws.ToString(h.Key), + names.AttrValue: aws.ToString(h.Value), } headers = append(headers, m) } @@ -2795,14 +2819,10 @@ func flattenHTTPAction(apiObject *iot.HttpAction) []interface{} { } // Legacy root attribute handling -func flattenAnalyticsActions(actions []*iot.Action) []interface{} { +func flattenAnalyticsActions(actions []awstypes.Action) []interface{} { results := make([]interface{}, 0) for _, action := range actions { - if action == nil { - continue - } - if v := action.IotAnalytics; v != nil { results = append(results, flattenAnalyticsAction(v)...) } @@ -2811,7 +2831,7 @@ func flattenAnalyticsActions(actions []*iot.Action) []interface{} { return results } -func flattenAnalyticsAction(apiObject *iot.IotAnalyticsAction) []interface{} { +func flattenAnalyticsAction(apiObject *awstypes.IotAnalyticsAction) []interface{} { if apiObject == nil { return nil } @@ -2819,29 +2839,25 @@ func flattenAnalyticsAction(apiObject *iot.IotAnalyticsAction) []interface{} { tfMap := make(map[string]interface{}) if v := apiObject.BatchMode; v != nil { - tfMap["batch_mode"] = aws.BoolValue(v) + tfMap["batch_mode"] = aws.ToBool(v) } if v := apiObject.ChannelName; v != nil { - tfMap["channel_name"] = aws.StringValue(v) + tfMap["channel_name"] = aws.ToString(v) } if v := apiObject.RoleArn; v != nil { - tfMap[names.AttrRoleARN] = aws.StringValue(v) + tfMap[names.AttrRoleARN] = aws.ToString(v) } return []interface{}{tfMap} } // Legacy root attribute handling -func flattenEventsActions(actions []*iot.Action) []interface{} { +func flattenEventsActions(actions []awstypes.Action) []interface{} { results := make([]interface{}, 0) for _, action := range actions { - if action == nil { - continue - } - if v := action.IotEvents; v != nil { results = append(results, flattenEventsAction(v)...) } @@ -2850,7 +2866,7 @@ func flattenEventsActions(actions []*iot.Action) []interface{} { return results } -func flattenEventsAction(apiObject *iot.IotEventsAction) []interface{} { +func flattenEventsAction(apiObject *awstypes.IotEventsAction) []interface{} { if apiObject == nil { return nil } @@ -2858,33 +2874,29 @@ func flattenEventsAction(apiObject *iot.IotEventsAction) []interface{} { tfMap := make(map[string]interface{}) if v := apiObject.BatchMode; v != nil { - tfMap["batch_mode"] = aws.BoolValue(v) + tfMap["batch_mode"] = aws.ToBool(v) } if v := apiObject.InputName; v != nil { - tfMap["input_name"] = aws.StringValue(v) + tfMap["input_name"] = aws.ToString(v) } if v := apiObject.MessageId; v != nil { - tfMap["message_id"] = aws.StringValue(v) + tfMap["message_id"] = aws.ToString(v) } if v := apiObject.RoleArn; v != nil { - tfMap[names.AttrRoleARN] = aws.StringValue(v) + tfMap[names.AttrRoleARN] = aws.ToString(v) } return []interface{}{tfMap} } // Legacy root attribute handling -func flattenKafkaActions(actions []*iot.Action) []interface{} { +func flattenKafkaActions(actions []awstypes.Action) []interface{} { results := make([]interface{}, 0) for _, action := range actions { - if action == nil { - continue - } - if v := action.Kafka; v != nil { results = append(results, flattenKafkaAction(v)...) } @@ -2893,7 +2905,7 @@ func flattenKafkaActions(actions []*iot.Action) []interface{} { return results } -func flattenKafkaAction(apiObject *iot.KafkaAction) []interface{} { +func flattenKafkaAction(apiObject *awstypes.KafkaAction) []interface{} { if apiObject == nil { return nil } @@ -2901,11 +2913,11 @@ func flattenKafkaAction(apiObject *iot.KafkaAction) []interface{} { tfMap := make(map[string]interface{}) if v := apiObject.ClientProperties; v != nil { - tfMap["client_properties"] = aws.StringValueMap(v) + tfMap["client_properties"] = aws.StringMap(v) } if v := apiObject.DestinationArn; v != nil { - tfMap[names.AttrDestinationARN] = aws.StringValue(v) + tfMap[names.AttrDestinationARN] = aws.ToString(v) } if v := apiObject.Headers; v != nil { @@ -2913,51 +2925,44 @@ func flattenKafkaAction(apiObject *iot.KafkaAction) []interface{} { } if v := apiObject.Key; v != nil { - tfMap[names.AttrKey] = aws.StringValue(v) + tfMap[names.AttrKey] = aws.ToString(v) } if v := apiObject.Partition; v != nil { - tfMap["partition"] = aws.StringValue(v) + tfMap["partition"] = aws.ToString(v) } if v := apiObject.Topic; v != nil { - tfMap["topic"] = aws.StringValue(v) + tfMap["topic"] = aws.ToString(v) } return []interface{}{tfMap} } -func flattenKafkaHeaders(apiObjects []*iot.KafkaActionHeader) []interface{} { +func flattenKafkaHeaders(apiObjects []awstypes.KafkaActionHeader) []interface{} { results := make([]interface{}, 0) for _, apiObject := range apiObjects { - if apiObject != nil { - tfMap := make(map[string]interface{}) + tfMap := make(map[string]interface{}) - if v := apiObject.Key; v != nil { - tfMap[names.AttrKey] = aws.StringValue(v) - } - - if v := apiObject.Value; v != nil { - tfMap[names.AttrValue] = aws.StringValue(v) - } + if v := apiObject.Key; v != nil { + tfMap[names.AttrKey] = aws.ToString(v) + } - results = append(results, tfMap) + if v := apiObject.Value; v != nil { + tfMap[names.AttrValue] = aws.ToString(v) } + results = append(results, tfMap) } return results } // Legacy root attribute handling -func flattenKinesisActions(actions []*iot.Action) []interface{} { +func flattenKinesisActions(actions []awstypes.Action) []interface{} { results := make([]interface{}, 0) for _, action := range actions { - if action == nil { - continue - } - if v := action.Kinesis; v != nil { results = append(results, flattenKinesisAction(v)...) } @@ -2966,7 +2971,7 @@ func flattenKinesisActions(actions []*iot.Action) []interface{} { return results } -func flattenKinesisAction(apiObject *iot.KinesisAction) []interface{} { +func flattenKinesisAction(apiObject *awstypes.KinesisAction) []interface{} { if apiObject == nil { return nil } @@ -2974,29 +2979,25 @@ func flattenKinesisAction(apiObject *iot.KinesisAction) []interface{} { tfMap := make(map[string]interface{}) if v := apiObject.PartitionKey; v != nil { - tfMap["partition_key"] = aws.StringValue(v) + tfMap["partition_key"] = aws.ToString(v) } if v := apiObject.RoleArn; v != nil { - tfMap[names.AttrRoleARN] = aws.StringValue(v) + tfMap[names.AttrRoleARN] = aws.ToString(v) } if v := apiObject.StreamName; v != nil { - tfMap["stream_name"] = aws.StringValue(v) + tfMap["stream_name"] = aws.ToString(v) } return []interface{}{tfMap} } // Legacy root attribute handling -func flattenLambdaActions(actions []*iot.Action) []interface{} { +func flattenLambdaActions(actions []awstypes.Action) []interface{} { results := make([]interface{}, 0) for _, action := range actions { - if action == nil { - continue - } - if v := action.Lambda; v != nil { results = append(results, flattenLambdaAction(v)...) } @@ -3005,7 +3006,7 @@ func flattenLambdaActions(actions []*iot.Action) []interface{} { return results } -func flattenLambdaAction(apiObject *iot.LambdaAction) []interface{} { +func flattenLambdaAction(apiObject *awstypes.LambdaAction) []interface{} { if apiObject == nil { return nil } @@ -3013,13 +3014,13 @@ func flattenLambdaAction(apiObject *iot.LambdaAction) []interface{} { tfMap := make(map[string]interface{}) if v := apiObject.FunctionArn; v != nil { - tfMap[names.AttrFunctionARN] = aws.StringValue(v) + tfMap[names.AttrFunctionARN] = aws.ToString(v) } return []interface{}{tfMap} } -func flattenPutItemInput(apiObject *iot.PutItemInput) []interface{} { +func flattenPutItemInput(apiObject *awstypes.PutItemInput) []interface{} { if apiObject == nil { return nil } @@ -3027,21 +3028,17 @@ func flattenPutItemInput(apiObject *iot.PutItemInput) []interface{} { tfMap := make(map[string]interface{}) if v := apiObject.TableName; v != nil { - tfMap[names.AttrTableName] = aws.StringValue(v) + tfMap[names.AttrTableName] = aws.ToString(v) } return []interface{}{tfMap} } // Legacy root attribute handling -func flattenRepublishActions(actions []*iot.Action) []interface{} { +func flattenRepublishActions(actions []awstypes.Action) []interface{} { results := make([]interface{}, 0) for _, action := range actions { - if action == nil { - continue - } - if v := action.Republish; v != nil { results = append(results, flattenRepublishAction(v)...) } @@ -3050,7 +3047,7 @@ func flattenRepublishActions(actions []*iot.Action) []interface{} { return results } -func flattenRepublishAction(apiObject *iot.RepublishAction) []interface{} { +func flattenRepublishAction(apiObject *awstypes.RepublishAction) []interface{} { if apiObject == nil { return nil } @@ -3058,29 +3055,25 @@ func flattenRepublishAction(apiObject *iot.RepublishAction) []interface{} { tfMap := make(map[string]interface{}) if v := apiObject.Qos; v != nil { - tfMap["qos"] = aws.Int64Value(v) + tfMap["qos"] = aws.ToInt32(v) } if v := apiObject.RoleArn; v != nil { - tfMap[names.AttrRoleARN] = aws.StringValue(v) + tfMap[names.AttrRoleARN] = aws.ToString(v) } if v := apiObject.Topic; v != nil { - tfMap["topic"] = aws.StringValue(v) + tfMap["topic"] = aws.ToString(v) } return []interface{}{tfMap} } // Legacy root attribute handling -func flattenS3Actions(actions []*iot.Action) []interface{} { +func flattenS3Actions(actions []awstypes.Action) []interface{} { results := make([]interface{}, 0) for _, action := range actions { - if action == nil { - continue - } - if v := action.S3; v != nil { results = append(results, flattenS3Action(v)...) } @@ -3089,7 +3082,7 @@ func flattenS3Actions(actions []*iot.Action) []interface{} { return results } -func flattenS3Action(apiObject *iot.S3Action) []interface{} { +func flattenS3Action(apiObject *awstypes.S3Action) []interface{} { if apiObject == nil { return nil } @@ -3097,33 +3090,27 @@ func flattenS3Action(apiObject *iot.S3Action) []interface{} { tfMap := make(map[string]interface{}) if v := apiObject.BucketName; v != nil { - tfMap[names.AttrBucketName] = aws.StringValue(v) + tfMap[names.AttrBucketName] = aws.ToString(v) } - if v := apiObject.CannedAcl; v != nil { - tfMap["canned_acl"] = aws.StringValue(v) - } + tfMap["canned_acl"] = apiObject.CannedAcl if v := apiObject.Key; v != nil { - tfMap[names.AttrKey] = aws.StringValue(v) + tfMap[names.AttrKey] = aws.ToString(v) } if v := apiObject.RoleArn; v != nil { - tfMap[names.AttrRoleARN] = aws.StringValue(v) + tfMap[names.AttrRoleARN] = aws.ToString(v) } return []interface{}{tfMap} } // Legacy root attribute handling -func flattenSNSActions(actions []*iot.Action) []interface{} { +func flattenSNSActions(actions []awstypes.Action) []interface{} { results := make([]interface{}, 0) for _, action := range actions { - if action == nil { - continue - } - if v := action.Sns; v != nil { results = append(results, flattenSNSAction(v)...) } @@ -3132,37 +3119,31 @@ func flattenSNSActions(actions []*iot.Action) []interface{} { return results } -func flattenSNSAction(apiObject *iot.SnsAction) []interface{} { +func flattenSNSAction(apiObject *awstypes.SnsAction) []interface{} { if apiObject == nil { return nil } tfMap := make(map[string]interface{}) - if v := apiObject.MessageFormat; v != nil { - tfMap["message_format"] = aws.StringValue(v) - } + tfMap["message_format"] = apiObject.MessageFormat if v := apiObject.RoleArn; v != nil { - tfMap[names.AttrRoleARN] = aws.StringValue(v) + tfMap[names.AttrRoleARN] = aws.ToString(v) } if v := apiObject.TargetArn; v != nil { - tfMap[names.AttrTargetARN] = aws.StringValue(v) + tfMap[names.AttrTargetARN] = aws.ToString(v) } return []interface{}{tfMap} } // Legacy root attribute handling -func flattenSQSActions(actions []*iot.Action) []interface{} { +func flattenSQSActions(actions []awstypes.Action) []interface{} { results := make([]interface{}, 0) for _, action := range actions { - if action == nil { - continue - } - if v := action.Sqs; v != nil { results = append(results, flattenSQSAction(v)...) } @@ -3171,7 +3152,7 @@ func flattenSQSActions(actions []*iot.Action) []interface{} { return results } -func flattenSQSAction(apiObject *iot.SqsAction) []interface{} { +func flattenSQSAction(apiObject *awstypes.SqsAction) []interface{} { if apiObject == nil { return nil } @@ -3179,29 +3160,25 @@ func flattenSQSAction(apiObject *iot.SqsAction) []interface{} { tfMap := make(map[string]interface{}) if v := apiObject.QueueUrl; v != nil { - tfMap["queue_url"] = aws.StringValue(v) + tfMap["queue_url"] = aws.ToString(v) } if v := apiObject.RoleArn; v != nil { - tfMap[names.AttrRoleARN] = aws.StringValue(v) + tfMap[names.AttrRoleARN] = aws.ToString(v) } if v := apiObject.UseBase64; v != nil { - tfMap["use_base64"] = aws.BoolValue(v) + tfMap["use_base64"] = aws.ToBool(v) } return []interface{}{tfMap} } // Legacy root attribute handling -func flattenStepFunctionsActions(actions []*iot.Action) []interface{} { +func flattenStepFunctionsActions(actions []awstypes.Action) []interface{} { results := make([]interface{}, 0) for _, action := range actions { - if action == nil { - continue - } - if v := action.StepFunctions; v != nil { results = append(results, flattenStepFunctionsAction(v)...) } @@ -3210,7 +3187,7 @@ func flattenStepFunctionsActions(actions []*iot.Action) []interface{} { return results } -func flattenStepFunctionsAction(apiObject *iot.StepFunctionsAction) []interface{} { +func flattenStepFunctionsAction(apiObject *awstypes.StepFunctionsAction) []interface{} { if apiObject == nil { return nil } @@ -3218,29 +3195,25 @@ func flattenStepFunctionsAction(apiObject *iot.StepFunctionsAction) []interface{ tfMap := make(map[string]interface{}) if v := apiObject.ExecutionNamePrefix; v != nil { - tfMap["execution_name_prefix"] = aws.StringValue(v) + tfMap["execution_name_prefix"] = aws.ToString(v) } if v := apiObject.StateMachineName; v != nil { - tfMap["state_machine_name"] = aws.StringValue(v) + tfMap["state_machine_name"] = aws.ToString(v) } if v := apiObject.RoleArn; v != nil { - tfMap[names.AttrRoleARN] = aws.StringValue(v) + tfMap[names.AttrRoleARN] = aws.ToString(v) } return []interface{}{tfMap} } // Legacy root attribute handling -func flattenTimestreamActions(actions []*iot.Action) []interface{} { +func flattenTimestreamActions(actions []awstypes.Action) []interface{} { results := make([]interface{}, 0) for _, action := range actions { - if action == nil { - continue - } - if v := action.Timestream; v != nil { results = append(results, flattenTimestreamAction(v)...) } @@ -3249,7 +3222,7 @@ func flattenTimestreamActions(actions []*iot.Action) []interface{} { return results } -func flattenTimestreamAction(apiObject *iot.TimestreamAction) []interface{} { +func flattenTimestreamAction(apiObject *awstypes.TimestreamAction) []interface{} { if apiObject == nil { return nil } @@ -3257,7 +3230,7 @@ func flattenTimestreamAction(apiObject *iot.TimestreamAction) []interface{} { tfMap := make(map[string]interface{}) if v := apiObject.DatabaseName; v != nil { - tfMap[names.AttrDatabaseName] = aws.StringValue(v) + tfMap[names.AttrDatabaseName] = aws.ToString(v) } if v := apiObject.Dimensions; v != nil { @@ -3265,11 +3238,11 @@ func flattenTimestreamAction(apiObject *iot.TimestreamAction) []interface{} { } if v := apiObject.RoleArn; v != nil { - tfMap[names.AttrRoleARN] = aws.StringValue(v) + tfMap[names.AttrRoleARN] = aws.ToString(v) } if v := apiObject.TableName; v != nil { - tfMap[names.AttrTableName] = aws.StringValue(v) + tfMap[names.AttrTableName] = aws.ToString(v) } if v := apiObject.Timestamp; v != nil { @@ -3279,33 +3252,31 @@ func flattenTimestreamAction(apiObject *iot.TimestreamAction) []interface{} { return []interface{}{tfMap} } -func flattenTimestreamDimensions(apiObjects []*iot.TimestreamDimension) *schema.Set { +func flattenTimestreamDimensions(apiObjects []awstypes.TimestreamDimension) []interface{} { if apiObjects == nil { return nil } - tfSet := schema.NewSet(schema.HashResource(timestreamDimensionResource), []interface{}{}) + tfList := make([]interface{}, 0) for _, apiObject := range apiObjects { - if apiObject != nil { - tfMap := make(map[string]interface{}) + tfMap := make(map[string]interface{}) - if v := apiObject.Name; v != nil { - tfMap[names.AttrName] = aws.StringValue(v) - } - - if v := apiObject.Value; v != nil { - tfMap[names.AttrValue] = aws.StringValue(v) - } + if v := apiObject.Name; v != nil { + tfMap[names.AttrName] = aws.ToString(v) + } - tfSet.Add(tfMap) + if v := apiObject.Value; v != nil { + tfMap[names.AttrValue] = aws.ToString(v) } + + tfList = append(tfList, tfMap) } - return tfSet + return tfList } -func flattenTimestreamTimestamp(apiObject *iot.TimestreamTimestamp) []interface{} { +func flattenTimestreamTimestamp(apiObject *awstypes.TimestreamTimestamp) []interface{} { if apiObject == nil { return nil } @@ -3313,23 +3284,24 @@ func flattenTimestreamTimestamp(apiObject *iot.TimestreamTimestamp) []interface{ tfMap := make(map[string]interface{}) if v := apiObject.Unit; v != nil { - tfMap[names.AttrUnit] = aws.StringValue(v) + tfMap[names.AttrUnit] = aws.ToString(v) } if v := apiObject.Value; v != nil { - tfMap[names.AttrValue] = aws.StringValue(v) + tfMap[names.AttrValue] = aws.ToString(v) } return []interface{}{tfMap} } -func flattenErrorAction(errorAction *iot.Action) []map[string]interface{} { +func flattenErrorAction(errorAction *awstypes.Action) []map[string]interface{} { results := make([]map[string]interface{}, 0) if errorAction == nil { - return results + return nil } - input := []*iot.Action{errorAction} + + input := []awstypes.Action{*errorAction} if errorAction.CloudwatchAlarm != nil { results = append(results, map[string]interface{}{"cloudwatch_alarm": flattenCloudWatchAlarmActions(input)}) return results diff --git a/internal/service/iot/topic_rule_destination.go b/internal/service/iot/topic_rule_destination.go index f16ff561587..d6fb79585f4 100644 --- a/internal/service/iot/topic_rule_destination.go +++ b/internal/service/iot/topic_rule_destination.go @@ -9,13 +9,15 @@ import ( "log" "time" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/service/iot" - "github.com/hashicorp/aws-sdk-go-base/v2/awsv1shim/v2/tfawserr" + "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/service/iot" + awstypes "github.com/aws/aws-sdk-go-v2/service/iot/types" "github.com/hashicorp/terraform-plugin-sdk/v2/diag" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/retry" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" "github.com/hashicorp/terraform-provider-aws/internal/conns" + "github.com/hashicorp/terraform-provider-aws/internal/enum" + "github.com/hashicorp/terraform-provider-aws/internal/errs" "github.com/hashicorp/terraform-provider-aws/internal/errs/sdkdiag" "github.com/hashicorp/terraform-provider-aws/internal/flex" "github.com/hashicorp/terraform-provider-aws/internal/tfresource" @@ -23,8 +25,8 @@ import ( "github.com/hashicorp/terraform-provider-aws/names" ) -// @SDKResource("aws_iot_topic_rule_destination") -func ResourceTopicRuleDestination() *schema.Resource { +// @SDKResource("aws_iot_topic_rule_destination", name="Topic Rule Destination") +func resourceTopicRuleDestination() *schema.Resource { return &schema.Resource{ CreateWithoutTimeout: resourceTopicRuleDestinationCreate, ReadWithoutTimeout: resourceTopicRuleDestinationRead, @@ -90,47 +92,38 @@ func ResourceTopicRuleDestination() *schema.Resource { func resourceTopicRuleDestinationCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { var diags diag.Diagnostics - - conn := meta.(*conns.AWSClient).IoTConn(ctx) + conn := meta.(*conns.AWSClient).IoTClient(ctx) input := &iot.CreateTopicRuleDestinationInput{ - DestinationConfiguration: &iot.TopicRuleDestinationConfiguration{}, + DestinationConfiguration: &awstypes.TopicRuleDestinationConfiguration{}, } if v, ok := d.GetOk(names.AttrVPCConfiguration); ok && len(v.([]interface{})) > 0 && v.([]interface{})[0] != nil { input.DestinationConfiguration.VpcConfiguration = expandVPCDestinationConfiguration(v.([]interface{})[0].(map[string]interface{})) } - log.Printf("[INFO] Creating IoT Topic Rule Destination: %s", input) - outputRaw, err := tfresource.RetryWhen(ctx, propagationTimeout, + outputRaw, err := tfresource.RetryWhenIsA[*awstypes.InvalidRequestException](ctx, propagationTimeout, func() (interface{}, error) { - return conn.CreateTopicRuleDestinationWithContext(ctx, input) - }, - func(err error) (bool, error) { - if tfawserr.ErrMessageContains(err, iot.ErrCodeInvalidRequestException, "sts:AssumeRole") || - tfawserr.ErrMessageContains(err, iot.ErrCodeInvalidRequestException, "Missing permission") { - return true, err - } - - return false, err - }, - ) + return conn.CreateTopicRuleDestination(ctx, input) + }) if err != nil { return sdkdiag.AppendErrorf(diags, "creating IoT Topic Rule Destination: %s", err) } - d.SetId(aws.StringValue(outputRaw.(*iot.CreateTopicRuleDestinationOutput).TopicRuleDestination.Arn)) + d.SetId(aws.ToString(outputRaw.(*iot.CreateTopicRuleDestinationOutput).TopicRuleDestination.Arn)) if _, err := waitTopicRuleDestinationCreated(ctx, conn, d.Id(), d.Timeout(schema.TimeoutCreate)); err != nil { return sdkdiag.AppendErrorf(diags, "waiting for IoT Topic Rule Destination (%s) create: %s", d.Id(), err) } if _, ok := d.GetOk(names.AttrEnabled); !ok { - _, err := conn.UpdateTopicRuleDestinationWithContext(ctx, &iot.UpdateTopicRuleDestinationInput{ + input := &iot.UpdateTopicRuleDestinationInput{ Arn: aws.String(d.Id()), - Status: aws.String(iot.TopicRuleDestinationStatusDisabled), - }) + Status: awstypes.TopicRuleDestinationStatusDisabled, + } + + _, err := conn.UpdateTopicRuleDestination(ctx, input) if err != nil { return sdkdiag.AppendErrorf(diags, "disabling IoT Topic Rule Destination (%s): %s", d.Id(), err) @@ -146,10 +139,9 @@ func resourceTopicRuleDestinationCreate(ctx context.Context, d *schema.ResourceD func resourceTopicRuleDestinationRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { var diags diag.Diagnostics + conn := meta.(*conns.AWSClient).IoTClient(ctx) - conn := meta.(*conns.AWSClient).IoTConn(ctx) - - output, err := FindTopicRuleDestinationByARN(ctx, conn, d.Id()) + output, err := findTopicRuleDestinationByARN(ctx, conn, d.Id()) if !d.IsNewResource() && tfresource.NotFound(err) { log.Printf("[WARN] IoT Topic Rule Destination %s not found, removing from state", d.Id()) @@ -162,7 +154,7 @@ func resourceTopicRuleDestinationRead(ctx context.Context, d *schema.ResourceDat } d.Set(names.AttrARN, output.Arn) - d.Set(names.AttrEnabled, aws.StringValue(output.Status) == iot.TopicRuleDestinationStatusEnabled) + d.Set(names.AttrEnabled, (output.Status == awstypes.TopicRuleDestinationStatusEnabled)) if output.VpcProperties != nil { if err := d.Set(names.AttrVPCConfiguration, []interface{}{flattenVPCDestinationProperties(output.VpcProperties)}); err != nil { return sdkdiag.AppendErrorf(diags, "setting vpc_configuration: %s", err) @@ -176,22 +168,21 @@ func resourceTopicRuleDestinationRead(ctx context.Context, d *schema.ResourceDat func resourceTopicRuleDestinationUpdate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { var diags diag.Diagnostics - - conn := meta.(*conns.AWSClient).IoTConn(ctx) + conn := meta.(*conns.AWSClient).IoTClient(ctx) if d.HasChange(names.AttrEnabled) { input := &iot.UpdateTopicRuleDestinationInput{ Arn: aws.String(d.Id()), - Status: aws.String(iot.TopicRuleDestinationStatusEnabled), + Status: awstypes.TopicRuleDestinationStatusEnabled, } waiter := waitTopicRuleDestinationEnabled if _, ok := d.GetOk(names.AttrEnabled); !ok { - input.Status = aws.String(iot.TopicRuleDestinationStatusDisabled) + input.Status = awstypes.TopicRuleDestinationStatusDisabled waiter = waitTopicRuleDestinationDisabled } - _, err := conn.UpdateTopicRuleDestinationWithContext(ctx, input) + _, err := conn.UpdateTopicRuleDestination(ctx, input) if err != nil { return sdkdiag.AppendErrorf(diags, "updating IoT Topic Rule Destination (%s): %s", d.Id(), err) @@ -207,14 +198,20 @@ func resourceTopicRuleDestinationUpdate(ctx context.Context, d *schema.ResourceD func resourceTopicRuleDestinationDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { var diags diag.Diagnostics - - conn := meta.(*conns.AWSClient).IoTConn(ctx) + conn := meta.(*conns.AWSClient).IoTClient(ctx) log.Printf("[INFO] Deleting IoT Topic Rule Destination: %s", d.Id()) - _, err := conn.DeleteTopicRuleDestinationWithContext(ctx, &iot.DeleteTopicRuleDestinationInput{ + + // DeleteTopicRuleDestination returns unhelpful errors such as + // "UnauthorizedException: Access to TopicRuleDestination 'xxx' was denied" when querying for a rule destination that doesn't exist. + _, err := conn.DeleteTopicRuleDestination(ctx, &iot.DeleteTopicRuleDestinationInput{ Arn: aws.String(d.Id()), }) + if errs.IsA[*awstypes.UnauthorizedException](err) { + return diags + } + if err != nil { return sdkdiag.AppendErrorf(diags, "deleting IoT Topic Rule Destination: %s", err) } @@ -226,61 +223,62 @@ func resourceTopicRuleDestinationDelete(ctx context.Context, d *schema.ResourceD return diags } -func expandVPCDestinationConfiguration(tfMap map[string]interface{}) *iot.VpcDestinationConfiguration { - if tfMap == nil { - return nil - } - - apiObject := &iot.VpcDestinationConfiguration{} +func findTopicRuleDestinationByARN(ctx context.Context, conn *iot.Client, arn string) (*awstypes.TopicRuleDestination, error) { + // GetTopicRuleDestination returns unhelpful errors such as + // "UnauthorizedException: Access to TopicRuleDestination 'arn:aws:iot:us-west-2:123456789012:ruledestination/vpc/f267138a-7383-4670-9e44-a7fe2f48af5e' was denied" + // when querying for a rule destination that doesn't exist. + inputL := &iot.ListTopicRuleDestinationsInput{} + var destination *awstypes.TopicRuleDestinationSummary - if v, ok := tfMap[names.AttrRoleARN].(string); ok && v != "" { - apiObject.RoleArn = aws.String(v) - } + pages := iot.NewListTopicRuleDestinationsPaginator(conn, inputL) +pageLoop: + for pages.HasMorePages() { + page, err := pages.NextPage(ctx) - if v, ok := tfMap[names.AttrSecurityGroups].(*schema.Set); ok && v.Len() > 0 { - apiObject.SecurityGroups = flex.ExpandStringSet(v) - } + if err != nil { + return nil, err + } - if v, ok := tfMap[names.AttrSubnetIDs].(*schema.Set); ok && v.Len() > 0 { - apiObject.SubnetIds = flex.ExpandStringSet(v) + for _, v := range page.DestinationSummaries { + v := v + if aws.ToString(v.Arn) == arn { + destination = &v + break pageLoop + } + } } - if v, ok := tfMap[names.AttrVPCID].(string); ok && v != "" { - apiObject.VpcId = aws.String(v) + if destination == nil { + return nil, tfresource.NewEmptyResultError(nil) } - return apiObject -} - -func flattenVPCDestinationProperties(apiObject *iot.VpcDestinationProperties) map[string]interface{} { - if apiObject == nil { - return nil + inputG := &iot.GetTopicRuleDestinationInput{ + Arn: aws.String(arn), } - tfMap := map[string]interface{}{} + output, err := conn.GetTopicRuleDestination(ctx, inputG) - if v := apiObject.RoleArn; v != nil { - tfMap[names.AttrRoleARN] = aws.StringValue(v) + if errs.IsA[*awstypes.ResourceNotFoundException](err) { + return nil, &retry.NotFoundError{ + LastError: err, + LastRequest: inputG, + } } - if v := apiObject.SecurityGroups; v != nil { - tfMap[names.AttrSecurityGroups] = aws.StringValueSlice(v) + if err != nil { + return nil, err } - if v := apiObject.SubnetIds; v != nil { - tfMap[names.AttrSubnetIDs] = aws.StringValueSlice(v) + if output == nil || output.TopicRuleDestination == nil { + return nil, tfresource.NewEmptyResultError(inputG) } - if v := apiObject.VpcId; v != nil { - tfMap[names.AttrVPCID] = aws.StringValue(v) - } - - return tfMap + return output.TopicRuleDestination, nil } -func statusTopicRuleDestination(ctx context.Context, conn *iot.IoT, arn string) retry.StateRefreshFunc { +func statusTopicRuleDestination(ctx context.Context, conn *iot.Client, arn string) retry.StateRefreshFunc { return func() (interface{}, string, error) { - output, err := FindTopicRuleDestinationByARN(ctx, conn, arn) + output, err := findTopicRuleDestinationByARN(ctx, conn, arn) if tfresource.NotFound(err) { return nil, "", nil @@ -290,22 +288,22 @@ func statusTopicRuleDestination(ctx context.Context, conn *iot.IoT, arn string) return nil, "", err } - return output, aws.StringValue(output.Status), nil + return output, string(output.Status), nil } } -func waitTopicRuleDestinationCreated(ctx context.Context, conn *iot.IoT, arn string, timeout time.Duration) (*iot.TopicRuleDestination, error) { +func waitTopicRuleDestinationCreated(ctx context.Context, conn *iot.Client, arn string, timeout time.Duration) (*awstypes.TopicRuleDestination, error) { stateConf := &retry.StateChangeConf{ - Pending: []string{iot.TopicRuleDestinationStatusInProgress}, - Target: []string{iot.TopicRuleDestinationStatusEnabled}, + Pending: enum.Slice(string(awstypes.TopicRuleDestinationStatusInProgress)), + Target: enum.Slice(string(awstypes.TopicRuleDestinationStatusEnabled)), Refresh: statusTopicRuleDestination(ctx, conn, arn), Timeout: timeout, } outputRaw, err := stateConf.WaitForStateContext(ctx) - if output, ok := outputRaw.(*iot.TopicRuleDestination); ok { - tfresource.SetLastError(err, errors.New(aws.StringValue(output.StatusReason))) + if output, ok := outputRaw.(*awstypes.TopicRuleDestination); ok { + tfresource.SetLastError(err, errors.New(aws.ToString(output.StatusReason))) return output, err } @@ -313,9 +311,9 @@ func waitTopicRuleDestinationCreated(ctx context.Context, conn *iot.IoT, arn str return nil, err } -func waitTopicRuleDestinationDeleted(ctx context.Context, conn *iot.IoT, arn string, timeout time.Duration) (*iot.TopicRuleDestination, error) { +func waitTopicRuleDestinationDeleted(ctx context.Context, conn *iot.Client, arn string, timeout time.Duration) (*awstypes.TopicRuleDestination, error) { stateConf := &retry.StateChangeConf{ - Pending: []string{iot.TopicRuleDestinationStatusDeleting}, + Pending: enum.Slice(string(awstypes.TopicRuleDestinationStatusDeleting)), Target: []string{}, Refresh: statusTopicRuleDestination(ctx, conn, arn), Timeout: timeout, @@ -323,8 +321,8 @@ func waitTopicRuleDestinationDeleted(ctx context.Context, conn *iot.IoT, arn str outputRaw, err := stateConf.WaitForStateContext(ctx) - if output, ok := outputRaw.(*iot.TopicRuleDestination); ok { - tfresource.SetLastError(err, errors.New(aws.StringValue(output.StatusReason))) + if output, ok := outputRaw.(*awstypes.TopicRuleDestination); ok { + tfresource.SetLastError(err, errors.New(aws.ToString(output.StatusReason))) return output, err } @@ -332,18 +330,18 @@ func waitTopicRuleDestinationDeleted(ctx context.Context, conn *iot.IoT, arn str return nil, err } -func waitTopicRuleDestinationDisabled(ctx context.Context, conn *iot.IoT, arn string, timeout time.Duration) (*iot.TopicRuleDestination, error) { +func waitTopicRuleDestinationDisabled(ctx context.Context, conn *iot.Client, arn string, timeout time.Duration) (*awstypes.TopicRuleDestination, error) { stateConf := &retry.StateChangeConf{ - Pending: []string{iot.TopicRuleDestinationStatusInProgress}, - Target: []string{iot.TopicRuleDestinationStatusDisabled}, + Pending: enum.Slice(string(awstypes.TopicRuleDestinationStatusInProgress)), + Target: enum.Slice(string(awstypes.TopicRuleDestinationStatusDisabled)), Refresh: statusTopicRuleDestination(ctx, conn, arn), Timeout: timeout, } outputRaw, err := stateConf.WaitForStateContext(ctx) - if output, ok := outputRaw.(*iot.TopicRuleDestination); ok { - tfresource.SetLastError(err, errors.New(aws.StringValue(output.StatusReason))) + if output, ok := outputRaw.(*awstypes.TopicRuleDestination); ok { + tfresource.SetLastError(err, errors.New(aws.ToString(output.StatusReason))) return output, err } @@ -351,21 +349,73 @@ func waitTopicRuleDestinationDisabled(ctx context.Context, conn *iot.IoT, arn st return nil, err } -func waitTopicRuleDestinationEnabled(ctx context.Context, conn *iot.IoT, arn string, timeout time.Duration) (*iot.TopicRuleDestination, error) { +func waitTopicRuleDestinationEnabled(ctx context.Context, conn *iot.Client, arn string, timeout time.Duration) (*awstypes.TopicRuleDestination, error) { stateConf := &retry.StateChangeConf{ - Pending: []string{iot.TopicRuleDestinationStatusInProgress}, - Target: []string{iot.TopicRuleDestinationStatusEnabled}, + Pending: enum.Slice(string(awstypes.TopicRuleDestinationStatusInProgress)), + Target: enum.Slice(string(awstypes.TopicRuleDestinationStatusEnabled)), Refresh: statusTopicRuleDestination(ctx, conn, arn), Timeout: timeout, } outputRaw, err := stateConf.WaitForStateContext(ctx) - if output, ok := outputRaw.(*iot.TopicRuleDestination); ok { - tfresource.SetLastError(err, errors.New(aws.StringValue(output.StatusReason))) + if output, ok := outputRaw.(*awstypes.TopicRuleDestination); ok { + tfresource.SetLastError(err, errors.New(aws.ToString(output.StatusReason))) return output, err } return nil, err } + +func expandVPCDestinationConfiguration(tfMap map[string]interface{}) *awstypes.VpcDestinationConfiguration { + if tfMap == nil { + return nil + } + + apiObject := &awstypes.VpcDestinationConfiguration{} + + if v, ok := tfMap[names.AttrRoleARN].(string); ok && v != "" { + apiObject.RoleArn = aws.String(v) + } + + if v, ok := tfMap[names.AttrSecurityGroups].(*schema.Set); ok && v.Len() > 0 { + apiObject.SecurityGroups = flex.ExpandStringValueSet(v) + } + + if v, ok := tfMap[names.AttrSubnetIDs].(*schema.Set); ok && v.Len() > 0 { + apiObject.SubnetIds = flex.ExpandStringValueSet(v) + } + + if v, ok := tfMap[names.AttrVPCID].(string); ok && v != "" { + apiObject.VpcId = aws.String(v) + } + + return apiObject +} + +func flattenVPCDestinationProperties(apiObject *awstypes.VpcDestinationProperties) map[string]interface{} { + if apiObject == nil { + return nil + } + + tfMap := map[string]interface{}{} + + if v := apiObject.RoleArn; v != nil { + tfMap[names.AttrRoleARN] = aws.ToString(v) + } + + if v := apiObject.SecurityGroups; v != nil { + tfMap[names.AttrSecurityGroups] = aws.StringSlice(v) + } + + if v := apiObject.SubnetIds; v != nil { + tfMap[names.AttrSubnetIDs] = aws.StringSlice(v) + } + + if v := apiObject.VpcId; v != nil { + tfMap[names.AttrVPCID] = aws.ToString(v) + } + + return tfMap +} diff --git a/internal/service/iot/topic_rule_destination_test.go b/internal/service/iot/topic_rule_destination_test.go index 58132cf0d17..1bbef98699c 100644 --- a/internal/service/iot/topic_rule_destination_test.go +++ b/internal/service/iot/topic_rule_destination_test.go @@ -126,7 +126,7 @@ func TestAccIoTTopicRuleDestination_enabled(t *testing.T) { func testAccCheckTopicRuleDestinationDestroy(ctx context.Context) resource.TestCheckFunc { return func(s *terraform.State) error { - conn := acctest.Provider.Meta().(*conns.AWSClient).IoTConn(ctx) + conn := acctest.Provider.Meta().(*conns.AWSClient).IoTClient(ctx) for _, rs := range s.RootModule().Resources { if rs.Type != "aws_iot_topic_rule_destination" { @@ -161,7 +161,7 @@ func testAccCheckTopicRuleDestinationExists(ctx context.Context, n string) resou return fmt.Errorf("No IoT Topic Rule Destination ID is set") } - conn := acctest.Provider.Meta().(*conns.AWSClient).IoTConn(ctx) + conn := acctest.Provider.Meta().(*conns.AWSClient).IoTClient(ctx) _, err := tfiot.FindTopicRuleDestinationByARN(ctx, conn, rs.Primary.ID) diff --git a/internal/service/iot/topic_rule_test.go b/internal/service/iot/topic_rule_test.go index 67966585d6e..cfc590b1c6a 100644 --- a/internal/service/iot/topic_rule_test.go +++ b/internal/service/iot/topic_rule_test.go @@ -2338,7 +2338,7 @@ func TestAccIoTTopicRule_updateKinesisErrorAction(t *testing.T) { func testAccCheckTopicRuleDestroy(ctx context.Context) resource.TestCheckFunc { return func(s *terraform.State) error { - conn := acctest.Provider.Meta().(*conns.AWSClient).IoTConn(ctx) + conn := acctest.Provider.Meta().(*conns.AWSClient).IoTClient(ctx) for _, rs := range s.RootModule().Resources { if rs.Type != "aws_iot_topic_rule" { @@ -2373,7 +2373,7 @@ func testAccCheckTopicRuleExists(ctx context.Context, n string) resource.TestChe return fmt.Errorf("No IoT Topic Rule ID is set") } - conn := acctest.Provider.Meta().(*conns.AWSClient).IoTConn(ctx) + conn := acctest.Provider.Meta().(*conns.AWSClient).IoTClient(ctx) _, err := tfiot.FindTopicRuleByName(ctx, conn, rs.Primary.ID) diff --git a/internal/service/iotanalytics/generate.go b/internal/service/iotanalytics/generate.go index 00e14896279..39475063214 100644 --- a/internal/service/iotanalytics/generate.go +++ b/internal/service/iotanalytics/generate.go @@ -1,7 +1,7 @@ // Copyright (c) HashiCorp, Inc. // SPDX-License-Identifier: MPL-2.0 -//go:generate go run ../../generate/tags/main.go -ListTags -ServiceTagsSlice -UpdateTags +//go:generate go run ../../generate/tags/main.go -ListTags -ServiceTagsSlice -UpdateTags -AWSSDKVersion=2 //go:generate go run ../../generate/servicepackage/main.go // ONLY generate directives and package declaration! Do not add anything else to this file. diff --git a/internal/service/iotanalytics/service_endpoint_resolver_gen.go b/internal/service/iotanalytics/service_endpoint_resolver_gen.go index feff5a3440d..eba81098a25 100644 --- a/internal/service/iotanalytics/service_endpoint_resolver_gen.go +++ b/internal/service/iotanalytics/service_endpoint_resolver_gen.go @@ -6,65 +6,63 @@ import ( "context" "fmt" "net" - "net/url" - endpoints_sdkv1 "github.com/aws/aws-sdk-go/aws/endpoints" + aws_sdkv2 "github.com/aws/aws-sdk-go-v2/aws" + iotanalytics_sdkv2 "github.com/aws/aws-sdk-go-v2/service/iotanalytics" + smithyendpoints "github.com/aws/smithy-go/endpoints" "github.com/hashicorp/terraform-plugin-log/tflog" "github.com/hashicorp/terraform-provider-aws/internal/errs" ) -var _ endpoints_sdkv1.Resolver = resolverSDKv1{} +var _ iotanalytics_sdkv2.EndpointResolverV2 = resolverSDKv2{} -type resolverSDKv1 struct { - ctx context.Context +type resolverSDKv2 struct { + defaultResolver iotanalytics_sdkv2.EndpointResolverV2 } -func newEndpointResolverSDKv1(ctx context.Context) resolverSDKv1 { - return resolverSDKv1{ - ctx: ctx, +func newEndpointResolverSDKv2() resolverSDKv2 { + return resolverSDKv2{ + defaultResolver: iotanalytics_sdkv2.NewDefaultEndpointResolverV2(), } } -func (r resolverSDKv1) EndpointFor(service, region string, opts ...func(*endpoints_sdkv1.Options)) (endpoint endpoints_sdkv1.ResolvedEndpoint, err error) { - ctx := r.ctx +func (r resolverSDKv2) ResolveEndpoint(ctx context.Context, params iotanalytics_sdkv2.EndpointParameters) (endpoint smithyendpoints.Endpoint, err error) { + params = params.WithDefaults() + useFIPS := aws_sdkv2.ToBool(params.UseFIPS) - var opt endpoints_sdkv1.Options - opt.Set(opts...) - - useFIPS := opt.UseFIPSEndpoint == endpoints_sdkv1.FIPSEndpointStateEnabled + if eps := params.Endpoint; aws_sdkv2.ToString(eps) != "" { + tflog.Debug(ctx, "setting endpoint", map[string]any{ + "tf_aws.endpoint": endpoint, + }) - defaultResolver := endpoints_sdkv1.DefaultResolver() + if useFIPS { + tflog.Debug(ctx, "endpoint set, ignoring UseFIPSEndpoint setting") + params.UseFIPS = aws_sdkv2.Bool(false) + } - if useFIPS { + return r.defaultResolver.ResolveEndpoint(ctx, params) + } else if useFIPS { ctx = tflog.SetField(ctx, "tf_aws.use_fips", useFIPS) - endpoint, err = defaultResolver.EndpointFor(service, region, opts...) + endpoint, err = r.defaultResolver.ResolveEndpoint(ctx, params) if err != nil { return endpoint, err } tflog.Debug(ctx, "endpoint resolved", map[string]any{ - "tf_aws.endpoint": endpoint.URL, + "tf_aws.endpoint": endpoint.URI.String(), }) - var endpointURL *url.URL - endpointURL, err = url.Parse(endpoint.URL) - if err != nil { - return endpoint, err - } - - hostname := endpointURL.Hostname() + hostname := endpoint.URI.Hostname() _, err = net.LookupHost(hostname) if err != nil { if dnsErr, ok := errs.As[*net.DNSError](err); ok && dnsErr.IsNotFound { tflog.Debug(ctx, "default endpoint host not found, disabling FIPS", map[string]any{ "tf_aws.hostname": hostname, }) - opts = append(opts, func(o *endpoints_sdkv1.Options) { - o.UseFIPSEndpoint = endpoints_sdkv1.FIPSEndpointStateDisabled - }) + params.UseFIPS = aws_sdkv2.Bool(false) } else { - err = fmt.Errorf("looking up accessanalyzer endpoint %q: %s", hostname, err) + err = fmt.Errorf("looking up iotanalytics endpoint %q: %s", hostname, err) return } } else { @@ -72,5 +70,13 @@ func (r resolverSDKv1) EndpointFor(service, region string, opts ...func(*endpoin } } - return defaultResolver.EndpointFor(service, region, opts...) + return r.defaultResolver.ResolveEndpoint(ctx, params) +} + +func withBaseEndpoint(endpoint string) func(*iotanalytics_sdkv2.Options) { + return func(o *iotanalytics_sdkv2.Options) { + if endpoint != "" { + o.BaseEndpoint = aws_sdkv2.String(endpoint) + } + } } diff --git a/internal/service/iotanalytics/service_endpoints_gen_test.go b/internal/service/iotanalytics/service_endpoints_gen_test.go index 43266b58965..61915471201 100644 --- a/internal/service/iotanalytics/service_endpoints_gen_test.go +++ b/internal/service/iotanalytics/service_endpoints_gen_test.go @@ -4,18 +4,22 @@ package iotanalytics_test import ( "context" + "errors" "fmt" "maps" "net" "net/url" "os" "path/filepath" + "reflect" "strings" "testing" - aws_sdkv1 "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/endpoints" - iotanalytics_sdkv1 "github.com/aws/aws-sdk-go/service/iotanalytics" + aws_sdkv2 "github.com/aws/aws-sdk-go-v2/aws" + awsmiddleware "github.com/aws/aws-sdk-go-v2/aws/middleware" + iotanalytics_sdkv2 "github.com/aws/aws-sdk-go-v2/service/iotanalytics" + "github.com/aws/smithy-go/middleware" + smithyhttp "github.com/aws/smithy-go/transport/http" "github.com/google/go-cmp/cmp" "github.com/hashicorp/aws-sdk-go-base/v2/servicemocks" "github.com/hashicorp/terraform-plugin-sdk/v2/diag" @@ -240,54 +244,63 @@ func TestEndpointConfiguration(t *testing.T) { //nolint:paralleltest // uses t.S } func defaultEndpoint(region string) (url.URL, error) { - r := endpoints.DefaultResolver() + r := iotanalytics_sdkv2.NewDefaultEndpointResolverV2() - ep, err := r.EndpointFor(iotanalytics_sdkv1.EndpointsID, region) + ep, err := r.ResolveEndpoint(context.Background(), iotanalytics_sdkv2.EndpointParameters{ + Region: aws_sdkv2.String(region), + }) if err != nil { return url.URL{}, err } - url, _ := url.Parse(ep.URL) - - if url.Path == "" { - url.Path = "/" + if ep.URI.Path == "" { + ep.URI.Path = "/" } - return *url, nil + return ep.URI, nil } func defaultFIPSEndpoint(region string) (url.URL, error) { - r := endpoints.DefaultResolver() + r := iotanalytics_sdkv2.NewDefaultEndpointResolverV2() - ep, err := r.EndpointFor(iotanalytics_sdkv1.EndpointsID, region, func(opt *endpoints.Options) { - opt.UseFIPSEndpoint = endpoints.FIPSEndpointStateEnabled + ep, err := r.ResolveEndpoint(context.Background(), iotanalytics_sdkv2.EndpointParameters{ + Region: aws_sdkv2.String(region), + UseFIPS: aws_sdkv2.Bool(true), }) if err != nil { return url.URL{}, err } - url, _ := url.Parse(ep.URL) - - if url.Path == "" { - url.Path = "/" + if ep.URI.Path == "" { + ep.URI.Path = "/" } - return *url, nil + return ep.URI, nil } func callService(ctx context.Context, t *testing.T, meta *conns.AWSClient) apiCallParams { t.Helper() - client := meta.IoTAnalyticsConn(ctx) + client := meta.IoTAnalyticsClient(ctx) - req, _ := client.ListChannelsRequest(&iotanalytics_sdkv1.ListChannelsInput{}) + var result apiCallParams - req.HTTPRequest.URL.Path = "/" - - return apiCallParams{ - endpoint: req.HTTPRequest.URL.String(), - region: aws_sdkv1.StringValue(client.Config.Region), + _, err := client.ListChannels(ctx, &iotanalytics_sdkv2.ListChannelsInput{}, + func(opts *iotanalytics_sdkv2.Options) { + opts.APIOptions = append(opts.APIOptions, + addRetrieveEndpointURLMiddleware(t, &result.endpoint), + addRetrieveRegionMiddleware(&result.region), + addCancelRequestMiddleware(), + ) + }, + ) + if err == nil { + t.Fatal("Expected an error, got none") + } else if !errors.Is(err, errCancelOperation) { + t.Fatalf("Unexpected error: %s", err) } + + return result } func withNoConfig(_ *caseSetup) { @@ -466,6 +479,89 @@ func testEndpointCase(t *testing.T, region string, testcase endpointTestCase, ca } } +func addRetrieveEndpointURLMiddleware(t *testing.T, endpoint *string) func(*middleware.Stack) error { + return func(stack *middleware.Stack) error { + return stack.Finalize.Add( + retrieveEndpointURLMiddleware(t, endpoint), + middleware.After, + ) + } +} + +func retrieveEndpointURLMiddleware(t *testing.T, endpoint *string) middleware.FinalizeMiddleware { + return middleware.FinalizeMiddlewareFunc( + "Test: Retrieve Endpoint", + func(ctx context.Context, in middleware.FinalizeInput, next middleware.FinalizeHandler) (middleware.FinalizeOutput, middleware.Metadata, error) { + t.Helper() + + request, ok := in.Request.(*smithyhttp.Request) + if !ok { + t.Fatalf("Expected *github.com/aws/smithy-go/transport/http.Request, got %s", fullTypeName(in.Request)) + } + + url := request.URL + url.RawQuery = "" + url.Path = "/" + + *endpoint = url.String() + + return next.HandleFinalize(ctx, in) + }) +} + +func addRetrieveRegionMiddleware(region *string) func(*middleware.Stack) error { + return func(stack *middleware.Stack) error { + return stack.Serialize.Add( + retrieveRegionMiddleware(region), + middleware.After, + ) + } +} + +func retrieveRegionMiddleware(region *string) middleware.SerializeMiddleware { + return middleware.SerializeMiddlewareFunc( + "Test: Retrieve Region", + func(ctx context.Context, in middleware.SerializeInput, next middleware.SerializeHandler) (middleware.SerializeOutput, middleware.Metadata, error) { + *region = awsmiddleware.GetRegion(ctx) + + return next.HandleSerialize(ctx, in) + }, + ) +} + +var errCancelOperation = fmt.Errorf("Test: Canceling request") + +func addCancelRequestMiddleware() func(*middleware.Stack) error { + return func(stack *middleware.Stack) error { + return stack.Finalize.Add( + cancelRequestMiddleware(), + middleware.After, + ) + } +} + +// cancelRequestMiddleware creates a Smithy middleware that intercepts the request before sending and cancels it +func cancelRequestMiddleware() middleware.FinalizeMiddleware { + return middleware.FinalizeMiddlewareFunc( + "Test: Cancel Requests", + func(_ context.Context, in middleware.FinalizeInput, next middleware.FinalizeHandler) (middleware.FinalizeOutput, middleware.Metadata, error) { + return middleware.FinalizeOutput{}, middleware.Metadata{}, errCancelOperation + }) +} + +func fullTypeName(i interface{}) string { + return fullValueTypeName(reflect.ValueOf(i)) +} + +func fullValueTypeName(v reflect.Value) string { + if v.Kind() == reflect.Ptr { + return "*" + fullValueTypeName(reflect.Indirect(v)) + } + + requestType := v.Type() + return fmt.Sprintf("%s.%s", requestType.PkgPath(), requestType.Name()) +} + func generateSharedConfigFile(config configFile) string { var buf strings.Builder diff --git a/internal/service/iotanalytics/service_package_gen.go b/internal/service/iotanalytics/service_package_gen.go index 0bf9e8a5e0f..32fcb9814eb 100644 --- a/internal/service/iotanalytics/service_package_gen.go +++ b/internal/service/iotanalytics/service_package_gen.go @@ -5,10 +5,8 @@ package iotanalytics import ( "context" - aws_sdkv1 "github.com/aws/aws-sdk-go/aws" - session_sdkv1 "github.com/aws/aws-sdk-go/aws/session" - iotanalytics_sdkv1 "github.com/aws/aws-sdk-go/service/iotanalytics" - "github.com/hashicorp/terraform-plugin-log/tflog" + aws_sdkv2 "github.com/aws/aws-sdk-go-v2/aws" + iotanalytics_sdkv2 "github.com/aws/aws-sdk-go-v2/service/iotanalytics" "github.com/hashicorp/terraform-provider-aws/internal/conns" "github.com/hashicorp/terraform-provider-aws/internal/types" "github.com/hashicorp/terraform-provider-aws/names" @@ -36,22 +34,14 @@ func (p *servicePackage) ServicePackageName() string { return names.IoTAnalytics } -// NewConn returns a new AWS SDK for Go v1 client for this service package's AWS API. -func (p *servicePackage) NewConn(ctx context.Context, config map[string]any) (*iotanalytics_sdkv1.IoTAnalytics, error) { - sess := config[names.AttrSession].(*session_sdkv1.Session) +// NewClient returns a new AWS SDK for Go v2 client for this service package's AWS API. +func (p *servicePackage) NewClient(ctx context.Context, config map[string]any) (*iotanalytics_sdkv2.Client, error) { + cfg := *(config["aws_sdkv2_config"].(*aws_sdkv2.Config)) - cfg := aws_sdkv1.Config{} - - if endpoint := config[names.AttrEndpoint].(string); endpoint != "" { - tflog.Debug(ctx, "setting endpoint", map[string]any{ - "tf_aws.endpoint": endpoint, - }) - cfg.Endpoint = aws_sdkv1.String(endpoint) - } else { - cfg.EndpointResolver = newEndpointResolverSDKv1(ctx) - } - - return iotanalytics_sdkv1.New(sess.Copy(&cfg)), nil + return iotanalytics_sdkv2.NewFromConfig(cfg, + iotanalytics_sdkv2.WithEndpointResolverV2(newEndpointResolverSDKv2()), + withBaseEndpoint(config[names.AttrEndpoint].(string)), + ), nil } func ServicePackage(ctx context.Context) conns.ServicePackage { diff --git a/internal/service/iotanalytics/tags_gen.go b/internal/service/iotanalytics/tags_gen.go index c4803733f28..46b768a0fea 100644 --- a/internal/service/iotanalytics/tags_gen.go +++ b/internal/service/iotanalytics/tags_gen.go @@ -5,9 +5,9 @@ import ( "context" "fmt" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/service/iotanalytics" - "github.com/aws/aws-sdk-go/service/iotanalytics/iotanalyticsiface" + "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/service/iotanalytics" + awstypes "github.com/aws/aws-sdk-go-v2/service/iotanalytics/types" "github.com/hashicorp/terraform-plugin-log/tflog" "github.com/hashicorp/terraform-provider-aws/internal/conns" "github.com/hashicorp/terraform-provider-aws/internal/logging" @@ -19,12 +19,12 @@ import ( // listTags lists iotanalytics service tags. // The identifier is typically the Amazon Resource Name (ARN), although // it may also be a different identifier depending on the service. -func listTags(ctx context.Context, conn iotanalyticsiface.IoTAnalyticsAPI, identifier string) (tftags.KeyValueTags, error) { +func listTags(ctx context.Context, conn *iotanalytics.Client, identifier string, optFns ...func(*iotanalytics.Options)) (tftags.KeyValueTags, error) { input := &iotanalytics.ListTagsForResourceInput{ ResourceArn: aws.String(identifier), } - output, err := conn.ListTagsForResourceWithContext(ctx, input) + output, err := conn.ListTagsForResource(ctx, input, optFns...) if err != nil { return tftags.New(ctx, nil), err @@ -36,7 +36,7 @@ func listTags(ctx context.Context, conn iotanalyticsiface.IoTAnalyticsAPI, ident // ListTags lists iotanalytics service tags and set them in Context. // It is called from outside this package. func (p *servicePackage) ListTags(ctx context.Context, meta any, identifier string) error { - tags, err := listTags(ctx, meta.(*conns.AWSClient).IoTAnalyticsConn(ctx), identifier) + tags, err := listTags(ctx, meta.(*conns.AWSClient).IoTAnalyticsClient(ctx), identifier) if err != nil { return err @@ -52,11 +52,11 @@ func (p *servicePackage) ListTags(ctx context.Context, meta any, identifier stri // []*SERVICE.Tag handling // Tags returns iotanalytics service tags. -func Tags(tags tftags.KeyValueTags) []*iotanalytics.Tag { - result := make([]*iotanalytics.Tag, 0, len(tags)) +func Tags(tags tftags.KeyValueTags) []awstypes.Tag { + result := make([]awstypes.Tag, 0, len(tags)) for k, v := range tags.Map() { - tag := &iotanalytics.Tag{ + tag := awstypes.Tag{ Key: aws.String(k), Value: aws.String(v), } @@ -68,11 +68,11 @@ func Tags(tags tftags.KeyValueTags) []*iotanalytics.Tag { } // KeyValueTags creates tftags.KeyValueTags from iotanalytics service tags. -func KeyValueTags(ctx context.Context, tags []*iotanalytics.Tag) tftags.KeyValueTags { +func KeyValueTags(ctx context.Context, tags []awstypes.Tag) tftags.KeyValueTags { m := make(map[string]*string, len(tags)) for _, tag := range tags { - m[aws.StringValue(tag.Key)] = tag.Value + m[aws.ToString(tag.Key)] = tag.Value } return tftags.New(ctx, m) @@ -80,7 +80,7 @@ func KeyValueTags(ctx context.Context, tags []*iotanalytics.Tag) tftags.KeyValue // getTagsIn returns iotanalytics service tags from Context. // nil is returned if there are no input tags. -func getTagsIn(ctx context.Context) []*iotanalytics.Tag { +func getTagsIn(ctx context.Context) []awstypes.Tag { if inContext, ok := tftags.FromContext(ctx); ok { if tags := Tags(inContext.TagsIn.UnwrapOrDefault()); len(tags) > 0 { return tags @@ -91,7 +91,7 @@ func getTagsIn(ctx context.Context) []*iotanalytics.Tag { } // setTagsOut sets iotanalytics service tags in Context. -func setTagsOut(ctx context.Context, tags []*iotanalytics.Tag) { +func setTagsOut(ctx context.Context, tags []awstypes.Tag) { if inContext, ok := tftags.FromContext(ctx); ok { inContext.TagsOut = option.Some(KeyValueTags(ctx, tags)) } @@ -100,7 +100,7 @@ func setTagsOut(ctx context.Context, tags []*iotanalytics.Tag) { // updateTags updates iotanalytics service tags. // The identifier is typically the Amazon Resource Name (ARN), although // it may also be a different identifier depending on the service. -func updateTags(ctx context.Context, conn iotanalyticsiface.IoTAnalyticsAPI, identifier string, oldTagsMap, newTagsMap any) error { +func updateTags(ctx context.Context, conn *iotanalytics.Client, identifier string, oldTagsMap, newTagsMap any, optFns ...func(*iotanalytics.Options)) error { oldTags := tftags.New(ctx, oldTagsMap) newTags := tftags.New(ctx, newTagsMap) @@ -111,10 +111,10 @@ func updateTags(ctx context.Context, conn iotanalyticsiface.IoTAnalyticsAPI, ide if len(removedTags) > 0 { input := &iotanalytics.UntagResourceInput{ ResourceArn: aws.String(identifier), - TagKeys: aws.StringSlice(removedTags.Keys()), + TagKeys: removedTags.Keys(), } - _, err := conn.UntagResourceWithContext(ctx, input) + _, err := conn.UntagResource(ctx, input, optFns...) if err != nil { return fmt.Errorf("untagging resource (%s): %w", identifier, err) @@ -129,7 +129,7 @@ func updateTags(ctx context.Context, conn iotanalyticsiface.IoTAnalyticsAPI, ide Tags: Tags(updatedTags), } - _, err := conn.TagResourceWithContext(ctx, input) + _, err := conn.TagResource(ctx, input, optFns...) if err != nil { return fmt.Errorf("tagging resource (%s): %w", identifier, err) @@ -142,5 +142,5 @@ func updateTags(ctx context.Context, conn iotanalyticsiface.IoTAnalyticsAPI, ide // UpdateTags updates iotanalytics service tags. // It is called from outside this package. func (p *servicePackage) UpdateTags(ctx context.Context, meta any, identifier string, oldTags, newTags any) error { - return updateTags(ctx, meta.(*conns.AWSClient).IoTAnalyticsConn(ctx), identifier, oldTags, newTags) + return updateTags(ctx, meta.(*conns.AWSClient).IoTAnalyticsClient(ctx), identifier, oldTags, newTags) } diff --git a/internal/service/iotevents/generate.go b/internal/service/iotevents/generate.go index 0cb770c5da9..ecaa54a5a45 100644 --- a/internal/service/iotevents/generate.go +++ b/internal/service/iotevents/generate.go @@ -1,7 +1,7 @@ // Copyright (c) HashiCorp, Inc. // SPDX-License-Identifier: MPL-2.0 -//go:generate go run ../../generate/tags/main.go -ListTags -ServiceTagsSlice -UpdateTags +//go:generate go run ../../generate/tags/main.go -ListTags -ServiceTagsSlice -UpdateTags -AWSSDKVersion=2 //go:generate go run ../../generate/servicepackage/main.go // ONLY generate directives and package declaration! Do not add anything else to this file. diff --git a/internal/service/iotevents/service_endpoint_resolver_gen.go b/internal/service/iotevents/service_endpoint_resolver_gen.go index 8848888c5d6..013e6dc51c6 100644 --- a/internal/service/iotevents/service_endpoint_resolver_gen.go +++ b/internal/service/iotevents/service_endpoint_resolver_gen.go @@ -6,65 +6,63 @@ import ( "context" "fmt" "net" - "net/url" - endpoints_sdkv1 "github.com/aws/aws-sdk-go/aws/endpoints" + aws_sdkv2 "github.com/aws/aws-sdk-go-v2/aws" + iotevents_sdkv2 "github.com/aws/aws-sdk-go-v2/service/iotevents" + smithyendpoints "github.com/aws/smithy-go/endpoints" "github.com/hashicorp/terraform-plugin-log/tflog" "github.com/hashicorp/terraform-provider-aws/internal/errs" ) -var _ endpoints_sdkv1.Resolver = resolverSDKv1{} +var _ iotevents_sdkv2.EndpointResolverV2 = resolverSDKv2{} -type resolverSDKv1 struct { - ctx context.Context +type resolverSDKv2 struct { + defaultResolver iotevents_sdkv2.EndpointResolverV2 } -func newEndpointResolverSDKv1(ctx context.Context) resolverSDKv1 { - return resolverSDKv1{ - ctx: ctx, +func newEndpointResolverSDKv2() resolverSDKv2 { + return resolverSDKv2{ + defaultResolver: iotevents_sdkv2.NewDefaultEndpointResolverV2(), } } -func (r resolverSDKv1) EndpointFor(service, region string, opts ...func(*endpoints_sdkv1.Options)) (endpoint endpoints_sdkv1.ResolvedEndpoint, err error) { - ctx := r.ctx +func (r resolverSDKv2) ResolveEndpoint(ctx context.Context, params iotevents_sdkv2.EndpointParameters) (endpoint smithyendpoints.Endpoint, err error) { + params = params.WithDefaults() + useFIPS := aws_sdkv2.ToBool(params.UseFIPS) - var opt endpoints_sdkv1.Options - opt.Set(opts...) - - useFIPS := opt.UseFIPSEndpoint == endpoints_sdkv1.FIPSEndpointStateEnabled + if eps := params.Endpoint; aws_sdkv2.ToString(eps) != "" { + tflog.Debug(ctx, "setting endpoint", map[string]any{ + "tf_aws.endpoint": endpoint, + }) - defaultResolver := endpoints_sdkv1.DefaultResolver() + if useFIPS { + tflog.Debug(ctx, "endpoint set, ignoring UseFIPSEndpoint setting") + params.UseFIPS = aws_sdkv2.Bool(false) + } - if useFIPS { + return r.defaultResolver.ResolveEndpoint(ctx, params) + } else if useFIPS { ctx = tflog.SetField(ctx, "tf_aws.use_fips", useFIPS) - endpoint, err = defaultResolver.EndpointFor(service, region, opts...) + endpoint, err = r.defaultResolver.ResolveEndpoint(ctx, params) if err != nil { return endpoint, err } tflog.Debug(ctx, "endpoint resolved", map[string]any{ - "tf_aws.endpoint": endpoint.URL, + "tf_aws.endpoint": endpoint.URI.String(), }) - var endpointURL *url.URL - endpointURL, err = url.Parse(endpoint.URL) - if err != nil { - return endpoint, err - } - - hostname := endpointURL.Hostname() + hostname := endpoint.URI.Hostname() _, err = net.LookupHost(hostname) if err != nil { if dnsErr, ok := errs.As[*net.DNSError](err); ok && dnsErr.IsNotFound { tflog.Debug(ctx, "default endpoint host not found, disabling FIPS", map[string]any{ "tf_aws.hostname": hostname, }) - opts = append(opts, func(o *endpoints_sdkv1.Options) { - o.UseFIPSEndpoint = endpoints_sdkv1.FIPSEndpointStateDisabled - }) + params.UseFIPS = aws_sdkv2.Bool(false) } else { - err = fmt.Errorf("looking up accessanalyzer endpoint %q: %s", hostname, err) + err = fmt.Errorf("looking up iotevents endpoint %q: %s", hostname, err) return } } else { @@ -72,5 +70,13 @@ func (r resolverSDKv1) EndpointFor(service, region string, opts ...func(*endpoin } } - return defaultResolver.EndpointFor(service, region, opts...) + return r.defaultResolver.ResolveEndpoint(ctx, params) +} + +func withBaseEndpoint(endpoint string) func(*iotevents_sdkv2.Options) { + return func(o *iotevents_sdkv2.Options) { + if endpoint != "" { + o.BaseEndpoint = aws_sdkv2.String(endpoint) + } + } } diff --git a/internal/service/iotevents/service_endpoints_gen_test.go b/internal/service/iotevents/service_endpoints_gen_test.go index deb66f9606d..ecd246190b4 100644 --- a/internal/service/iotevents/service_endpoints_gen_test.go +++ b/internal/service/iotevents/service_endpoints_gen_test.go @@ -4,18 +4,22 @@ package iotevents_test import ( "context" + "errors" "fmt" "maps" "net" "net/url" "os" "path/filepath" + "reflect" "strings" "testing" - aws_sdkv1 "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/aws/endpoints" - iotevents_sdkv1 "github.com/aws/aws-sdk-go/service/iotevents" + aws_sdkv2 "github.com/aws/aws-sdk-go-v2/aws" + awsmiddleware "github.com/aws/aws-sdk-go-v2/aws/middleware" + iotevents_sdkv2 "github.com/aws/aws-sdk-go-v2/service/iotevents" + "github.com/aws/smithy-go/middleware" + smithyhttp "github.com/aws/smithy-go/transport/http" "github.com/google/go-cmp/cmp" "github.com/hashicorp/aws-sdk-go-base/v2/servicemocks" "github.com/hashicorp/terraform-plugin-sdk/v2/diag" @@ -240,54 +244,63 @@ func TestEndpointConfiguration(t *testing.T) { //nolint:paralleltest // uses t.S } func defaultEndpoint(region string) (url.URL, error) { - r := endpoints.DefaultResolver() + r := iotevents_sdkv2.NewDefaultEndpointResolverV2() - ep, err := r.EndpointFor(iotevents_sdkv1.EndpointsID, region) + ep, err := r.ResolveEndpoint(context.Background(), iotevents_sdkv2.EndpointParameters{ + Region: aws_sdkv2.String(region), + }) if err != nil { return url.URL{}, err } - url, _ := url.Parse(ep.URL) - - if url.Path == "" { - url.Path = "/" + if ep.URI.Path == "" { + ep.URI.Path = "/" } - return *url, nil + return ep.URI, nil } func defaultFIPSEndpoint(region string) (url.URL, error) { - r := endpoints.DefaultResolver() + r := iotevents_sdkv2.NewDefaultEndpointResolverV2() - ep, err := r.EndpointFor(iotevents_sdkv1.EndpointsID, region, func(opt *endpoints.Options) { - opt.UseFIPSEndpoint = endpoints.FIPSEndpointStateEnabled + ep, err := r.ResolveEndpoint(context.Background(), iotevents_sdkv2.EndpointParameters{ + Region: aws_sdkv2.String(region), + UseFIPS: aws_sdkv2.Bool(true), }) if err != nil { return url.URL{}, err } - url, _ := url.Parse(ep.URL) - - if url.Path == "" { - url.Path = "/" + if ep.URI.Path == "" { + ep.URI.Path = "/" } - return *url, nil + return ep.URI, nil } func callService(ctx context.Context, t *testing.T, meta *conns.AWSClient) apiCallParams { t.Helper() - client := meta.IoTEventsConn(ctx) + client := meta.IoTEventsClient(ctx) - req, _ := client.ListAlarmModelsRequest(&iotevents_sdkv1.ListAlarmModelsInput{}) + var result apiCallParams - req.HTTPRequest.URL.Path = "/" - - return apiCallParams{ - endpoint: req.HTTPRequest.URL.String(), - region: aws_sdkv1.StringValue(client.Config.Region), + _, err := client.ListAlarmModels(ctx, &iotevents_sdkv2.ListAlarmModelsInput{}, + func(opts *iotevents_sdkv2.Options) { + opts.APIOptions = append(opts.APIOptions, + addRetrieveEndpointURLMiddleware(t, &result.endpoint), + addRetrieveRegionMiddleware(&result.region), + addCancelRequestMiddleware(), + ) + }, + ) + if err == nil { + t.Fatal("Expected an error, got none") + } else if !errors.Is(err, errCancelOperation) { + t.Fatalf("Unexpected error: %s", err) } + + return result } func withNoConfig(_ *caseSetup) { @@ -466,6 +479,89 @@ func testEndpointCase(t *testing.T, region string, testcase endpointTestCase, ca } } +func addRetrieveEndpointURLMiddleware(t *testing.T, endpoint *string) func(*middleware.Stack) error { + return func(stack *middleware.Stack) error { + return stack.Finalize.Add( + retrieveEndpointURLMiddleware(t, endpoint), + middleware.After, + ) + } +} + +func retrieveEndpointURLMiddleware(t *testing.T, endpoint *string) middleware.FinalizeMiddleware { + return middleware.FinalizeMiddlewareFunc( + "Test: Retrieve Endpoint", + func(ctx context.Context, in middleware.FinalizeInput, next middleware.FinalizeHandler) (middleware.FinalizeOutput, middleware.Metadata, error) { + t.Helper() + + request, ok := in.Request.(*smithyhttp.Request) + if !ok { + t.Fatalf("Expected *github.com/aws/smithy-go/transport/http.Request, got %s", fullTypeName(in.Request)) + } + + url := request.URL + url.RawQuery = "" + url.Path = "/" + + *endpoint = url.String() + + return next.HandleFinalize(ctx, in) + }) +} + +func addRetrieveRegionMiddleware(region *string) func(*middleware.Stack) error { + return func(stack *middleware.Stack) error { + return stack.Serialize.Add( + retrieveRegionMiddleware(region), + middleware.After, + ) + } +} + +func retrieveRegionMiddleware(region *string) middleware.SerializeMiddleware { + return middleware.SerializeMiddlewareFunc( + "Test: Retrieve Region", + func(ctx context.Context, in middleware.SerializeInput, next middleware.SerializeHandler) (middleware.SerializeOutput, middleware.Metadata, error) { + *region = awsmiddleware.GetRegion(ctx) + + return next.HandleSerialize(ctx, in) + }, + ) +} + +var errCancelOperation = fmt.Errorf("Test: Canceling request") + +func addCancelRequestMiddleware() func(*middleware.Stack) error { + return func(stack *middleware.Stack) error { + return stack.Finalize.Add( + cancelRequestMiddleware(), + middleware.After, + ) + } +} + +// cancelRequestMiddleware creates a Smithy middleware that intercepts the request before sending and cancels it +func cancelRequestMiddleware() middleware.FinalizeMiddleware { + return middleware.FinalizeMiddlewareFunc( + "Test: Cancel Requests", + func(_ context.Context, in middleware.FinalizeInput, next middleware.FinalizeHandler) (middleware.FinalizeOutput, middleware.Metadata, error) { + return middleware.FinalizeOutput{}, middleware.Metadata{}, errCancelOperation + }) +} + +func fullTypeName(i interface{}) string { + return fullValueTypeName(reflect.ValueOf(i)) +} + +func fullValueTypeName(v reflect.Value) string { + if v.Kind() == reflect.Ptr { + return "*" + fullValueTypeName(reflect.Indirect(v)) + } + + requestType := v.Type() + return fmt.Sprintf("%s.%s", requestType.PkgPath(), requestType.Name()) +} + func generateSharedConfigFile(config configFile) string { var buf strings.Builder diff --git a/internal/service/iotevents/service_package_gen.go b/internal/service/iotevents/service_package_gen.go index bd734ea2837..c664bdbabc5 100644 --- a/internal/service/iotevents/service_package_gen.go +++ b/internal/service/iotevents/service_package_gen.go @@ -5,10 +5,8 @@ package iotevents import ( "context" - aws_sdkv1 "github.com/aws/aws-sdk-go/aws" - session_sdkv1 "github.com/aws/aws-sdk-go/aws/session" - iotevents_sdkv1 "github.com/aws/aws-sdk-go/service/iotevents" - "github.com/hashicorp/terraform-plugin-log/tflog" + aws_sdkv2 "github.com/aws/aws-sdk-go-v2/aws" + iotevents_sdkv2 "github.com/aws/aws-sdk-go-v2/service/iotevents" "github.com/hashicorp/terraform-provider-aws/internal/conns" "github.com/hashicorp/terraform-provider-aws/internal/types" "github.com/hashicorp/terraform-provider-aws/names" @@ -36,22 +34,14 @@ func (p *servicePackage) ServicePackageName() string { return names.IoTEvents } -// NewConn returns a new AWS SDK for Go v1 client for this service package's AWS API. -func (p *servicePackage) NewConn(ctx context.Context, config map[string]any) (*iotevents_sdkv1.IoTEvents, error) { - sess := config[names.AttrSession].(*session_sdkv1.Session) +// NewClient returns a new AWS SDK for Go v2 client for this service package's AWS API. +func (p *servicePackage) NewClient(ctx context.Context, config map[string]any) (*iotevents_sdkv2.Client, error) { + cfg := *(config["aws_sdkv2_config"].(*aws_sdkv2.Config)) - cfg := aws_sdkv1.Config{} - - if endpoint := config[names.AttrEndpoint].(string); endpoint != "" { - tflog.Debug(ctx, "setting endpoint", map[string]any{ - "tf_aws.endpoint": endpoint, - }) - cfg.Endpoint = aws_sdkv1.String(endpoint) - } else { - cfg.EndpointResolver = newEndpointResolverSDKv1(ctx) - } - - return iotevents_sdkv1.New(sess.Copy(&cfg)), nil + return iotevents_sdkv2.NewFromConfig(cfg, + iotevents_sdkv2.WithEndpointResolverV2(newEndpointResolverSDKv2()), + withBaseEndpoint(config[names.AttrEndpoint].(string)), + ), nil } func ServicePackage(ctx context.Context) conns.ServicePackage { diff --git a/internal/service/iotevents/tags_gen.go b/internal/service/iotevents/tags_gen.go index 1a6b7912d8b..2aad3d41338 100644 --- a/internal/service/iotevents/tags_gen.go +++ b/internal/service/iotevents/tags_gen.go @@ -5,9 +5,9 @@ import ( "context" "fmt" - "github.com/aws/aws-sdk-go/aws" - "github.com/aws/aws-sdk-go/service/iotevents" - "github.com/aws/aws-sdk-go/service/iotevents/ioteventsiface" + "github.com/aws/aws-sdk-go-v2/aws" + "github.com/aws/aws-sdk-go-v2/service/iotevents" + awstypes "github.com/aws/aws-sdk-go-v2/service/iotevents/types" "github.com/hashicorp/terraform-plugin-log/tflog" "github.com/hashicorp/terraform-provider-aws/internal/conns" "github.com/hashicorp/terraform-provider-aws/internal/logging" @@ -19,12 +19,12 @@ import ( // listTags lists iotevents service tags. // The identifier is typically the Amazon Resource Name (ARN), although // it may also be a different identifier depending on the service. -func listTags(ctx context.Context, conn ioteventsiface.IoTEventsAPI, identifier string) (tftags.KeyValueTags, error) { +func listTags(ctx context.Context, conn *iotevents.Client, identifier string, optFns ...func(*iotevents.Options)) (tftags.KeyValueTags, error) { input := &iotevents.ListTagsForResourceInput{ ResourceArn: aws.String(identifier), } - output, err := conn.ListTagsForResourceWithContext(ctx, input) + output, err := conn.ListTagsForResource(ctx, input, optFns...) if err != nil { return tftags.New(ctx, nil), err @@ -36,7 +36,7 @@ func listTags(ctx context.Context, conn ioteventsiface.IoTEventsAPI, identifier // ListTags lists iotevents service tags and set them in Context. // It is called from outside this package. func (p *servicePackage) ListTags(ctx context.Context, meta any, identifier string) error { - tags, err := listTags(ctx, meta.(*conns.AWSClient).IoTEventsConn(ctx), identifier) + tags, err := listTags(ctx, meta.(*conns.AWSClient).IoTEventsClient(ctx), identifier) if err != nil { return err @@ -52,11 +52,11 @@ func (p *servicePackage) ListTags(ctx context.Context, meta any, identifier stri // []*SERVICE.Tag handling // Tags returns iotevents service tags. -func Tags(tags tftags.KeyValueTags) []*iotevents.Tag { - result := make([]*iotevents.Tag, 0, len(tags)) +func Tags(tags tftags.KeyValueTags) []awstypes.Tag { + result := make([]awstypes.Tag, 0, len(tags)) for k, v := range tags.Map() { - tag := &iotevents.Tag{ + tag := awstypes.Tag{ Key: aws.String(k), Value: aws.String(v), } @@ -68,11 +68,11 @@ func Tags(tags tftags.KeyValueTags) []*iotevents.Tag { } // KeyValueTags creates tftags.KeyValueTags from iotevents service tags. -func KeyValueTags(ctx context.Context, tags []*iotevents.Tag) tftags.KeyValueTags { +func KeyValueTags(ctx context.Context, tags []awstypes.Tag) tftags.KeyValueTags { m := make(map[string]*string, len(tags)) for _, tag := range tags { - m[aws.StringValue(tag.Key)] = tag.Value + m[aws.ToString(tag.Key)] = tag.Value } return tftags.New(ctx, m) @@ -80,7 +80,7 @@ func KeyValueTags(ctx context.Context, tags []*iotevents.Tag) tftags.KeyValueTag // getTagsIn returns iotevents service tags from Context. // nil is returned if there are no input tags. -func getTagsIn(ctx context.Context) []*iotevents.Tag { +func getTagsIn(ctx context.Context) []awstypes.Tag { if inContext, ok := tftags.FromContext(ctx); ok { if tags := Tags(inContext.TagsIn.UnwrapOrDefault()); len(tags) > 0 { return tags @@ -91,7 +91,7 @@ func getTagsIn(ctx context.Context) []*iotevents.Tag { } // setTagsOut sets iotevents service tags in Context. -func setTagsOut(ctx context.Context, tags []*iotevents.Tag) { +func setTagsOut(ctx context.Context, tags []awstypes.Tag) { if inContext, ok := tftags.FromContext(ctx); ok { inContext.TagsOut = option.Some(KeyValueTags(ctx, tags)) } @@ -100,7 +100,7 @@ func setTagsOut(ctx context.Context, tags []*iotevents.Tag) { // updateTags updates iotevents service tags. // The identifier is typically the Amazon Resource Name (ARN), although // it may also be a different identifier depending on the service. -func updateTags(ctx context.Context, conn ioteventsiface.IoTEventsAPI, identifier string, oldTagsMap, newTagsMap any) error { +func updateTags(ctx context.Context, conn *iotevents.Client, identifier string, oldTagsMap, newTagsMap any, optFns ...func(*iotevents.Options)) error { oldTags := tftags.New(ctx, oldTagsMap) newTags := tftags.New(ctx, newTagsMap) @@ -111,10 +111,10 @@ func updateTags(ctx context.Context, conn ioteventsiface.IoTEventsAPI, identifie if len(removedTags) > 0 { input := &iotevents.UntagResourceInput{ ResourceArn: aws.String(identifier), - TagKeys: aws.StringSlice(removedTags.Keys()), + TagKeys: removedTags.Keys(), } - _, err := conn.UntagResourceWithContext(ctx, input) + _, err := conn.UntagResource(ctx, input, optFns...) if err != nil { return fmt.Errorf("untagging resource (%s): %w", identifier, err) @@ -129,7 +129,7 @@ func updateTags(ctx context.Context, conn ioteventsiface.IoTEventsAPI, identifie Tags: Tags(updatedTags), } - _, err := conn.TagResourceWithContext(ctx, input) + _, err := conn.TagResource(ctx, input, optFns...) if err != nil { return fmt.Errorf("tagging resource (%s): %w", identifier, err) @@ -142,5 +142,5 @@ func updateTags(ctx context.Context, conn ioteventsiface.IoTEventsAPI, identifie // UpdateTags updates iotevents service tags. // It is called from outside this package. func (p *servicePackage) UpdateTags(ctx context.Context, meta any, identifier string, oldTags, newTags any) error { - return updateTags(ctx, meta.(*conns.AWSClient).IoTEventsConn(ctx), identifier, oldTags, newTags) + return updateTags(ctx, meta.(*conns.AWSClient).IoTEventsClient(ctx), identifier, oldTags, newTags) } diff --git a/names/data/names_data.hcl b/names/data/names_data.hcl index 288549a8923..903c4a08c63 100644 --- a/names/data/names_data.hcl +++ b/names/data/names_data.hcl @@ -4564,7 +4564,7 @@ service "iotanalytics" { sdk { id = "IoTAnalytics" - client_version = [1] + client_version = [2] } names { @@ -4656,7 +4656,7 @@ service "iotevents" { sdk { id = "IoT Events" - client_version = [1] + client_version = [2] } names { @@ -4742,7 +4742,7 @@ service "greengrass" { sdk { id = "Greengrass" - client_version = [1] + client_version = [2] } names { @@ -9779,7 +9779,7 @@ service "iot" { sdk { id = "IoT" - client_version = [1] + client_version = [2] } names { diff --git a/tools/tfsdk2fw/go.mod b/tools/tfsdk2fw/go.mod index e1c0cb47194..033db5b9070 100644 --- a/tools/tfsdk2fw/go.mod +++ b/tools/tfsdk2fw/go.mod @@ -18,13 +18,13 @@ require ( github.com/agext/levenshtein v1.2.3 // indirect github.com/apparentlymart/go-textseg/v15 v15.0.0 // indirect github.com/armon/go-radix v1.0.0 // indirect - github.com/aws/aws-sdk-go v1.54.11 // indirect + github.com/aws/aws-sdk-go v1.54.12 // indirect github.com/aws/aws-sdk-go-v2 v1.30.1 // indirect github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.3 // indirect - github.com/aws/aws-sdk-go-v2/config v1.27.22 // indirect - github.com/aws/aws-sdk-go-v2/credentials v1.17.22 // indirect - github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.8 // indirect - github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.17.2 // indirect + github.com/aws/aws-sdk-go-v2/config v1.27.23 // indirect + github.com/aws/aws-sdk-go-v2/credentials v1.17.23 // indirect + github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.9 // indirect + github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.17.3 // indirect github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.13 // indirect github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.13 // indirect github.com/aws/aws-sdk-go-v2/internal/ini v1.8.0 // indirect @@ -32,7 +32,7 @@ require ( github.com/aws/aws-sdk-go-v2/service/accessanalyzer v1.32.1 // indirect github.com/aws/aws-sdk-go-v2/service/account v1.19.1 // indirect github.com/aws/aws-sdk-go-v2/service/acm v1.28.1 // indirect - github.com/aws/aws-sdk-go-v2/service/acmpca v1.33.0 // indirect + github.com/aws/aws-sdk-go-v2/service/acmpca v1.33.1 // indirect github.com/aws/aws-sdk-go-v2/service/amp v1.27.1 // indirect github.com/aws/aws-sdk-go-v2/service/amplify v1.23.1 // indirect github.com/aws/aws-sdk-go-v2/service/apigateway v1.25.1 // indirect @@ -108,7 +108,7 @@ require ( github.com/aws/aws-sdk-go-v2/service/ecr v1.30.1 // indirect github.com/aws/aws-sdk-go-v2/service/ecrpublic v1.25.1 // indirect github.com/aws/aws-sdk-go-v2/service/ecs v1.44.1 // indirect - github.com/aws/aws-sdk-go-v2/service/eks v1.45.1 // indirect + github.com/aws/aws-sdk-go-v2/service/eks v1.46.0 // indirect github.com/aws/aws-sdk-go-v2/service/elasticache v1.40.1 // indirect github.com/aws/aws-sdk-go-v2/service/elasticbeanstalk v1.25.1 // indirect github.com/aws/aws-sdk-go-v2/service/elasticloadbalancingv2 v1.33.1 // indirect @@ -123,6 +123,7 @@ require ( github.com/aws/aws-sdk-go-v2/service/glacier v1.24.1 // indirect github.com/aws/aws-sdk-go-v2/service/globalaccelerator v1.26.1 // indirect github.com/aws/aws-sdk-go-v2/service/grafana v1.24.1 // indirect + github.com/aws/aws-sdk-go-v2/service/greengrass v1.25.1 // indirect github.com/aws/aws-sdk-go-v2/service/groundstation v1.29.1 // indirect github.com/aws/aws-sdk-go-v2/service/guardduty v1.45.1 // indirect github.com/aws/aws-sdk-go-v2/service/healthlake v1.26.1 // indirect @@ -135,6 +136,9 @@ require ( github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.11.15 // indirect github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.17.13 // indirect github.com/aws/aws-sdk-go-v2/service/internetmonitor v1.16.1 // indirect + github.com/aws/aws-sdk-go-v2/service/iot v1.55.1 // indirect + github.com/aws/aws-sdk-go-v2/service/iotanalytics v1.24.1 // indirect + github.com/aws/aws-sdk-go-v2/service/iotevents v1.25.1 // indirect github.com/aws/aws-sdk-go-v2/service/ivschat v1.14.1 // indirect github.com/aws/aws-sdk-go-v2/service/kafka v1.35.1 // indirect github.com/aws/aws-sdk-go-v2/service/kendra v1.52.1 // indirect @@ -218,7 +222,7 @@ require ( github.com/aws/aws-sdk-go-v2/service/vpclattice v1.10.1 // indirect github.com/aws/aws-sdk-go-v2/service/waf v1.23.1 // indirect github.com/aws/aws-sdk-go-v2/service/wafregional v1.23.1 // indirect - github.com/aws/aws-sdk-go-v2/service/wafv2 v1.51.1 // indirect + github.com/aws/aws-sdk-go-v2/service/wafv2 v1.51.2 // indirect github.com/aws/aws-sdk-go-v2/service/wellarchitected v1.32.1 // indirect github.com/aws/aws-sdk-go-v2/service/workspaces v1.43.0 // indirect github.com/aws/aws-sdk-go-v2/service/workspacesweb v1.21.1 // indirect diff --git a/tools/tfsdk2fw/go.sum b/tools/tfsdk2fw/go.sum index 6e74706721c..9fa094611f0 100644 --- a/tools/tfsdk2fw/go.sum +++ b/tools/tfsdk2fw/go.sum @@ -22,20 +22,20 @@ github.com/apparentlymart/go-textseg/v15 v15.0.0 h1:uYvfpb3DyLSCGWnctWKGj857c6ew github.com/apparentlymart/go-textseg/v15 v15.0.0/go.mod h1:K8XmNZdhEBkdlyDdvbmmsvpAG721bKi0joRfFdHIWJ4= 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.54.11 h1:Zxuv/R+IVS0B66yz4uezhxH9FN9/G2nbxejYqAMFjxk= -github.com/aws/aws-sdk-go v1.54.11/go.mod h1:eRwEWoyTWFMVYVQzKMNHWP5/RV4xIUGMQfXQHfHkpNU= +github.com/aws/aws-sdk-go v1.54.12 h1:xPDB+GSBZq0rJbmDZF+EyfMbnWRyfEPcn7PZ7bJjXSw= +github.com/aws/aws-sdk-go v1.54.12/go.mod h1:eRwEWoyTWFMVYVQzKMNHWP5/RV4xIUGMQfXQHfHkpNU= github.com/aws/aws-sdk-go-v2 v1.30.1 h1:4y/5Dvfrhd1MxRDD77SrfsDaj8kUkkljU7XE83NPV+o= github.com/aws/aws-sdk-go-v2 v1.30.1/go.mod h1:nIQjQVp5sfpQcTc9mPSr1B0PaWK5ByX9MOoDadSN4lc= github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.3 h1:tW1/Rkad38LA15X4UQtjXZXNKsCgkshC3EbmcUmghTg= github.com/aws/aws-sdk-go-v2/aws/protocol/eventstream v1.6.3/go.mod h1:UbnqO+zjqk3uIt9yCACHJ9IVNhyhOCnYk8yA19SAWrM= -github.com/aws/aws-sdk-go-v2/config v1.27.22 h1:TRkQVtpDINt+Na/ToU7iptyW6U0awAwJ24q4XN+59k8= -github.com/aws/aws-sdk-go-v2/config v1.27.22/go.mod h1:EYY3mVgFRUWkh6QNKH64MdyKs1YSUgatc0Zp3MDxi7c= -github.com/aws/aws-sdk-go-v2/credentials v1.17.22 h1:wu9kXQbbt64ul09v3ye4HYleAr4WiGV/uv69EXKDEr0= -github.com/aws/aws-sdk-go-v2/credentials v1.17.22/go.mod h1:pcvMtPcxJn3r2k6mZD9I0EcumLqPLA7V/0iCgOIlY+o= -github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.8 h1:FR+oWPFb/8qMVYMWN98bUZAGqPvLHiyqg1wqQGfUAXY= -github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.8/go.mod h1:EgSKcHiuuakEIxJcKGzVNWh5srVAQ3jKaSrBGRYvM48= -github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.17.2 h1:Za8rJGgO8qRfCvLTBNTTeQlFkIubOPrNuDX03TghDA0= -github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.17.2/go.mod h1:Ks7cRJzJ3WyhLux68C+EzogpJRKQi6HobwJVJInY5kw= +github.com/aws/aws-sdk-go-v2/config v1.27.23 h1:Cr/gJEa9NAS7CDAjbnB7tHYb3aLZI2gVggfmSAasDac= +github.com/aws/aws-sdk-go-v2/config v1.27.23/go.mod h1:WMMYHqLCFu5LH05mFOF5tsq1PGEMfKbu083VKqLCd0o= +github.com/aws/aws-sdk-go-v2/credentials v1.17.23 h1:G1CfmLVoO2TdQ8z9dW+JBc/r8+MqyPQhXCafNZcXVZo= +github.com/aws/aws-sdk-go-v2/credentials v1.17.23/go.mod h1:V/DvSURn6kKgcuKEk4qwSwb/fZ2d++FFARtWSbXnLqY= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.9 h1:Aznqksmd6Rfv2HQN9cpqIV/lQRMaIpJkLLaJ1ZI76no= +github.com/aws/aws-sdk-go-v2/feature/ec2/imds v1.16.9/go.mod h1:WQr3MY7AxGNxaqAtsDWn+fBxmd4XvLkzeqQ8P1VM0/w= +github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.17.3 h1:J2mHCzCeDQNfBOas73ARi4/CsLm0wYpQ3Itll8dPDBQ= +github.com/aws/aws-sdk-go-v2/feature/s3/manager v1.17.3/go.mod h1:6rYGWnaLHD+WRF4E709VW+HEEJPKZbNdjHgq9osFXuE= github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.13 h1:5SAoZ4jYpGH4721ZNoS1znQrhOfZinOhc4XuTXx/nVc= github.com/aws/aws-sdk-go-v2/internal/configsources v1.3.13/go.mod h1:+rdA6ZLpaSeM7tSg/B0IEDinCIBJGmW8rKDFkYpP04g= github.com/aws/aws-sdk-go-v2/internal/endpoints/v2 v2.6.13 h1:WIijqeaAO7TYFLbhsZmi2rgLEAtWOC1LhxCAVTJlSKw= @@ -50,8 +50,8 @@ github.com/aws/aws-sdk-go-v2/service/account v1.19.1 h1:zrQ4xJWzZvtpk82yTNUa1epa github.com/aws/aws-sdk-go-v2/service/account v1.19.1/go.mod h1:MM1yOaj4b9dKTV559gAznF1cxwH25q9coIs72FOyok8= github.com/aws/aws-sdk-go-v2/service/acm v1.28.1 h1:fwsAC87QCkj4eQ3/q6qqBux9s0sdBb8HRsUEK9Lpf1Q= github.com/aws/aws-sdk-go-v2/service/acm v1.28.1/go.mod h1:PlzT5RdIk5yPjDQu9q+SB3UhMY2XIvGhol8vBhZFc0M= -github.com/aws/aws-sdk-go-v2/service/acmpca v1.33.0 h1:21PU1CLtfIDky8DWRgSPRW2SK79IMbjhT04Wh8FRkzw= -github.com/aws/aws-sdk-go-v2/service/acmpca v1.33.0/go.mod h1:2a/l5Gz15HVSg1nyQauzh+WmZ5bIWjpigz5k/Z8GqNo= +github.com/aws/aws-sdk-go-v2/service/acmpca v1.33.1 h1:kyHfl1VRBejUolTBJ0YIp6rPxAKYyjIms6bQRILrXC8= +github.com/aws/aws-sdk-go-v2/service/acmpca v1.33.1/go.mod h1:2a/l5Gz15HVSg1nyQauzh+WmZ5bIWjpigz5k/Z8GqNo= github.com/aws/aws-sdk-go-v2/service/amp v1.27.1 h1:va9j7MGA8jBlQs9KujMlkSdnC26TuEJXv7ywnFjmTZ8= github.com/aws/aws-sdk-go-v2/service/amp v1.27.1/go.mod h1:QhmX7qjomjuHJjCJbW+QRdaCBM42v1eAbWvBVFrT1Vw= github.com/aws/aws-sdk-go-v2/service/amplify v1.23.1 h1:rBKIzcAYdu33dRUlKeiBqJ0jKPhTb9ppMjyykUIXqkw= @@ -202,8 +202,8 @@ github.com/aws/aws-sdk-go-v2/service/ecrpublic v1.25.1 h1:54/7zy+oA2ep9UzWjAtcca github.com/aws/aws-sdk-go-v2/service/ecrpublic v1.25.1/go.mod h1:2UjSvHCwdRoPF17osaRvfBXuo32KPSvTlGMii5YbjyU= github.com/aws/aws-sdk-go-v2/service/ecs v1.44.1 h1:Kc0ubjRMW0nq5Tu2LDhQBOLzP2/oUceZNP0NUfU+MQo= github.com/aws/aws-sdk-go-v2/service/ecs v1.44.1/go.mod h1:+l39x/ffnRnFeIAe3OzWX6LTv/fkLyo5zNehFgMEwzQ= -github.com/aws/aws-sdk-go-v2/service/eks v1.45.1 h1:pKNGlzsJNJ/p7naBjlXakz5nzHa4+p27Psu8UuSZ6h0= -github.com/aws/aws-sdk-go-v2/service/eks v1.45.1/go.mod h1:p4Yk0zfWEoLvvQ4V6XZrTmAAPzcevNnEsbUR82NAY0w= +github.com/aws/aws-sdk-go-v2/service/eks v1.46.0 h1:ZPhHHZtAjVohIGIVjXECPfljcPOQ+hjZ1IpgvjPTJ50= +github.com/aws/aws-sdk-go-v2/service/eks v1.46.0/go.mod h1:p4Yk0zfWEoLvvQ4V6XZrTmAAPzcevNnEsbUR82NAY0w= github.com/aws/aws-sdk-go-v2/service/elasticache v1.40.1 h1:yJMmaQ3jTpCrsXl0lxQUsvlMZA4/B8ia+99eSbIBjAA= github.com/aws/aws-sdk-go-v2/service/elasticache v1.40.1/go.mod h1:HfavnpYheVa3TXRxHNZYIM/BMI8hmSbtiSbYxqdri/4= github.com/aws/aws-sdk-go-v2/service/elasticbeanstalk v1.25.1 h1:T1lEDcxMSuHOIeY6CrmTCpRa1lOy9GMi03OZCa9H31g= @@ -232,6 +232,8 @@ github.com/aws/aws-sdk-go-v2/service/globalaccelerator v1.26.1 h1:ZF//0v9qJttmSj github.com/aws/aws-sdk-go-v2/service/globalaccelerator v1.26.1/go.mod h1:bWwtuxoMnUPJAn7EjLscm0ddKzf++mnjCUF8J/gjxsA= github.com/aws/aws-sdk-go-v2/service/grafana v1.24.1 h1:9arpyvo+AHuSlfwd0B4+99mSauANa+ca4UR04TXpMC8= github.com/aws/aws-sdk-go-v2/service/grafana v1.24.1/go.mod h1:w3Do1roFlHxKtjWkjSwevSX4Vbia2CpZ32rfBa38xJs= +github.com/aws/aws-sdk-go-v2/service/greengrass v1.25.1 h1:Fw4hUGV/H7uJUf+h/ZkwXHDUrCeRzy6T8JvzsM5J1yE= +github.com/aws/aws-sdk-go-v2/service/greengrass v1.25.1/go.mod h1:sdnAwxQLduSCSlpqfPY8XSfcPNzT9uMG+h7+AmgPQ1w= github.com/aws/aws-sdk-go-v2/service/groundstation v1.29.1 h1:b7NYx+Wns7iVGWCoVDlYeJhmBvzYBrtCqbIkDxOrHE8= github.com/aws/aws-sdk-go-v2/service/groundstation v1.29.1/go.mod h1:AJdJPFZ2QWkkVn/zt+y9KcVTZiMCWQCgDyMRjxr6Rww= github.com/aws/aws-sdk-go-v2/service/guardduty v1.45.1 h1:+YYUnMwh5C8JIKCdwMjcamNqbId+vidg4Dri2Z+VSKA= @@ -256,6 +258,12 @@ github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.17.13 h1:Eq2THzHt6P41m github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.17.13/go.mod h1:FgwTca6puegxgCInYwGjmd4tB9195Dd6LCuA+8MjpWw= github.com/aws/aws-sdk-go-v2/service/internetmonitor v1.16.1 h1:k/RKod+whF8SajBLtMbonnASqDH7cdcaV+dV4Y+Iy14= github.com/aws/aws-sdk-go-v2/service/internetmonitor v1.16.1/go.mod h1:XPMC1HSRRPuwRPyJxEOdmXDMwSzwuLRgJxWvruqOb1E= +github.com/aws/aws-sdk-go-v2/service/iot v1.55.1 h1:vtcrAu71ib/I1HZMNT/Kse/EHOnoxsG72sqlkuCn7mE= +github.com/aws/aws-sdk-go-v2/service/iot v1.55.1/go.mod h1:teEXCZKFcHzIeb3lp18Rg1UQNB1dFSza6xlnPySBUsE= +github.com/aws/aws-sdk-go-v2/service/iotanalytics v1.24.1 h1:HgYcw25tNge1/t+QTaGP5snHG2Ktb/u4KlD/qkxyjk8= +github.com/aws/aws-sdk-go-v2/service/iotanalytics v1.24.1/go.mod h1:7EAfulhWZOndeYQyqloMJoPK9YbInZ7MXsDRTB3QcU0= +github.com/aws/aws-sdk-go-v2/service/iotevents v1.25.1 h1:5DFNTv6jUEMVK/XiO/kjFhJLALQUXhBxERUHqY2I1Fg= +github.com/aws/aws-sdk-go-v2/service/iotevents v1.25.1/go.mod h1:aFAvBjoz1mujsaPHgVoj4Bhwg6xG7vzk1AfCOt7/u8I= github.com/aws/aws-sdk-go-v2/service/ivschat v1.14.1 h1:rmVLJaE6iqVSSeipZnhul8BMBm6PkVIWvFkPUnSLYcc= github.com/aws/aws-sdk-go-v2/service/ivschat v1.14.1/go.mod h1:IUQ9qdszWBPacNZ36JLkmOxGx/2LCzz/DOZjpg/8tz4= github.com/aws/aws-sdk-go-v2/service/kafka v1.35.1 h1:Q4Jr/gf+7LHjBFTdecQJn4ugVoVszCHzyq1EztrHHkc= @@ -422,8 +430,8 @@ github.com/aws/aws-sdk-go-v2/service/waf v1.23.1 h1:tx7khP2EwrDhX9Kzm0hDfggcYvHs github.com/aws/aws-sdk-go-v2/service/waf v1.23.1/go.mod h1:FUoTH4A1m9fZ7Fp6OvCVhZnEw0BOZKaaAhd1tSiaoYQ= github.com/aws/aws-sdk-go-v2/service/wafregional v1.23.1 h1:RvXU6G18/Y9uGZAAbzF/4bHdzAb09VnGcWYWiH4K6/o= github.com/aws/aws-sdk-go-v2/service/wafregional v1.23.1/go.mod h1:zUuYInADnRi0KdVW+FgxM+wikdC0+W4xcMDVG/OQnBc= -github.com/aws/aws-sdk-go-v2/service/wafv2 v1.51.1 h1:WbcdVt+8a9bNqJ7v8ogrMVkIfYzK1+h5NNa1xfk4VPI= -github.com/aws/aws-sdk-go-v2/service/wafv2 v1.51.1/go.mod h1:kfHast+LcTA5amM8pQFIvTzzAlfKTa2/Vilbb9qLoEY= +github.com/aws/aws-sdk-go-v2/service/wafv2 v1.51.2 h1:ohNyyHWxZe2dp1l3YMzrN9OUS0QtvxmjjYMHNyQUK8I= +github.com/aws/aws-sdk-go-v2/service/wafv2 v1.51.2/go.mod h1:kfHast+LcTA5amM8pQFIvTzzAlfKTa2/Vilbb9qLoEY= github.com/aws/aws-sdk-go-v2/service/wellarchitected v1.32.1 h1:FlvBKTXUACdt5eDDB9UAPNwWqs4CCqaU963WSlvWyE8= github.com/aws/aws-sdk-go-v2/service/wellarchitected v1.32.1/go.mod h1:6uG4zrI1dAsqdmv4eEx9VU5NWTIpLSUkh2CQIzDmZfQ= github.com/aws/aws-sdk-go-v2/service/workspaces v1.43.0 h1:8984C5RyPVPGuTq8xH7id5hkW30OR1tcFCqaLA1rSus= diff --git a/website/docs/r/iot_authorizer.html.markdown b/website/docs/r/iot_authorizer.html.markdown index c129f2efe56..5e5750c5c6d 100644 --- a/website/docs/r/iot_authorizer.html.markdown +++ b/website/docs/r/iot_authorizer.html.markdown @@ -23,6 +23,10 @@ resource "aws_iot_authorizer" "example" { token_signing_public_keys = { Key1 = file("test-fixtures/iot-authorizer-signing-key.pem") } + + tags = { + Name = "example" + } } ``` @@ -33,6 +37,7 @@ resource "aws_iot_authorizer" "example" { * `name` - (Required) The name of the authorizer. * `signing_disabled` - (Optional) Specifies whether AWS IoT validates the token signature in an authorization request. Default: `false`. * `status` - (Optional) The status of Authorizer request at creation. Valid values: `ACTIVE`, `INACTIVE`. Default: `ACTIVE`. +* `tags` - (Optional) Map of tags to assign to this resource. If configured with a provider [`default_tags` configuration block](https://www.terraform.io/docs/providers/aws/index.html#default_tags-configuration-block) present, tags with matching keys will overwrite those defined at the provider-level. * `token_key_name` - (Optional) The name of the token key used to extract the token from the HTTP headers. This value is required if signing is enabled in your authorizer. * `token_signing_public_keys` - (Optional) The public keys used to verify the digital signature returned by your custom authentication service. This value is required if signing is enabled in your authorizer. @@ -41,6 +46,7 @@ resource "aws_iot_authorizer" "example" { This resource exports the following attributes in addition to the arguments above: * `arn` - The ARN of the authorizer. +* `tags_all` - A map of tags assigned to the resource, including those inherited from the provider [`default_tags` configuration block](https://www.terraform.io/docs/providers/aws/index.html#default_tags-configuration-block). ## Import