Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .changelog/45467.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
```release-note:new-list-resource
aws_lambda_capacity_provider
```
64 changes: 64 additions & 0 deletions internal/framework/with_list.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,18 @@
package framework

import (
"context"
"fmt"
"slices"

"github.com/hashicorp/terraform-plugin-framework/attr"
"github.com/hashicorp/terraform-plugin-framework/diag"
"github.com/hashicorp/terraform-plugin-framework/list"
"github.com/hashicorp/terraform-plugin-framework/path"
"github.com/hashicorp/terraform-plugin-framework/types/basetypes"
"github.com/hashicorp/terraform-provider-aws/internal/provider/framework/listresource"
tfslices "github.com/hashicorp/terraform-provider-aws/internal/slices"
"github.com/hashicorp/terraform-provider-aws/names"
)

type Lister interface {
Expand All @@ -24,3 +35,56 @@ func (w *WithList) AppendResultInterceptor(interceptor listresource.ListResultIn
func (w WithList) ResultInterceptors() []listresource.ListResultInterceptor {
return w.interceptors
}

func (w *WithList) RunResultInterceptors(ctx context.Context, when listresource.When, params listresource.InterceptorParams) diag.Diagnostics {
var diags diag.Diagnostics
switch when {
case listresource.Before:
params.When = listresource.Before
for interceptor := range slices.Values(w.interceptors) {
diags.Append(interceptor.Read(ctx, params)...)
}
return diags
case listresource.After:
params.When = listresource.After
for interceptor := range tfslices.BackwardValues(w.interceptors) {
diags.Append(interceptor.Read(ctx, params)...)
}
return diags
}

return diags
}

func (w *WithList) ListResourceTagsInit(ctx context.Context, result list.ListResult) basetypes.MapValue {
typ, _ := result.Resource.Schema.TypeAtPath(ctx, path.Root(names.AttrTags))
tagsType := typ.(attr.TypeWithElementType)

return basetypes.NewMapNull(tagsType.ElementType())
}

func (w *WithList) ListResourceTimeoutInit(ctx context.Context, result list.ListResult) (basetypes.ObjectValue, diag.Diagnostics) {
timeoutsType, _ := result.Resource.Schema.TypeAtPath(ctx, path.Root(names.AttrTimeouts))

return newNullObject(timeoutsType)
}

func newNullObject(typ attr.Type) (obj basetypes.ObjectValue, diags diag.Diagnostics) {
i, ok := typ.(attr.TypeWithAttributeTypes)
if !ok {
diags.AddError(
"Internal Error",
"An unexpected error occurred. "+
"This is always an error in the provider. "+
"Please report the following to the provider developer:\n\n"+
fmt.Sprintf("Expected value type to implement attr.TypeWithAttributeTypes, got: %T", typ),
)
return
}

attrTypes := i.AttributeTypes()

obj = basetypes.NewObjectNull(attrTypes)

return obj, diags
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,8 @@ import (
// Multiple values can be ORed together.
type when uint16

type When = when

const (
Before when = 1 << iota // Interceptor is invoked before call to method in schema
After // Interceptor is invoked after successful call to method in schema
Expand Down
144 changes: 144 additions & 0 deletions internal/service/lambda/capacity_provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,14 +6,21 @@ package lambda
import (
"context"
"errors"
"fmt"
"iter"
"strings"
"time"

"github.com/YakDriver/smarterr"
"github.com/aws/aws-sdk-go-v2/aws"
"github.com/aws/aws-sdk-go-v2/aws/arn"
"github.com/aws/aws-sdk-go-v2/service/lambda"
awstypes "github.com/aws/aws-sdk-go-v2/service/lambda/types"
"github.com/hashicorp/terraform-plugin-framework-timeouts/resource/timeouts"
"github.com/hashicorp/terraform-plugin-framework-validators/listvalidator"
"github.com/hashicorp/terraform-plugin-framework/diag"
"github.com/hashicorp/terraform-plugin-framework/list"
listschema "github.com/hashicorp/terraform-plugin-framework/list/schema"
"github.com/hashicorp/terraform-plugin-framework/path"
"github.com/hashicorp/terraform-plugin-framework/resource"
"github.com/hashicorp/terraform-plugin-framework/resource/schema"
Expand All @@ -30,6 +37,7 @@ import (
"github.com/hashicorp/terraform-provider-aws/internal/framework"
"github.com/hashicorp/terraform-provider-aws/internal/framework/flex"
fwtypes "github.com/hashicorp/terraform-provider-aws/internal/framework/types"
"github.com/hashicorp/terraform-provider-aws/internal/provider/framework/listresource"
"github.com/hashicorp/terraform-provider-aws/internal/retry"
"github.com/hashicorp/terraform-provider-aws/internal/smerr"
tftags "github.com/hashicorp/terraform-provider-aws/internal/tags"
Expand All @@ -54,6 +62,11 @@ func newResourceCapacityProvider(_ context.Context) (resource.ResourceWithConfig
return r, nil
}

// @FrameworkListResource("aws_lambda_capacity_provider")
func capacityProviderResourceAsListResource() list.ListResourceWithConfigure {
return &resourceCapacityProvider{}
}

const (
capacityProviderNamePrefix = "CapacityProvider"
ResNameCapacityProvider = "Capacity Provider"
Expand All @@ -63,6 +76,7 @@ type resourceCapacityProvider struct {
framework.ResourceWithModel[resourceCapacityProviderModel]
framework.WithTimeouts
framework.WithImportByIdentity
framework.WithList
}

func (r *resourceCapacityProvider) Schema(ctx context.Context, _ resource.SchemaRequest, response *resource.SchemaResponse) {
Expand Down Expand Up @@ -460,3 +474,133 @@ type scalingPoliciesModel struct {
PredefinedMetricType fwtypes.StringEnum[awstypes.CapacityProviderPredefinedMetricType] `tfsdk:"predefined_metric_type"`
TargetValue types.Float64 `tfsdk:"target_value"`
}

var _ list.ListResource = &resourceCapacityProvider{}

func listCapacityProviders(ctx context.Context, conn *lambda.Client, input *lambda.ListCapacityProvidersInput) iter.Seq2[awstypes.CapacityProvider, error] {
return func(yield func(awstypes.CapacityProvider, error) bool) {
pages := lambda.NewListCapacityProvidersPaginator(conn, input)
for pages.HasMorePages() {
page, err := pages.NextPage(ctx)
if err != nil {
yield(awstypes.CapacityProvider{}, fmt.Errorf("listing Lambda Capacity Providers: %w", err))
return
}

for _, cp := range page.CapacityProviders {
if !yield(cp, nil) {
return
}
}
}
}
}

func (r *resourceCapacityProvider) ListResourceConfigSchema(ctx context.Context, _ list.ListResourceSchemaRequest, response *list.ListResourceSchemaResponse) {
response.Schema = listschema.Schema{
Attributes: map[string]listschema.Attribute{},
}
}

func (r *resourceCapacityProvider) List(ctx context.Context, request list.ListRequest, stream *list.ListResultsStream) {
var query capacityProviderListModel

if request.Config.Raw.IsKnown() && !request.Config.Raw.IsNull() {
if diags := request.Config.Get(ctx, &query); diags.HasError() {
stream.Results = list.ListResultsStreamDiagnostics(diags)
return
}
}

awsClient := r.Meta()
conn := awsClient.LambdaClient(ctx)

stream.Results = func(yield func(list.ListResult) bool) {
result := request.NewListResult(ctx)
var input lambda.ListCapacityProvidersInput
for capacityProvider, err := range listCapacityProviders(ctx, conn, &input) {
if err != nil {
result = list.ListResult{
Diagnostics: diag.Diagnostics{
diag.NewErrorDiagnostic(
"Error Listing Remote Resources",
fmt.Sprintf("Error: %s", err),
),
},
}
yield(result)
return
}

ctx = tftags.NewContext(ctx, awsClient.DefaultTagsConfig(ctx), awsClient.IgnoreTagsConfig(ctx), awsClient.TagPolicyConfig(ctx))
var data resourceCapacityProviderModel
timeoutObject, d := r.ListResourceTimeoutInit(ctx, result)
result.Diagnostics.Append(d...)
if result.Diagnostics.HasError() {
result = list.ListResult{Diagnostics: result.Diagnostics}
yield(result)
return
}

data.Timeouts.Object = timeoutObject
data.Tags.MapValue = r.ListResourceTagsInit(ctx, result)
data.TagsAll.MapValue = r.ListResourceTagsInit(ctx, result)

params := listresource.InterceptorParams{
C: awsClient,
Result: &result,
}

if diags := r.RunResultInterceptors(ctx, listresource.Before, params); diags.HasError() {
result.Diagnostics.Append(diags...)
yield(result)
return
}

if diags := flex.Flatten(ctx, capacityProvider, &data, flex.WithFieldNamePrefix(capacityProviderNamePrefix)); diags.HasError() {
result.Diagnostics.Append(diags...)
yield(result)
return
}

cpARN, err := arn.Parse(data.ARN.ValueString())
if err != nil {
result = list.ListResult{
Diagnostics: diag.Diagnostics{
diag.NewErrorDiagnostic(
"Error Listing Remote Resources",
fmt.Sprintf("Error: %s", err),
),
},
}
yield(result)
return
}

name := strings.TrimPrefix(cpARN.Resource, "capacity-provider:")
data.Name = flex.StringValueToFramework(ctx, name)

if diags := result.Resource.Set(ctx, &data); diags.HasError() {
result.Diagnostics.Append(diags...)
yield(result)
return
}

result.DisplayName = name

if diags := r.RunResultInterceptors(ctx, listresource.After, params); diags.HasError() {
result.Diagnostics.Append(diags...)
yield(result)
return
}

if !yield(result) {
return
}
}
}
}

type capacityProviderListModel struct {
framework.WithRegionModel
}
Loading
Loading