diff --git a/.changelog/34670.txt b/.changelog/34670.txt new file mode 100644 index 00000000000..4d045f17819 --- /dev/null +++ b/.changelog/34670.txt @@ -0,0 +1,3 @@ +```release-note:new-data-source +aws_ssoadmin_application_providers +``` diff --git a/internal/service/ssoadmin/application_providers_data_source.go b/internal/service/ssoadmin/application_providers_data_source.go new file mode 100644 index 00000000000..caca155e7f3 --- /dev/null +++ b/internal/service/ssoadmin/application_providers_data_source.go @@ -0,0 +1,178 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package ssoadmin + +import ( + "context" + + "github.com/aws/aws-sdk-go-v2/service/ssoadmin" + awstypes "github.com/aws/aws-sdk-go-v2/service/ssoadmin/types" + "github.com/hashicorp/terraform-plugin-framework/attr" + "github.com/hashicorp/terraform-plugin-framework/datasource" + "github.com/hashicorp/terraform-plugin-framework/datasource/schema" + "github.com/hashicorp/terraform-plugin-framework/diag" + "github.com/hashicorp/terraform-plugin-framework/types" + "github.com/hashicorp/terraform-provider-aws/internal/create" + "github.com/hashicorp/terraform-provider-aws/internal/framework" + "github.com/hashicorp/terraform-provider-aws/internal/framework/flex" + "github.com/hashicorp/terraform-provider-aws/names" +) + +// @FrameworkDataSource(name="Application Providers") +func newDataSourceApplicationProviders(context.Context) (datasource.DataSourceWithConfigure, error) { + return &dataSourceApplicationProviders{}, nil +} + +const ( + DSNameApplicationProviders = "Application Providers Data Source" +) + +type dataSourceApplicationProviders struct { + framework.DataSourceWithConfigure +} + +func (d *dataSourceApplicationProviders) Metadata(_ context.Context, req datasource.MetadataRequest, resp *datasource.MetadataResponse) { // nosemgrep:ci.meta-in-func-name + resp.TypeName = "aws_ssoadmin_application_providers" +} + +func (d *dataSourceApplicationProviders) Schema(ctx context.Context, req datasource.SchemaRequest, resp *datasource.SchemaResponse) { + resp.Schema = schema.Schema{ + Attributes: map[string]schema.Attribute{ + "id": framework.IDAttribute(), + }, + Blocks: map[string]schema.Block{ + "application_providers": schema.ListNestedBlock{ + NestedObject: schema.NestedBlockObject{ + Attributes: map[string]schema.Attribute{ + "application_provider_arn": framework.ARNAttributeComputedOnly(), + "federation_protocol": schema.StringAttribute{ + Computed: true, + }, + }, + Blocks: map[string]schema.Block{ + "display_data": schema.ListNestedBlock{ + NestedObject: schema.NestedBlockObject{ + Attributes: map[string]schema.Attribute{ + "description": schema.StringAttribute{ + Computed: true, + }, + "display_name": schema.StringAttribute{ + Computed: true, + }, + "icon_url": schema.StringAttribute{ + Computed: true, + }, + }, + }, + }, + }, + }, + }, + }, + } +} + +func (d *dataSourceApplicationProviders) Read(ctx context.Context, req datasource.ReadRequest, resp *datasource.ReadResponse) { + conn := d.Meta().SSOAdminClient(ctx) + + var data dataSourceApplicationProvidersData + resp.Diagnostics.Append(req.Config.Get(ctx, &data)...) + if resp.Diagnostics.HasError() { + return + } + data.ID = types.StringValue(d.Meta().Region) + + paginator := ssoadmin.NewListApplicationProvidersPaginator(conn, &ssoadmin.ListApplicationProvidersInput{}) + var apiObjects []awstypes.ApplicationProvider + for paginator.HasMorePages() { + page, err := paginator.NextPage(ctx) + + if err != nil { + resp.Diagnostics.AddError( + create.ProblemStandardMessage(names.SSOAdmin, create.ErrActionReading, DSNameApplicationProviders, data.ID.String(), err), + err.Error(), + ) + return + } + + if page != nil { + apiObjects = append(apiObjects, page.ApplicationProviders...) + } + } + + applicationProviders, diag := flattenApplicationProviders(ctx, apiObjects) + resp.Diagnostics.Append(diag...) + data.ApplicationProviders = applicationProviders + + resp.Diagnostics.Append(resp.State.Set(ctx, &data)...) +} + +type dataSourceApplicationProvidersData struct { + ApplicationProviders types.List `tfsdk:"application_providers"` + ID types.String `tfsdk:"id"` +} + +var applicationProviderAttrTypes = map[string]attr.Type{ + "application_provider_arn": types.StringType, + "display_data": types.ListType{ElemType: types.ObjectType{AttrTypes: displayDataAttrTypes}}, + "federation_protocol": types.StringType, +} + +var displayDataAttrTypes = map[string]attr.Type{ + "description": types.StringType, + "display_name": types.StringType, + "icon_url": types.StringType, +} + +func flattenApplicationProviders(ctx context.Context, apiObjects []awstypes.ApplicationProvider) (types.List, diag.Diagnostics) { + var diags diag.Diagnostics + elemType := types.ObjectType{AttrTypes: applicationProviderAttrTypes} + + if len(apiObjects) == 0 { + return types.ListNull(elemType), diags + } + + elems := []attr.Value{} + for _, apiObject := range apiObjects { + displayData, d := flattenDisplayData(ctx, apiObject.DisplayData) + diags.Append(d...) + + obj := map[string]attr.Value{ + "application_provider_arn": flex.StringToFramework(ctx, apiObject.ApplicationProviderArn), + "display_data": displayData, + "federation_protocol": flex.StringValueToFramework(ctx, apiObject.FederationProtocol), + } + objVal, d := types.ObjectValue(applicationProviderAttrTypes, obj) + diags.Append(d...) + + elems = append(elems, objVal) + } + + listVal, d := types.ListValue(elemType, elems) + diags.Append(d...) + + return listVal, diags +} + +func flattenDisplayData(ctx context.Context, apiObject *awstypes.DisplayData) (types.List, diag.Diagnostics) { + var diags diag.Diagnostics + elemType := types.ObjectType{AttrTypes: displayDataAttrTypes} + + if apiObject == nil { + return types.ListNull(elemType), diags + } + + obj := map[string]attr.Value{ + "description": flex.StringToFramework(ctx, apiObject.Description), + "display_name": flex.StringToFramework(ctx, apiObject.DisplayName), + "icon_url": flex.StringToFramework(ctx, apiObject.IconUrl), + } + objVal, d := types.ObjectValue(displayDataAttrTypes, obj) + diags.Append(d...) + + listVal, d := types.ListValue(elemType, []attr.Value{objVal}) + diags.Append(d...) + + return listVal, diags +} diff --git a/internal/service/ssoadmin/application_providers_data_source_test.go b/internal/service/ssoadmin/application_providers_data_source_test.go new file mode 100644 index 00000000000..7ce50bb3e3b --- /dev/null +++ b/internal/service/ssoadmin/application_providers_data_source_test.go @@ -0,0 +1,46 @@ +// Copyright (c) HashiCorp, Inc. +// SPDX-License-Identifier: MPL-2.0 + +package ssoadmin_test + +import ( + "testing" + + "github.com/hashicorp/terraform-plugin-testing/helper/resource" + "github.com/hashicorp/terraform-provider-aws/internal/acctest" + "github.com/hashicorp/terraform-provider-aws/names" +) + +func TestAccSSOAdminApplicationProvidersDataSource_basic(t *testing.T) { + ctx := acctest.Context(t) + dataSourceName := "data.aws_ssoadmin_application_providers.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { + acctest.PreCheck(ctx, t) + acctest.PreCheckPartitionHasService(t, names.SSOAdminEndpointID) + acctest.PreCheckSSOAdminInstances(ctx, t) + }, + ErrorCheck: acctest.ErrorCheck(t, names.SSOAdminEndpointID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: nil, + Steps: []resource.TestStep{ + { + Config: testAccApplicationProvidersDataSourceConfig_basic(), + Check: resource.ComposeTestCheckFunc( + resource.TestCheckResourceAttrSet(dataSourceName, "id"), + // Verify a known application provider is included in the output + resource.TestCheckTypeSetElemNestedAttrs(dataSourceName, "application_providers.*", map[string]string{ + "application_provider_arn": "arn:aws:sso::aws:applicationProvider/custom", //lintignore:AWSAT005 + }), + ), + }, + }, + }) +} + +func testAccApplicationProvidersDataSourceConfig_basic() string { + return ` +data "aws_ssoadmin_application_providers" "test" {} +` +} diff --git a/internal/service/ssoadmin/service_package_gen.go b/internal/service/ssoadmin/service_package_gen.go index baec9f3d2fb..a8052cd2697 100644 --- a/internal/service/ssoadmin/service_package_gen.go +++ b/internal/service/ssoadmin/service_package_gen.go @@ -13,7 +13,12 @@ import ( type servicePackage struct{} func (p *servicePackage) FrameworkDataSources(ctx context.Context) []*types.ServicePackageFrameworkDataSource { - return []*types.ServicePackageFrameworkDataSource{} + return []*types.ServicePackageFrameworkDataSource{ + { + Factory: newDataSourceApplicationProviders, + Name: "Application Providers", + }, + } } func (p *servicePackage) FrameworkResources(ctx context.Context) []*types.ServicePackageFrameworkResource { diff --git a/website/docs/d/ssoadmin_application_providers.html.markdown b/website/docs/d/ssoadmin_application_providers.html.markdown new file mode 100644 index 00000000000..6521a020453 --- /dev/null +++ b/website/docs/d/ssoadmin_application_providers.html.markdown @@ -0,0 +1,42 @@ +--- +subcategory: "SSO Admin" +layout: "aws" +page_title: "AWS: aws_ssoadmin_application_providers" +description: |- + Terraform data source for managing AWS SSO Admin Application Providers. +--- + +# Data Source: aws_ssoadmin_application_providers + +Terraform data source for managing AWS SSO Admin Application Providers. + +## Example Usage + +### Basic Usage + +```terraform +data "aws_ssoadmin_application_providers" "example" {} +``` + +## Argument Reference + +There are no arguments available for this data source. + +## Attribute Reference + +This data source exports the following attributes in addition to the arguments above: + +* `id` - AWS region. +* `application_providers` - A list of application providers available in the current region. See [`application_providers`](#application_providers-attribute-reference) below. + +### `application_providers` Attribute Reference + +* `application_provider_arn` - ARN of the application provider. +* `display_data` - An object describing how IAM Identity Center represents the application provider in the portal. See [`display_data`](#display_data-attribute-reference) below. +* `federation_protocol` - Protocol that the application provider uses to perform federation. Valid values are `SAML` and `OAUTH`. + +### `display_data` Attribute Reference + +* `description` - Description of the application provider. +* `display_name` - Name of the application provider. +* `icon_url` - URL that points to an icon that represents the application provider.