From 37fd526256a33e68c7bee01e308ae46bdecaa3dc Mon Sep 17 00:00:00 2001 From: Stephen Monaghan Date: Wed, 27 Aug 2025 17:44:22 -0400 Subject: [PATCH 01/65] Adding support for OpenSearch Managed Clusters --- CHANGELOG.md | 1 + .../service/bedrockagent/knowledge_base.go | 95 ++++++++- .../bedrockagent/knowledge_base_test.go | 201 ++++++++++++++++++ .../bedrockagent_knowledge_base.html.markdown | 17 +- .../bedrockagent_knowledge_base.html.markdown | 17 +- .../bedrockagent_knowledge_base.html.markdown | 45 +++- 6 files changed, 365 insertions(+), 11 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 730ab56286e1..79390e0969ff 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,6 +16,7 @@ FEATURES: ENHANCEMENTS: +* resource/aws_bedrockagent_knowledge_base: Add support for OpenSearch managed clusters in `storage_configuration` ([#42588](https://github.com/hashicorp/terraform-provider-aws/issues/42588)) * data-source/aws_network_interface: Add `attachment.network_card_index` attribute ([#42188](https://github.com/hashicorp/terraform-provider-aws/issues/42188)) * data-source/aws_sesv2_email_identity: Add `verification_status` attribute ([#44045](https://github.com/hashicorp/terraform-provider-aws/issues/44045)) * data-source/aws_signer_signing_profile: Add `signing_material` and `signing_parameters` attributes ([#43921](https://github.com/hashicorp/terraform-provider-aws/issues/43921)) diff --git a/internal/service/bedrockagent/knowledge_base.go b/internal/service/bedrockagent/knowledge_base.go index 8aeb2a7565f9..cd4f7337a967 100644 --- a/internal/service/bedrockagent/knowledge_base.go +++ b/internal/service/bedrockagent/knowledge_base.go @@ -431,6 +431,77 @@ func (r *knowledgeBaseResource) Schema(ctx context.Context, request resource.Sch }, }, }, + "opensearch_managed_cluster_configuration": schema.ListNestedBlock{ + CustomType: fwtypes.NewListNestedObjectTypeOf[opensearchManagedClusterConfigurationModel](ctx), + Validators: []validator.List{ + listvalidator.SizeAtMost(1), + }, + PlanModifiers: []planmodifier.List{ + listplanmodifier.RequiresReplace(), + }, + NestedObject: schema.NestedBlockObject{ + Attributes: map[string]schema.Attribute{ + "domain_arn": schema.StringAttribute{ + CustomType: fwtypes.ARNType, + Required: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.RequiresReplace(), + }, + }, + "domain_endpoint": schema.StringAttribute{ + Required: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.RequiresReplace(), + }, + Validators: []validator.String{ + stringvalidator.RegexMatches( + regexache.MustCompile(`^https://.*$`), + "must be a valid HTTPS URL", + ), + }, + }, + "vector_index_name": schema.StringAttribute{ + Required: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.RequiresReplace(), + }, + }, + }, + Blocks: map[string]schema.Block{ + "field_mapping": schema.ListNestedBlock{ + CustomType: fwtypes.NewListNestedObjectTypeOf[opensearchManagedClusterFieldMappingModel](ctx), + Validators: []validator.List{ + listvalidator.SizeAtMost(1), + }, + PlanModifiers: []planmodifier.List{ + listplanmodifier.RequiresReplace(), + }, + NestedObject: schema.NestedBlockObject{ + Attributes: map[string]schema.Attribute{ + "metadata_field": schema.StringAttribute{ + Required: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.RequiresReplace(), + }, + }, + "text_field": schema.StringAttribute{ + Required: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.RequiresReplace(), + }, + }, + "vector_field": schema.StringAttribute{ + Required: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.RequiresReplace(), + }, + }, + }, + }, + }, + }, + }, + }, "opensearch_serverless_configuration": schema.ListNestedBlock{ CustomType: fwtypes.NewListNestedObjectTypeOf[opensearchServerlessConfigurationModel](ctx), Validators: []validator.List{ @@ -834,11 +905,12 @@ type storageLocationModel struct { } type storageConfigurationModel struct { - OpensearchServerlessConfiguration fwtypes.ListNestedObjectValueOf[opensearchServerlessConfigurationModel] `tfsdk:"opensearch_serverless_configuration"` - PineconeConfiguration fwtypes.ListNestedObjectValueOf[pineconeConfigurationModel] `tfsdk:"pinecone_configuration"` - RDSConfiguration fwtypes.ListNestedObjectValueOf[rdsConfigurationModel] `tfsdk:"rds_configuration"` - RedisEnterpriseCloudConfiguration fwtypes.ListNestedObjectValueOf[redisEnterpriseCloudConfigurationModel] `tfsdk:"redis_enterprise_cloud_configuration"` - Type types.String `tfsdk:"type"` + OpensearchManagedClusterConfiguration fwtypes.ListNestedObjectValueOf[opensearchManagedClusterConfigurationModel] `tfsdk:"opensearch_managed_cluster_configuration"` + OpensearchServerlessConfiguration fwtypes.ListNestedObjectValueOf[opensearchServerlessConfigurationModel] `tfsdk:"opensearch_serverless_configuration"` + PineconeConfiguration fwtypes.ListNestedObjectValueOf[pineconeConfigurationModel] `tfsdk:"pinecone_configuration"` + RDSConfiguration fwtypes.ListNestedObjectValueOf[rdsConfigurationModel] `tfsdk:"rds_configuration"` + RedisEnterpriseCloudConfiguration fwtypes.ListNestedObjectValueOf[redisEnterpriseCloudConfigurationModel] `tfsdk:"redis_enterprise_cloud_configuration"` + Type types.String `tfsdk:"type"` } type opensearchServerlessConfigurationModel struct { @@ -853,6 +925,19 @@ type opensearchServerlessFieldMappingModel struct { VectorField types.String `tfsdk:"vector_field"` } +type opensearchManagedClusterConfigurationModel struct { + DomainARN fwtypes.ARN `tfsdk:"domain_arn"` + DomainEndpoint types.String `tfsdk:"domain_endpoint"` + FieldMapping fwtypes.ListNestedObjectValueOf[opensearchManagedClusterFieldMappingModel] `tfsdk:"field_mapping"` + VectorIndexName types.String `tfsdk:"vector_index_name"` +} + +type opensearchManagedClusterFieldMappingModel struct { + MetadataField types.String `tfsdk:"metadata_field"` + TextField types.String `tfsdk:"text_field"` + VectorField types.String `tfsdk:"vector_field"` +} + type pineconeConfigurationModel struct { ConnectionString types.String `tfsdk:"connection_string"` CredentialsSecretARN fwtypes.ARN `tfsdk:"credentials_secret_arn"` diff --git a/internal/service/bedrockagent/knowledge_base_test.go b/internal/service/bedrockagent/knowledge_base_test.go index eb19ecfc5a69..e822dd2a546a 100644 --- a/internal/service/bedrockagent/knowledge_base_test.go +++ b/internal/service/bedrockagent/knowledge_base_test.go @@ -486,6 +486,22 @@ func skipIfOSSCollectionNameEnvVarNotSet(t *testing.T) string { return v } +// skipIfOSDomainEnvVarNotSet handles skipping tests when an environment +// variable providing a valid OpenSearch domain name is unset +// +// This should be called in all acceptance tests currently dependent on an OpenSearch +// Managed Cluster domain. +func skipIfOSDomainEnvVarNotSet(t *testing.T) string { + t.Helper() + + v := os.Getenv("TF_AWS_BEDROCK_OS_DOMAIN_NAME") + if v == "" { + acctest.Skip(t, "This test requires external configuration of an OpenSearch domain. "+ + "Set the TF_AWS_BEDROCK_OS_DOMAIN_NAME environment variable to the OpenSearch domain name.") + } + return v +} + func testAccKnowledgeBaseConfig_basicRDS(rName, model, description string) string { if description == "" { description = "null" @@ -940,3 +956,188 @@ resource "aws_bedrockagent_knowledge_base" "test" { } `, rName, model)) } + +func testAccKnowledgeBase_OpenSearchManagedCluster_basic(t *testing.T) { + ctx := acctest.Context(t) + domain := skipIfOSDomainEnvVarNotSet(t) + + var knowledgebase types.KnowledgeBase + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + resourceName := "aws_bedrockagent_knowledge_base.test" + foundationModel := "amazon.titan-embed-text-v2:0" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { + acctest.PreCheck(ctx, t) + }, + ErrorCheck: acctest.ErrorCheck(t, names.BedrockAgentServiceID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckKnowledgeBaseDestroy(ctx), + Steps: []resource.TestStep{ + { + Config: testAccKnowledgeBaseConfig_OpenSearchManagedCluster_basic(rName, domain, foundationModel), + Check: resource.ComposeTestCheckFunc( + testAccCheckKnowledgeBaseExists(ctx, resourceName, &knowledgebase), + resource.TestCheckResourceAttr(resourceName, names.AttrName, rName), + resource.TestCheckResourceAttrPair(resourceName, names.AttrRoleARN, "aws_iam_role.test", names.AttrARN), + resource.TestCheckResourceAttr(resourceName, "knowledge_base_configuration.#", "1"), + resource.TestCheckResourceAttr(resourceName, "knowledge_base_configuration.0.vector_knowledge_base_configuration.#", "1"), + resource.TestCheckResourceAttr(resourceName, "knowledge_base_configuration.0.type", "VECTOR"), + resource.TestCheckResourceAttr(resourceName, "storage_configuration.#", "1"), + resource.TestCheckResourceAttr(resourceName, "storage_configuration.0.type", "OPENSEARCH_MANAGED_CLUSTER"), + resource.TestCheckResourceAttr(resourceName, "storage_configuration.0.opensearch_managed_cluster_configuration.#", "1"), + resource.TestCheckResourceAttr(resourceName, "storage_configuration.0.opensearch_managed_cluster_configuration.0.vector_index_name", "bedrock-knowledge-base-default-index"), + resource.TestCheckResourceAttr(resourceName, "storage_configuration.0.opensearch_managed_cluster_configuration.0.field_mapping.#", "1"), + resource.TestCheckResourceAttr(resourceName, "storage_configuration.0.opensearch_managed_cluster_configuration.0.field_mapping.0.vector_field", "bedrock-knowledge-base-default-vector"), + resource.TestCheckResourceAttr(resourceName, "storage_configuration.0.opensearch_managed_cluster_configuration.0.field_mapping.0.text_field", "text_chunk"), + resource.TestCheckResourceAttr(resourceName, "storage_configuration.0.opensearch_managed_cluster_configuration.0.field_mapping.0.metadata_field", "metadata"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func testAccKnowledgeBaseConfigBase_openSearchManagedCluster(rName, domainName, model string) string { + return fmt.Sprintf(` +data "aws_caller_identity" "current" {} +data "aws_region" "current" {} +data "aws_partition" "current" {} + +data "aws_opensearch_domain" "test" { + domain_name = %[2]q +} + +# See the Amazon Bedrock documentation for creating a service role: +# https://docs.aws.amazon.com/bedrock/latest/userguide/kb-permissions.html +data "aws_iam_policy_document" "test_trust" { + statement { + effect = "Allow" + actions = [ + "sts:AssumeRole", + ] + principals { + type = "Service" + identifiers = ["bedrock.amazonaws.com"] + } + condition { + test = "StringEquals" + variable = "aws:SourceAccount" + values = [ + data.aws_caller_identity.current.account_id, + ] + } + condition { + test = "ArnLike" + variable = "aws:SourceArn" + values = [ + "arn:${data.aws_partition.current.partition}:bedrock:${data.aws_region.current.region}:${data.aws_caller_identity.current.account_id}:knowledge-base/*" + ] + } + } +} + +data "aws_iam_policy_document" "test" { + statement { + effect = "Allow" + actions = [ + "bedrock:ListFoundationModels", + "bedrock:ListCustomModels", + ] + resources = [ + "*", + ] + } + + statement { + effect = "Allow" + actions = [ + "bedrock:InvokeModel", + ] + resources = [ + "arn:${data.aws_partition.current.partition}:bedrock:${data.aws_region.current.region}:${data.aws_caller_identity.current.account_id}:foundation-model/%[3]s", + ] + } + + statement { + effect = "Allow" + actions = [ + "bedrock:RetreiveAndGenerate", + ] + resources = [ + "*", + ] + } + + statement { + effect = "Allow" + actions = [ + "es:ESHttpDelete", + "es:ESHttpGet", + "es:ESHttpHead", + "es:ESHttpPost", + "es:ESHttpPut", + ] + resources = [ + data.aws_opensearch_domain.test.arn, + "${data.aws_opensearch_domain.test.arn}/*", + ] + } +} + +resource "aws_iam_role" "test" { + name = %[1]q + assume_role_policy = data.aws_iam_policy_document.test_trust.json +} + +resource "aws_iam_policy" "test" { + name = %[1]q + policy = data.aws_iam_policy_document.test.json +} + +resource "aws_iam_role_policy_attachment" "test" { + role = aws_iam_role.test.name + policy_arn = aws_iam_policy.test.arn +} +`, rName, domainName, model) +} + +func testAccKnowledgeBaseConfig_OpenSearchManagedCluster_basic(rName, domainName, model string) string { + return acctest.ConfigCompose( + testAccKnowledgeBaseConfigBase_openSearchManagedCluster(rName, domainName, model), + fmt.Sprintf(` +resource "aws_bedrockagent_knowledge_base" "test" { + depends_on = [ + aws_iam_role_policy_attachment.test, + ] + + name = %[1]q + role_arn = aws_iam_role.test.arn + + knowledge_base_configuration { + vector_knowledge_base_configuration { + embedding_model_arn = "arn:${data.aws_partition.current.partition}:bedrock:${data.aws_region.current.region}::foundation-model/%[2]s" + } + type = "VECTOR" + } + + storage_configuration { + type = "OPENSEARCH_MANAGED_CLUSTER" + opensearch_managed_cluster_configuration { + domain_arn = data.aws_opensearch_domain.test.arn + domain_endpoint = data.aws_opensearch_domain.test.endpoint + vector_index_name = "bedrock-knowledge-base-default-index" + field_mapping { + vector_field = "bedrock-knowledge-base-default-vector" + text_field = "text_chunk" + metadata_field = "metadata" + } + } + } +} +`, rName, model)) +} diff --git a/website/docs/cdktf/python/r/bedrockagent_knowledge_base.html.markdown b/website/docs/cdktf/python/r/bedrockagent_knowledge_base.html.markdown index 8ce28e694607..8471a413b44f 100644 --- a/website/docs/cdktf/python/r/bedrockagent_knowledge_base.html.markdown +++ b/website/docs/cdktf/python/r/bedrockagent_knowledge_base.html.markdown @@ -185,8 +185,9 @@ The `s3_location` configuration block supports the following arguments: The `storage_configuration` configuration block supports the following arguments: -* `type` - (Required) Vector store service in which the knowledge base is stored. Valid Values: `OPENSEARCH_SERVERLESS`, `PINECONE`, `REDIS_ENTERPRISE_CLOUD`, `RDS`. -* `opensearch_serverless_configuration` - (Optional) The storage configuration of the knowledge base in Amazon OpenSearch Service. See [`opensearch_serverless_configuration` block](#opensearch_serverless_configuration-block) for details. +* `type` - (Required) Vector store service in which the knowledge base is stored. Valid Values: `OPENSEARCH_SERVERLESS`, `OPENSEARCH_MANAGED_CLUSTER`, `PINECONE`, `REDIS_ENTERPRISE_CLOUD`, `RDS`. +* `opensearch_serverless_configuration` - (Optional) The storage configuration of the knowledge base in Amazon OpenSearch Service Serverless. See [`opensearch_serverless_configuration` block](#opensearch_serverless_configuration-block) for details. +* `opensearch_managed_cluster_configuration` - (Optional) The storage configuration of the knowledge base in Amazon OpenSearch Service Managed Cluster. See [`opensearch_managed_cluster_configuration` block](#opensearch_managed_cluster_configuration-block) for details. * `pinecone_configuration` - (Optional) The storage configuration of the knowledge base in Pinecone. See [`pinecone_configuration` block](#pinecone_configuration-block) for details. * `rds_configuration` - (Optional) Details about the storage configuration of the knowledge base in Amazon RDS. For more information, see [Create a vector index in Amazon RDS](https://docs.aws.amazon.com/bedrock/latest/userguide/knowledge-base-setup.html). See [`rds_configuration` block](#rds_configuration-block) for details. * `redis_enterprise_cloud_configuration` - (Optional) The storage configuration of the knowledge base in Redis Enterprise Cloud. See [`redis_enterprise_cloud_configuration` block](#redis_enterprise_cloud_configuration-block) for details. @@ -202,6 +203,18 @@ The `opensearch_serverless_configuration` configuration block supports the follo * `vector_field` - (Required) Name of the field in which Amazon Bedrock stores the vector embeddings for your data sources. * `vector_index_name` - (Required) Name of the vector store. +### `opensearch_managed_cluster_configuration` block + +The `opensearch_managed_cluster_configuration` configuration block supports the following arguments: + +* `domain_arn` - (Required) ARN of the OpenSearch domain. +* `domain_endpoint` - (Required) Endpoint URL of the OpenSearch domain. +* `field_mapping` - (Required) The names of the fields to which to map information about the vector store. This block supports the following arguments: + * `metadata_field` - (Required) Name of the field in which Amazon Bedrock stores metadata about the vector store. + * `text_field` - (Required) Name of the field in which Amazon Bedrock stores the raw text from your data. The text is split according to the chunking strategy you choose. + * `vector_field` - (Required) Name of the field in which Amazon Bedrock stores the vector embeddings for your data sources. +* `vector_index_name` - (Required) Name of the vector store. + ### `pinecone_configuration` block The `pinecone_configuration` configuration block supports the following arguments: diff --git a/website/docs/cdktf/typescript/r/bedrockagent_knowledge_base.html.markdown b/website/docs/cdktf/typescript/r/bedrockagent_knowledge_base.html.markdown index 6b687c69aae4..14f47e6d1440 100644 --- a/website/docs/cdktf/typescript/r/bedrockagent_knowledge_base.html.markdown +++ b/website/docs/cdktf/typescript/r/bedrockagent_knowledge_base.html.markdown @@ -210,8 +210,9 @@ The `s3Location` configuration block supports the following arguments: The `storageConfiguration` configuration block supports the following arguments: -* `type` - (Required) Vector store service in which the knowledge base is stored. Valid Values: `OPENSEARCH_SERVERLESS`, `PINECONE`, `REDIS_ENTERPRISE_CLOUD`, `RDS`. -* `opensearchServerlessConfiguration` - (Optional) The storage configuration of the knowledge base in Amazon OpenSearch Service. See [`opensearchServerlessConfiguration` block](#opensearch_serverless_configuration-block) for details. +* `type` - (Required) Vector store service in which the knowledge base is stored. Valid Values: `OPENSEARCH_SERVERLESS`, `OPENSEARCH_MANAGED_CLUSTER`, `PINECONE`, `REDIS_ENTERPRISE_CLOUD`, `RDS`. +* `opensearchServerlessConfiguration` - (Optional) The storage configuration of the knowledge base in Amazon OpenSearch Service Serverless. See [`opensearchServerlessConfiguration` block](#opensearch_serverless_configuration-block) for details. +* `opensearchManagedClusterConfiguration` - (Optional) The storage configuration of the knowledge base in Amazon OpenSearch Service Managed Cluster. See [`opensearchManagedClusterConfiguration` block](#opensearch_managed_cluster_configuration-block) for details. * `pineconeConfiguration` - (Optional) The storage configuration of the knowledge base in Pinecone. See [`pineconeConfiguration` block](#pinecone_configuration-block) for details. * `rdsConfiguration` - (Optional) Details about the storage configuration of the knowledge base in Amazon RDS. For more information, see [Create a vector index in Amazon RDS](https://docs.aws.amazon.com/bedrock/latest/userguide/knowledge-base-setup.html). See [`rdsConfiguration` block](#rds_configuration-block) for details. * `redisEnterpriseCloudConfiguration` - (Optional) The storage configuration of the knowledge base in Redis Enterprise Cloud. See [`redisEnterpriseCloudConfiguration` block](#redis_enterprise_cloud_configuration-block) for details. @@ -227,6 +228,18 @@ The `opensearchServerlessConfiguration` configuration block supports the followi * `vectorField` - (Required) Name of the field in which Amazon Bedrock stores the vector embeddings for your data sources. * `vectorIndexName` - (Required) Name of the vector store. +### `opensearchManagedClusterConfiguration` block + +The `opensearchManagedClusterConfiguration` configuration block supports the following arguments: + +* `domainArn` - (Required) ARN of the OpenSearch domain. +* `domainEndpoint` - (Required) Endpoint URL of the OpenSearch domain. +* `fieldMapping` - (Required) The names of the fields to which to map information about the vector store. This block supports the following arguments: + * `metadataField` - (Required) Name of the field in which Amazon Bedrock stores metadata about the vector store. + * `textField` - (Required) Name of the field in which Amazon Bedrock stores the raw text from your data. The text is split according to the chunking strategy you choose. + * `vectorField` - (Required) Name of the field in which Amazon Bedrock stores the vector embeddings for your data sources. +* `vectorIndexName` - (Required) Name of the vector store. + ### `pineconeConfiguration` block The `pineconeConfiguration` configuration block supports the following arguments: diff --git a/website/docs/r/bedrockagent_knowledge_base.html.markdown b/website/docs/r/bedrockagent_knowledge_base.html.markdown index 29125c6e87f8..9efb4cafb351 100644 --- a/website/docs/r/bedrockagent_knowledge_base.html.markdown +++ b/website/docs/r/bedrockagent_knowledge_base.html.markdown @@ -39,6 +39,34 @@ resource "aws_bedrockagent_knowledge_base" "example" { } ``` +### OpenSearch Managed Cluster Configuration + +```terraform +resource "aws_bedrockagent_knowledge_base" "example" { + name = "example" + role_arn = aws_iam_role.example.arn + knowledge_base_configuration { + vector_knowledge_base_configuration { + embedding_model_arn = "arn:aws:bedrock:us-west-2::foundation-model/amazon.titan-embed-text-v2:0" + } + type = "VECTOR" + } + storage_configuration { + type = "OPENSEARCH_MANAGED_CLUSTER" + opensearch_managed_cluster_configuration { + domain_arn = "arn:aws:es:us-west-2:123456789012:domain/example-domain" + domain_endpoint = "https://search-example-domain.us-west-2.es.amazonaws.com" + vector_index_name = "example_index" + field_mapping { + metadata_field = "metadata" + text_field = "chunks" + vector_field = "embedding" + } + } + } +} +``` + ### With Supplemental Data Storage Configuration ```terraform @@ -149,8 +177,9 @@ The `s3_location` configuration block supports the following arguments: The `storage_configuration` configuration block supports the following arguments: -* `type` - (Required) Vector store service in which the knowledge base is stored. Valid Values: `OPENSEARCH_SERVERLESS`, `PINECONE`, `REDIS_ENTERPRISE_CLOUD`, `RDS`. -* `opensearch_serverless_configuration` - (Optional) The storage configuration of the knowledge base in Amazon OpenSearch Service. See [`opensearch_serverless_configuration` block](#opensearch_serverless_configuration-block) for details. +* `type` - (Required) Vector store service in which the knowledge base is stored. Valid Values: `OPENSEARCH_SERVERLESS`, `OPENSEARCH_MANAGED_CLUSTER`, `PINECONE`, `REDIS_ENTERPRISE_CLOUD`, `RDS`. +* `opensearch_serverless_configuration` - (Optional) The storage configuration of the knowledge base in Amazon OpenSearch Service Serverless. See [`opensearch_serverless_configuration` block](#opensearch_serverless_configuration-block) for details. +* `opensearch_managed_cluster_configuration` - (Optional) The storage configuration of the knowledge base in Amazon OpenSearch Service Managed Cluster. See [`opensearch_managed_cluster_configuration` block](#opensearch_managed_cluster_configuration-block) for details. * `pinecone_configuration` - (Optional) The storage configuration of the knowledge base in Pinecone. See [`pinecone_configuration` block](#pinecone_configuration-block) for details. * `rds_configuration` - (Optional) Details about the storage configuration of the knowledge base in Amazon RDS. For more information, see [Create a vector index in Amazon RDS](https://docs.aws.amazon.com/bedrock/latest/userguide/knowledge-base-setup.html). See [`rds_configuration` block](#rds_configuration-block) for details. * `redis_enterprise_cloud_configuration` - (Optional) The storage configuration of the knowledge base in Redis Enterprise Cloud. See [`redis_enterprise_cloud_configuration` block](#redis_enterprise_cloud_configuration-block) for details. @@ -166,6 +195,18 @@ The `opensearch_serverless_configuration` configuration block supports the follo * `vector_field` - (Required) Name of the field in which Amazon Bedrock stores the vector embeddings for your data sources. * `vector_index_name` - (Required) Name of the vector store. +### `opensearch_managed_cluster_configuration` block + +The `opensearch_managed_cluster_configuration` configuration block supports the following arguments: + +* `domain_arn` - (Required) ARN of the OpenSearch domain. +* `domain_endpoint` - (Required) Endpoint URL of the OpenSearch domain. +* `field_mapping` - (Required) The names of the fields to which to map information about the vector store. This block supports the following arguments: + * `metadata_field` - (Required) Name of the field in which Amazon Bedrock stores metadata about the vector store. + * `text_field` - (Required) Name of the field in which Amazon Bedrock stores the raw text from your data. The text is split according to the chunking strategy you choose. + * `vector_field` - (Required) Name of the field in which Amazon Bedrock stores the vector embeddings for your data sources. +* `vector_index_name` - (Required) Name of the vector store. + ### `pinecone_configuration` block The `pinecone_configuration` configuration block supports the following arguments: From ad79c9a20f9bedae07ccdd4c392d5481a84ac2bf Mon Sep 17 00:00:00 2001 From: Stephen Monaghan Date: Wed, 27 Aug 2025 23:33:58 -0400 Subject: [PATCH 02/65] Fixing acceptance test --- .../bedrockagent/knowledge_base_test.go | 223 ++++++------------ 1 file changed, 67 insertions(+), 156 deletions(-) diff --git a/internal/service/bedrockagent/knowledge_base_test.go b/internal/service/bedrockagent/knowledge_base_test.go index e822dd2a546a..543283bdd9ad 100644 --- a/internal/service/bedrockagent/knowledge_base_test.go +++ b/internal/service/bedrockagent/knowledge_base_test.go @@ -449,6 +449,51 @@ func testAccCheckKnowledgeBaseExists(ctx context.Context, n string, v *types.Kno } } +func TestAccKnowledgeBase_OpenSearchManagedCluster_basic(t *testing.T) { + ctx := acctest.Context(t) + domain := skipIfOSDomainEnvVarNotSet(t) + bedrockIAMRoleName := skipIfIAMRoleVarNotSet(t) + + var knowledgebase types.KnowledgeBase + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + resourceName := "aws_bedrockagent_knowledge_base.test" + foundationModel := "amazon.titan-embed-text-v2:0" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { + acctest.PreCheck(ctx, t) + }, + ErrorCheck: acctest.ErrorCheck(t, names.BedrockAgentServiceID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckKnowledgeBaseDestroy(ctx), + Steps: []resource.TestStep{ + { + Config: testAccKnowledgeBaseConfig_OpenSearchManagedCluster_basic(rName, domain, bedrockIAMRoleName, foundationModel), + Check: resource.ComposeTestCheckFunc( + testAccCheckKnowledgeBaseExists(ctx, resourceName, &knowledgebase), + resource.TestCheckResourceAttr(resourceName, names.AttrName, rName), + resource.TestCheckResourceAttr(resourceName, "knowledge_base_configuration.#", "1"), + resource.TestCheckResourceAttr(resourceName, "knowledge_base_configuration.0.vector_knowledge_base_configuration.#", "1"), + resource.TestCheckResourceAttr(resourceName, "knowledge_base_configuration.0.type", "VECTOR"), + resource.TestCheckResourceAttr(resourceName, "storage_configuration.#", "1"), + resource.TestCheckResourceAttr(resourceName, "storage_configuration.0.type", "OPENSEARCH_MANAGED_CLUSTER"), + resource.TestCheckResourceAttr(resourceName, "storage_configuration.0.opensearch_managed_cluster_configuration.#", "1"), + resource.TestCheckResourceAttr(resourceName, "storage_configuration.0.opensearch_managed_cluster_configuration.0.vector_index_name", "knowledge-index"), + resource.TestCheckResourceAttr(resourceName, "storage_configuration.0.opensearch_managed_cluster_configuration.0.field_mapping.#", "1"), + resource.TestCheckResourceAttr(resourceName, "storage_configuration.0.opensearch_managed_cluster_configuration.0.field_mapping.0.vector_field", "vector_embedding"), + resource.TestCheckResourceAttr(resourceName, "storage_configuration.0.opensearch_managed_cluster_configuration.0.field_mapping.0.text_field", "text"), + resource.TestCheckResourceAttr(resourceName, "storage_configuration.0.opensearch_managed_cluster_configuration.0.field_mapping.0.metadata_field", "metadata"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + // skipIfOSSCollectionNameEnvVarNotSet handles skipping tests when an environment // variable providing a valid OSS collection name is unset // @@ -502,6 +547,18 @@ func skipIfOSDomainEnvVarNotSet(t *testing.T) string { return v } +func skipIfIAMRoleVarNotSet(t *testing.T) string { + t.Helper() + + v := os.Getenv("TF_AWS_BEDROCK_IAM_ROLE_ARN") + if v == "" { + acctest.Skip(t, "This test requires external configuration of an IAM Role with permissions on the OpenSearch Cluster."+ + "It must be able to be assumed by the Amazon Bedrock service"+ + "Set the TF_AWS_BEDROCK_IAM_ROLE_ARN environment variable to the IAM Role's ARN.") + } + return v +} + func testAccKnowledgeBaseConfig_basicRDS(rName, model, description string) string { if description == "" { description = "null" @@ -957,166 +1014,20 @@ resource "aws_bedrockagent_knowledge_base" "test" { `, rName, model)) } -func testAccKnowledgeBase_OpenSearchManagedCluster_basic(t *testing.T) { - ctx := acctest.Context(t) - domain := skipIfOSDomainEnvVarNotSet(t) - - var knowledgebase types.KnowledgeBase - rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) - resourceName := "aws_bedrockagent_knowledge_base.test" - foundationModel := "amazon.titan-embed-text-v2:0" - - resource.Test(t, resource.TestCase{ - PreCheck: func() { - acctest.PreCheck(ctx, t) - }, - ErrorCheck: acctest.ErrorCheck(t, names.BedrockAgentServiceID), - ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, - CheckDestroy: testAccCheckKnowledgeBaseDestroy(ctx), - Steps: []resource.TestStep{ - { - Config: testAccKnowledgeBaseConfig_OpenSearchManagedCluster_basic(rName, domain, foundationModel), - Check: resource.ComposeTestCheckFunc( - testAccCheckKnowledgeBaseExists(ctx, resourceName, &knowledgebase), - resource.TestCheckResourceAttr(resourceName, names.AttrName, rName), - resource.TestCheckResourceAttrPair(resourceName, names.AttrRoleARN, "aws_iam_role.test", names.AttrARN), - resource.TestCheckResourceAttr(resourceName, "knowledge_base_configuration.#", "1"), - resource.TestCheckResourceAttr(resourceName, "knowledge_base_configuration.0.vector_knowledge_base_configuration.#", "1"), - resource.TestCheckResourceAttr(resourceName, "knowledge_base_configuration.0.type", "VECTOR"), - resource.TestCheckResourceAttr(resourceName, "storage_configuration.#", "1"), - resource.TestCheckResourceAttr(resourceName, "storage_configuration.0.type", "OPENSEARCH_MANAGED_CLUSTER"), - resource.TestCheckResourceAttr(resourceName, "storage_configuration.0.opensearch_managed_cluster_configuration.#", "1"), - resource.TestCheckResourceAttr(resourceName, "storage_configuration.0.opensearch_managed_cluster_configuration.0.vector_index_name", "bedrock-knowledge-base-default-index"), - resource.TestCheckResourceAttr(resourceName, "storage_configuration.0.opensearch_managed_cluster_configuration.0.field_mapping.#", "1"), - resource.TestCheckResourceAttr(resourceName, "storage_configuration.0.opensearch_managed_cluster_configuration.0.field_mapping.0.vector_field", "bedrock-knowledge-base-default-vector"), - resource.TestCheckResourceAttr(resourceName, "storage_configuration.0.opensearch_managed_cluster_configuration.0.field_mapping.0.text_field", "text_chunk"), - resource.TestCheckResourceAttr(resourceName, "storage_configuration.0.opensearch_managed_cluster_configuration.0.field_mapping.0.metadata_field", "metadata"), - ), - }, - { - ResourceName: resourceName, - ImportState: true, - ImportStateVerify: true, - }, - }, - }) -} - -func testAccKnowledgeBaseConfigBase_openSearchManagedCluster(rName, domainName, model string) string { - return fmt.Sprintf(` +func testAccKnowledgeBaseConfig_OpenSearchManagedCluster_basic(rName, domainName, bedrockRole, model string) string { + return acctest.ConfigCompose( + fmt.Sprintf(` data "aws_caller_identity" "current" {} data "aws_region" "current" {} data "aws_partition" "current" {} data "aws_opensearch_domain" "test" { - domain_name = %[2]q + domain_name = %[4]q } -# See the Amazon Bedrock documentation for creating a service role: -# https://docs.aws.amazon.com/bedrock/latest/userguide/kb-permissions.html -data "aws_iam_policy_document" "test_trust" { - statement { - effect = "Allow" - actions = [ - "sts:AssumeRole", - ] - principals { - type = "Service" - identifiers = ["bedrock.amazonaws.com"] - } - condition { - test = "StringEquals" - variable = "aws:SourceAccount" - values = [ - data.aws_caller_identity.current.account_id, - ] - } - condition { - test = "ArnLike" - variable = "aws:SourceArn" - values = [ - "arn:${data.aws_partition.current.partition}:bedrock:${data.aws_region.current.region}:${data.aws_caller_identity.current.account_id}:knowledge-base/*" - ] - } - } -} - -data "aws_iam_policy_document" "test" { - statement { - effect = "Allow" - actions = [ - "bedrock:ListFoundationModels", - "bedrock:ListCustomModels", - ] - resources = [ - "*", - ] - } - - statement { - effect = "Allow" - actions = [ - "bedrock:InvokeModel", - ] - resources = [ - "arn:${data.aws_partition.current.partition}:bedrock:${data.aws_region.current.region}:${data.aws_caller_identity.current.account_id}:foundation-model/%[3]s", - ] - } - - statement { - effect = "Allow" - actions = [ - "bedrock:RetreiveAndGenerate", - ] - resources = [ - "*", - ] - } - - statement { - effect = "Allow" - actions = [ - "es:ESHttpDelete", - "es:ESHttpGet", - "es:ESHttpHead", - "es:ESHttpPost", - "es:ESHttpPut", - ] - resources = [ - data.aws_opensearch_domain.test.arn, - "${data.aws_opensearch_domain.test.arn}/*", - ] - } -} - -resource "aws_iam_role" "test" { - name = %[1]q - assume_role_policy = data.aws_iam_policy_document.test_trust.json -} - -resource "aws_iam_policy" "test" { - name = %[1]q - policy = data.aws_iam_policy_document.test.json -} - -resource "aws_iam_role_policy_attachment" "test" { - role = aws_iam_role.test.name - policy_arn = aws_iam_policy.test.arn -} -`, rName, domainName, model) -} - -func testAccKnowledgeBaseConfig_OpenSearchManagedCluster_basic(rName, domainName, model string) string { - return acctest.ConfigCompose( - testAccKnowledgeBaseConfigBase_openSearchManagedCluster(rName, domainName, model), - fmt.Sprintf(` resource "aws_bedrockagent_knowledge_base" "test" { - depends_on = [ - aws_iam_role_policy_attachment.test, - ] - name = %[1]q - role_arn = aws_iam_role.test.arn + role_arn = %[3]q #aws_iam_role.test.arn knowledge_base_configuration { vector_knowledge_base_configuration { @@ -1129,15 +1040,15 @@ resource "aws_bedrockagent_knowledge_base" "test" { type = "OPENSEARCH_MANAGED_CLUSTER" opensearch_managed_cluster_configuration { domain_arn = data.aws_opensearch_domain.test.arn - domain_endpoint = data.aws_opensearch_domain.test.endpoint - vector_index_name = "bedrock-knowledge-base-default-index" + domain_endpoint = "https://${data.aws_opensearch_domain.test.endpoint}" + vector_index_name = "knowledge-index" field_mapping { - vector_field = "bedrock-knowledge-base-default-vector" - text_field = "text_chunk" + vector_field = "vector_embedding" + text_field = "text" metadata_field = "metadata" } } } } -`, rName, model)) +`, rName, model, bedrockRole, domainName)) } From 1ab2c900d445086e16ae46a5cc783fa93b2b3b58 Mon Sep 17 00:00:00 2001 From: Stephen Monaghan Date: Wed, 27 Aug 2025 23:38:28 -0400 Subject: [PATCH 03/65] Fixing documentation --- .../typescript/r/bedrockagent_knowledge_base.html.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/docs/cdktf/typescript/r/bedrockagent_knowledge_base.html.markdown b/website/docs/cdktf/typescript/r/bedrockagent_knowledge_base.html.markdown index 14f47e6d1440..c0a10d86b5e4 100644 --- a/website/docs/cdktf/typescript/r/bedrockagent_knowledge_base.html.markdown +++ b/website/docs/cdktf/typescript/r/bedrockagent_knowledge_base.html.markdown @@ -238,7 +238,7 @@ The `opensearchManagedClusterConfiguration` configuration block supports the fol * `metadataField` - (Required) Name of the field in which Amazon Bedrock stores metadata about the vector store. * `textField` - (Required) Name of the field in which Amazon Bedrock stores the raw text from your data. The text is split according to the chunking strategy you choose. * `vectorField` - (Required) Name of the field in which Amazon Bedrock stores the vector embeddings for your data sources. -* `vectorIndexName` - (Required) Name of the vector store. +* `vectorIndexName` - (Required) Name of the vector index. ### `pineconeConfiguration` block From 5bf230667efc10cebbd14518545feb1485b9486c Mon Sep 17 00:00:00 2001 From: Stephen Monaghan Date: Thu, 28 Aug 2025 09:22:10 -0400 Subject: [PATCH 04/65] Fixing CHANGELOG --- .changelog/44060.txt | 3 +++ CHANGELOG.md | 1 - 2 files changed, 3 insertions(+), 1 deletion(-) create mode 100644 .changelog/44060.txt diff --git a/.changelog/44060.txt b/.changelog/44060.txt new file mode 100644 index 000000000000..999abda73ccc --- /dev/null +++ b/.changelog/44060.txt @@ -0,0 +1,3 @@ +```release-note:enhancement +resource/aws_bedrockagent_knowledge_base: Add support for OpenSearch managed clusters in `storage_configuration` +``` diff --git a/CHANGELOG.md b/CHANGELOG.md index 79390e0969ff..730ab56286e1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -16,7 +16,6 @@ FEATURES: ENHANCEMENTS: -* resource/aws_bedrockagent_knowledge_base: Add support for OpenSearch managed clusters in `storage_configuration` ([#42588](https://github.com/hashicorp/terraform-provider-aws/issues/42588)) * data-source/aws_network_interface: Add `attachment.network_card_index` attribute ([#42188](https://github.com/hashicorp/terraform-provider-aws/issues/42188)) * data-source/aws_sesv2_email_identity: Add `verification_status` attribute ([#44045](https://github.com/hashicorp/terraform-provider-aws/issues/44045)) * data-source/aws_signer_signing_profile: Add `signing_material` and `signing_parameters` attributes ([#43921](https://github.com/hashicorp/terraform-provider-aws/issues/43921)) From 786b4b822b945405b8394c6f4f231f300cd7281a Mon Sep 17 00:00:00 2001 From: Stephen Monaghan Date: Thu, 28 Aug 2025 10:38:00 -0400 Subject: [PATCH 05/65] Fixing formatting --- internal/service/bedrockagent/knowledge_base_test.go | 4 ++-- website/docs/r/bedrockagent_knowledge_base.html.markdown | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/internal/service/bedrockagent/knowledge_base_test.go b/internal/service/bedrockagent/knowledge_base_test.go index 543283bdd9ad..24b82e27e7aa 100644 --- a/internal/service/bedrockagent/knowledge_base_test.go +++ b/internal/service/bedrockagent/knowledge_base_test.go @@ -449,7 +449,7 @@ func testAccCheckKnowledgeBaseExists(ctx context.Context, n string, v *types.Kno } } -func TestAccKnowledgeBase_OpenSearchManagedCluster_basic(t *testing.T) { +func TestAccBedrockAgentKnowledgeBase_OpenSearchManagedCluster_basic(t *testing.T) { ctx := acctest.Context(t) domain := skipIfOSDomainEnvVarNotSet(t) bedrockIAMRoleName := skipIfIAMRoleVarNotSet(t) @@ -1027,7 +1027,7 @@ data "aws_opensearch_domain" "test" { resource "aws_bedrockagent_knowledge_base" "test" { name = %[1]q - role_arn = %[3]q #aws_iam_role.test.arn + role_arn = %[3]q knowledge_base_configuration { vector_knowledge_base_configuration { diff --git a/website/docs/r/bedrockagent_knowledge_base.html.markdown b/website/docs/r/bedrockagent_knowledge_base.html.markdown index 9efb4cafb351..b40c45d20879 100644 --- a/website/docs/r/bedrockagent_knowledge_base.html.markdown +++ b/website/docs/r/bedrockagent_knowledge_base.html.markdown @@ -54,8 +54,8 @@ resource "aws_bedrockagent_knowledge_base" "example" { storage_configuration { type = "OPENSEARCH_MANAGED_CLUSTER" opensearch_managed_cluster_configuration { - domain_arn = "arn:aws:es:us-west-2:123456789012:domain/example-domain" - domain_endpoint = "https://search-example-domain.us-west-2.es.amazonaws.com" + domain_arn = "arn:aws:es:us-west-2:123456789012:domain/example-domain" + domain_endpoint = "https://search-example-domain.us-west-2.es.amazonaws.com" vector_index_name = "example_index" field_mapping { metadata_field = "metadata" From dbc03cd54521e8e39291929853e2d0ab30fd0d63 Mon Sep 17 00:00:00 2001 From: Stephen Monaghan Date: Thu, 28 Aug 2025 16:13:21 -0400 Subject: [PATCH 06/65] Fixing terrafmt issues in test --- internal/service/bedrockagent/knowledge_base_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/internal/service/bedrockagent/knowledge_base_test.go b/internal/service/bedrockagent/knowledge_base_test.go index 24b82e27e7aa..c188732cc969 100644 --- a/internal/service/bedrockagent/knowledge_base_test.go +++ b/internal/service/bedrockagent/knowledge_base_test.go @@ -1039,8 +1039,8 @@ resource "aws_bedrockagent_knowledge_base" "test" { storage_configuration { type = "OPENSEARCH_MANAGED_CLUSTER" opensearch_managed_cluster_configuration { - domain_arn = data.aws_opensearch_domain.test.arn - domain_endpoint = "https://${data.aws_opensearch_domain.test.endpoint}" + domain_arn = data.aws_opensearch_domain.test.arn + domain_endpoint = "https://${data.aws_opensearch_domain.test.endpoint}" vector_index_name = "knowledge-index" field_mapping { vector_field = "vector_embedding" From bee607290dd28f09bed0ed634850d01becf1c8cd Mon Sep 17 00:00:00 2001 From: Stephen Monaghan Date: Thu, 28 Aug 2025 17:23:31 -0400 Subject: [PATCH 07/65] Fixing documentation Removing unneeded changes in website/docs/cdktf --- .../r/bedrockagent_knowledge_base.html.markdown | 17 ++--------------- .../r/bedrockagent_knowledge_base.html.markdown | 17 ++--------------- 2 files changed, 4 insertions(+), 30 deletions(-) diff --git a/website/docs/cdktf/python/r/bedrockagent_knowledge_base.html.markdown b/website/docs/cdktf/python/r/bedrockagent_knowledge_base.html.markdown index 8471a413b44f..8ce28e694607 100644 --- a/website/docs/cdktf/python/r/bedrockagent_knowledge_base.html.markdown +++ b/website/docs/cdktf/python/r/bedrockagent_knowledge_base.html.markdown @@ -185,9 +185,8 @@ The `s3_location` configuration block supports the following arguments: The `storage_configuration` configuration block supports the following arguments: -* `type` - (Required) Vector store service in which the knowledge base is stored. Valid Values: `OPENSEARCH_SERVERLESS`, `OPENSEARCH_MANAGED_CLUSTER`, `PINECONE`, `REDIS_ENTERPRISE_CLOUD`, `RDS`. -* `opensearch_serverless_configuration` - (Optional) The storage configuration of the knowledge base in Amazon OpenSearch Service Serverless. See [`opensearch_serverless_configuration` block](#opensearch_serverless_configuration-block) for details. -* `opensearch_managed_cluster_configuration` - (Optional) The storage configuration of the knowledge base in Amazon OpenSearch Service Managed Cluster. See [`opensearch_managed_cluster_configuration` block](#opensearch_managed_cluster_configuration-block) for details. +* `type` - (Required) Vector store service in which the knowledge base is stored. Valid Values: `OPENSEARCH_SERVERLESS`, `PINECONE`, `REDIS_ENTERPRISE_CLOUD`, `RDS`. +* `opensearch_serverless_configuration` - (Optional) The storage configuration of the knowledge base in Amazon OpenSearch Service. See [`opensearch_serverless_configuration` block](#opensearch_serverless_configuration-block) for details. * `pinecone_configuration` - (Optional) The storage configuration of the knowledge base in Pinecone. See [`pinecone_configuration` block](#pinecone_configuration-block) for details. * `rds_configuration` - (Optional) Details about the storage configuration of the knowledge base in Amazon RDS. For more information, see [Create a vector index in Amazon RDS](https://docs.aws.amazon.com/bedrock/latest/userguide/knowledge-base-setup.html). See [`rds_configuration` block](#rds_configuration-block) for details. * `redis_enterprise_cloud_configuration` - (Optional) The storage configuration of the knowledge base in Redis Enterprise Cloud. See [`redis_enterprise_cloud_configuration` block](#redis_enterprise_cloud_configuration-block) for details. @@ -203,18 +202,6 @@ The `opensearch_serverless_configuration` configuration block supports the follo * `vector_field` - (Required) Name of the field in which Amazon Bedrock stores the vector embeddings for your data sources. * `vector_index_name` - (Required) Name of the vector store. -### `opensearch_managed_cluster_configuration` block - -The `opensearch_managed_cluster_configuration` configuration block supports the following arguments: - -* `domain_arn` - (Required) ARN of the OpenSearch domain. -* `domain_endpoint` - (Required) Endpoint URL of the OpenSearch domain. -* `field_mapping` - (Required) The names of the fields to which to map information about the vector store. This block supports the following arguments: - * `metadata_field` - (Required) Name of the field in which Amazon Bedrock stores metadata about the vector store. - * `text_field` - (Required) Name of the field in which Amazon Bedrock stores the raw text from your data. The text is split according to the chunking strategy you choose. - * `vector_field` - (Required) Name of the field in which Amazon Bedrock stores the vector embeddings for your data sources. -* `vector_index_name` - (Required) Name of the vector store. - ### `pinecone_configuration` block The `pinecone_configuration` configuration block supports the following arguments: diff --git a/website/docs/cdktf/typescript/r/bedrockagent_knowledge_base.html.markdown b/website/docs/cdktf/typescript/r/bedrockagent_knowledge_base.html.markdown index c0a10d86b5e4..6b687c69aae4 100644 --- a/website/docs/cdktf/typescript/r/bedrockagent_knowledge_base.html.markdown +++ b/website/docs/cdktf/typescript/r/bedrockagent_knowledge_base.html.markdown @@ -210,9 +210,8 @@ The `s3Location` configuration block supports the following arguments: The `storageConfiguration` configuration block supports the following arguments: -* `type` - (Required) Vector store service in which the knowledge base is stored. Valid Values: `OPENSEARCH_SERVERLESS`, `OPENSEARCH_MANAGED_CLUSTER`, `PINECONE`, `REDIS_ENTERPRISE_CLOUD`, `RDS`. -* `opensearchServerlessConfiguration` - (Optional) The storage configuration of the knowledge base in Amazon OpenSearch Service Serverless. See [`opensearchServerlessConfiguration` block](#opensearch_serverless_configuration-block) for details. -* `opensearchManagedClusterConfiguration` - (Optional) The storage configuration of the knowledge base in Amazon OpenSearch Service Managed Cluster. See [`opensearchManagedClusterConfiguration` block](#opensearch_managed_cluster_configuration-block) for details. +* `type` - (Required) Vector store service in which the knowledge base is stored. Valid Values: `OPENSEARCH_SERVERLESS`, `PINECONE`, `REDIS_ENTERPRISE_CLOUD`, `RDS`. +* `opensearchServerlessConfiguration` - (Optional) The storage configuration of the knowledge base in Amazon OpenSearch Service. See [`opensearchServerlessConfiguration` block](#opensearch_serverless_configuration-block) for details. * `pineconeConfiguration` - (Optional) The storage configuration of the knowledge base in Pinecone. See [`pineconeConfiguration` block](#pinecone_configuration-block) for details. * `rdsConfiguration` - (Optional) Details about the storage configuration of the knowledge base in Amazon RDS. For more information, see [Create a vector index in Amazon RDS](https://docs.aws.amazon.com/bedrock/latest/userguide/knowledge-base-setup.html). See [`rdsConfiguration` block](#rds_configuration-block) for details. * `redisEnterpriseCloudConfiguration` - (Optional) The storage configuration of the knowledge base in Redis Enterprise Cloud. See [`redisEnterpriseCloudConfiguration` block](#redis_enterprise_cloud_configuration-block) for details. @@ -228,18 +227,6 @@ The `opensearchServerlessConfiguration` configuration block supports the followi * `vectorField` - (Required) Name of the field in which Amazon Bedrock stores the vector embeddings for your data sources. * `vectorIndexName` - (Required) Name of the vector store. -### `opensearchManagedClusterConfiguration` block - -The `opensearchManagedClusterConfiguration` configuration block supports the following arguments: - -* `domainArn` - (Required) ARN of the OpenSearch domain. -* `domainEndpoint` - (Required) Endpoint URL of the OpenSearch domain. -* `fieldMapping` - (Required) The names of the fields to which to map information about the vector store. This block supports the following arguments: - * `metadataField` - (Required) Name of the field in which Amazon Bedrock stores metadata about the vector store. - * `textField` - (Required) Name of the field in which Amazon Bedrock stores the raw text from your data. The text is split according to the chunking strategy you choose. - * `vectorField` - (Required) Name of the field in which Amazon Bedrock stores the vector embeddings for your data sources. -* `vectorIndexName` - (Required) Name of the vector index. - ### `pineconeConfiguration` block The `pineconeConfiguration` configuration block supports the following arguments: From 920f60726afbe32202775932e749ce496bd954c1 Mon Sep 17 00:00:00 2001 From: Aya Kim Date: Sat, 20 Sep 2025 07:42:37 +0000 Subject: [PATCH 08/65] feat: Add Kendra support to aws_bedrockagent_knowledge_base Add kendra_knowledge_base_configuration block and acceptance test to support Kendra indexes as knowledge base backend. --- .../service/bedrockagent/bedrockagent_test.go | 1 + .../service/bedrockagent/knowledge_base.go | 29 ++++- .../bedrockagent/knowledge_base_test.go | 112 ++++++++++++++++++ 3 files changed, 138 insertions(+), 4 deletions(-) diff --git a/internal/service/bedrockagent/bedrockagent_test.go b/internal/service/bedrockagent/bedrockagent_test.go index ae39ed34b5c1..5581a9685a17 100644 --- a/internal/service/bedrockagent/bedrockagent_test.go +++ b/internal/service/bedrockagent/bedrockagent_test.go @@ -20,6 +20,7 @@ func TestAccBedrockAgent_serial(t *testing.T) { "OpenSearchBasic": testAccKnowledgeBase_OpenSearch_basic, "OpenSearchUpdate": testAccKnowledgeBase_OpenSearch_update, "OpenSearchSupplementalDataStorage": testAccKnowledgeBase_OpenSearch_supplementalDataStorage, + "KendraBasic": testAccKnowledgeBase_Kendra_basic, }, "DataSource": { acctest.CtBasic: testAccDataSource_basic, diff --git a/internal/service/bedrockagent/knowledge_base.go b/internal/service/bedrockagent/knowledge_base.go index 9d1384b53454..eea9c4090bac 100644 --- a/internal/service/bedrockagent/knowledge_base.go +++ b/internal/service/bedrockagent/knowledge_base.go @@ -115,8 +115,6 @@ func (r *knowledgeBaseResource) Schema(ctx context.Context, request resource.Sch "vector_knowledge_base_configuration": schema.ListNestedBlock{ CustomType: fwtypes.NewListNestedObjectTypeOf[vectorKnowledgeBaseConfigurationModel](ctx), Validators: []validator.List{ - listvalidator.IsRequired(), - listvalidator.SizeAtLeast(1), listvalidator.SizeAtMost(1), }, PlanModifiers: []planmodifier.List{ @@ -206,14 +204,32 @@ func (r *knowledgeBaseResource) Schema(ctx context.Context, request resource.Sch }, }, }, + "kendra_knowledge_base_configuration": schema.ListNestedBlock{ + CustomType: fwtypes.NewListNestedObjectTypeOf[kendraKnowledgeBaseConfigurationModel](ctx), + Validators: []validator.List{ + listvalidator.SizeAtMost(1), + }, + PlanModifiers: []planmodifier.List{ + listplanmodifier.RequiresReplace(), + }, + NestedObject: schema.NestedBlockObject{ + Attributes: map[string]schema.Attribute{ + "kendra_index_arn": schema.StringAttribute{ + CustomType: fwtypes.ARNType, + Required: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.RequiresReplace(), + }, + }, + }, + }, + }, }, }, }, "storage_configuration": schema.ListNestedBlock{ CustomType: fwtypes.NewListNestedObjectTypeOf[storageConfigurationModel](ctx), Validators: []validator.List{ - listvalidator.IsRequired(), - listvalidator.SizeAtLeast(1), listvalidator.SizeAtMost(1), }, PlanModifiers: []planmodifier.List{ @@ -803,6 +819,7 @@ type knowledgeBaseResourceModel struct { type knowledgeBaseConfigurationModel struct { Type types.String `tfsdk:"type"` VectorKnowledgeBaseConfiguration fwtypes.ListNestedObjectValueOf[vectorKnowledgeBaseConfigurationModel] `tfsdk:"vector_knowledge_base_configuration"` + KendraKnowledgeBaseConfiguration fwtypes.ListNestedObjectValueOf[kendraKnowledgeBaseConfigurationModel] `tfsdk:"kendra_knowledge_base_configuration"` } type vectorKnowledgeBaseConfigurationModel struct { @@ -829,6 +846,10 @@ type storageLocationModel struct { S3Location fwtypes.ListNestedObjectValueOf[s3LocationModel] `tfsdk:"s3_location"` } +type kendraKnowledgeBaseConfigurationModel struct { + KendraIndexARN fwtypes.ARN `tfsdk:"kendra_index_arn"` +} + type storageConfigurationModel struct { OpensearchServerlessConfiguration fwtypes.ListNestedObjectValueOf[opensearchServerlessConfigurationModel] `tfsdk:"opensearch_serverless_configuration"` PineconeConfiguration fwtypes.ListNestedObjectValueOf[pineconeConfigurationModel] `tfsdk:"pinecone_configuration"` diff --git a/internal/service/bedrockagent/knowledge_base_test.go b/internal/service/bedrockagent/knowledge_base_test.go index eb19ecfc5a69..d20503898a7f 100644 --- a/internal/service/bedrockagent/knowledge_base_test.go +++ b/internal/service/bedrockagent/knowledge_base_test.go @@ -402,6 +402,35 @@ func testAccKnowledgeBase_OpenSearch_supplementalDataStorage(t *testing.T) { }) } +func testAccKnowledgeBase_Kendra_basic(t *testing.T) { + ctx := acctest.Context(t) + kendraIndexArn := skipIfKendraIndexArnEnvVarNotSet(t) + + var knowledgebase types.KnowledgeBase + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + resourceName := "aws_bedrockagent_knowledge_base.test" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { + acctest.PreCheck(ctx, t) + }, + ErrorCheck: acctest.ErrorCheck(t, names.BedrockAgentServiceID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckKnowledgeBaseDestroy(ctx), + Steps: []resource.TestStep{ + { + Config: testAccKnowledgeBaseConfig_Kendra_basic(rName, kendraIndexArn), + Check: resource.ComposeTestCheckFunc( + testAccCheckKnowledgeBaseExists(ctx, resourceName, &knowledgebase), + resource.TestCheckResourceAttr(resourceName, "knowledge_base_configuration.#", "1"), + resource.TestCheckResourceAttr(resourceName, "knowledge_base_configuration.0.kendra_knowledge_base_configuration.#", "1"), + resource.TestCheckResourceAttr(resourceName, "knowledge_base_configuration.0.type", "KENDRA"), + ), + }, + }, + }) +} + func testAccCheckKnowledgeBaseDestroy(ctx context.Context) resource.TestCheckFunc { return func(s *terraform.State) error { conn := acctest.Provider.Meta().(*conns.AWSClient).BedrockAgentClient(ctx) @@ -486,6 +515,26 @@ func skipIfOSSCollectionNameEnvVarNotSet(t *testing.T) string { return v } +// skipIfKendraIndexArnEnvVarNotSet handles skipping tests when an environment +// variable providing a valid Kendra index ARN is unset +// +// This should be called in all acceptance tests currently dependent on a Kendra index. +// +// To create a Kendra index to be used with this environment variable: +// 1. In the AWS console, navigate to Amazon Kendra +// 2. Create a new index with "GEN_AI_ENTERPRISE_EDITION" edition +// 3. Wait for the index to be in "ACTIVE" status (this can take 20+ minutes) +// 4. Copy the index ARN and set it as the TF_AWS_KENDRA_INDEX_ARN environment variable +func skipIfKendraIndexArnEnvVarNotSet(t *testing.T) string { + t.Helper() + v := os.Getenv("TF_AWS_KENDRA_INDEX_ARN") + if v == "" { + acctest.Skip(t, "This test requires a pre-existing Kendra index. "+ + "Set the TF_AWS_KENDRA_INDEX_ARN environment variable to the ARN of an existing Kendra index.") + } + return v +} + func testAccKnowledgeBaseConfig_basicRDS(rName, model, description string) string { if description == "" { description = "null" @@ -940,3 +989,66 @@ resource "aws_bedrockagent_knowledge_base" "test" { } `, rName, model)) } + +func testAccKnowledgeBaseConfig_Kendra_basic(rName, kendraIndexArn string) string { + return fmt.Sprintf(` +data "aws_caller_identity" "current" {} +data "aws_region" "current" {} +data "aws_partition" "current" {} + +resource "aws_iam_role" "test" { + name = %[1]q + assume_role_policy = jsonencode({ + Version = "2012-10-17" + Statement = [ + { + Action = "sts:AssumeRole" + Effect = "Allow" + Principal = { + Service = "bedrock.amazonaws.com" + } + Condition = { + StringEquals = { + "aws:SourceAccount" = data.aws_caller_identity.current.account_id + } + ArnLike = { + "aws:SourceArn" = "arn:${data.aws_partition.current.partition}:bedrock:${data.aws_region.current.region}:${data.aws_caller_identity.current.account_id}:knowledge-base/*" + } + } + } + ] + }) +} + +resource "aws_iam_role_policy" "test" { + name = "%[1]s-bedrock" + role = aws_iam_role.test.id + policy = jsonencode({ + Version = "2012-10-17" + Statement = [ + { + Effect = "Allow" + Action = [ + "kendra:Retrieve", + "kendra:DescribeIndex" + ] + Resource = %[2]q + } + ] + }) +} + +resource "aws_bedrockagent_knowledge_base" "test" { + name = %[1]q + role_arn = aws_iam_role.test.arn + depends_on = [aws_iam_role_policy.test] + + knowledge_base_configuration { + type = "KENDRA" + kendra_knowledge_base_configuration { + kendra_index_arn = %[2]q + } + } +} +`, rName, kendraIndexArn) +} From 4b277f686050249c6dc5f9dce59269810beaca16 Mon Sep 17 00:00:00 2001 From: Aya Kim Date: Sat, 20 Sep 2025 15:48:21 +0000 Subject: [PATCH 09/65] docs: Add Kendra knowledge base documentation --- .../bedrockagent_knowledge_base.html.markdown | 26 +++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/website/docs/cdktf/typescript/r/bedrockagent_knowledge_base.html.markdown b/website/docs/cdktf/typescript/r/bedrockagent_knowledge_base.html.markdown index 6b687c69aae4..618802aef02e 100644 --- a/website/docs/cdktf/typescript/r/bedrockagent_knowledge_base.html.markdown +++ b/website/docs/cdktf/typescript/r/bedrockagent_knowledge_base.html.markdown @@ -144,6 +144,21 @@ class MyConvertedCode extends TerraformStack { ``` +### Kendra Knowledge Base + +```hcl +resource "aws_bedrockagent_knowledge_base" "kendra_example" { + name = "example-kendra-kb" + role_arn = aws_iam_role.example.arn + + knowledge_base_configuration { + type = "KENDRA" + kendra_knowledge_base_configuration { + kendra_index_arn = "arn:aws:kendra:us-east-1:123456789012:index/example-index-id" + } + } +} + ## Argument Reference The following arguments are required: @@ -163,8 +178,9 @@ The following arguments are optional: The `knowledgeBaseConfiguration` configuration block supports the following arguments: -* `type` - (Required) Type of data that the data source is converted into for the knowledge base. Valid Values: `VECTOR`. -* `vectorKnowledgeBaseConfiguration` - (Optional) Details about the embeddings model that'sused to convert the data source. See [`vectorKnowledgeBaseConfiguration` block](#vector_knowledge_base_configuration-block) for details. +* `type` - (Required) Type of data that the data source is converted into for the knowledge base. Valid Values: `VECTOR`, `KENDRA`. +* `vectorKnowledgeBaseConfiguration` - (Optional) Details about the embeddings model that's used to convert the data source. See [`vectorKnowledgeBaseConfiguration` block](#vector_knowledge_base_configuration-block) for details. +* `kendraKnowledgeBaseConfiguration` - (Optional) Configuration for Kendra knowledge base. See [`kendraKnowledgeBaseConfiguration` block](#kendra_knowledge_base_configuration-block) for details. ### `vectorKnowledgeBaseConfiguration` block @@ -206,6 +222,12 @@ The `s3Location` configuration block supports the following arguments: * `uri` - (Required) URI of the location. +### `kendraKnowledgeBaseConfiguration` block + +The `kendraKnowledgeBaseConfiguration` configuration block supports the following arguments: + +* `kendraIndexArn` - (Required) ARN of the Amazon Kendra index. + ### `storageConfiguration` block The `storageConfiguration` configuration block supports the following arguments: From 14d7f056511d539db1e4c394aca4d0ac1e63eb71 Mon Sep 17 00:00:00 2001 From: Aya Kim Date: Sat, 20 Sep 2025 16:31:17 +0000 Subject: [PATCH 10/65] docs: Add Kendra knowledge base documentation --- .../cdktf/typescript/r/bedrockagent_knowledge_base.html.markdown | 1 + 1 file changed, 1 insertion(+) diff --git a/website/docs/cdktf/typescript/r/bedrockagent_knowledge_base.html.markdown b/website/docs/cdktf/typescript/r/bedrockagent_knowledge_base.html.markdown index 618802aef02e..94abfffffe29 100644 --- a/website/docs/cdktf/typescript/r/bedrockagent_knowledge_base.html.markdown +++ b/website/docs/cdktf/typescript/r/bedrockagent_knowledge_base.html.markdown @@ -158,6 +158,7 @@ resource "aws_bedrockagent_knowledge_base" "kendra_example" { } } } +``` ## Argument Reference From 8c81e05066d40aebb02311d5a4cb653fb817c516 Mon Sep 17 00:00:00 2001 From: Aya Kim Date: Sat, 20 Sep 2025 16:36:57 +0000 Subject: [PATCH 11/65] Add changelog --- .changelog/44388.txt | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 .changelog/44388.txt diff --git a/.changelog/44388.txt b/.changelog/44388.txt new file mode 100644 index 000000000000..c2ae45acffe6 --- /dev/null +++ b/.changelog/44388.txt @@ -0,0 +1,3 @@ +```release-note:enhancement +resource/aws_bedrockagent_knowledge_base: Add Kendra support to aws_bedrockagent_knowledge_base +``` \ No newline at end of file From 24a7bb7a14a09c136dd71dd6dbdd457605a39c95 Mon Sep 17 00:00:00 2001 From: Aya Kim Date: Sat, 20 Sep 2025 16:49:59 +0000 Subject: [PATCH 12/65] Fix test formatting --- internal/service/bedrockagent/knowledge_base_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/internal/service/bedrockagent/knowledge_base_test.go b/internal/service/bedrockagent/knowledge_base_test.go index d20503898a7f..907ee240223c 100644 --- a/internal/service/bedrockagent/knowledge_base_test.go +++ b/internal/service/bedrockagent/knowledge_base_test.go @@ -1039,8 +1039,8 @@ resource "aws_iam_role_policy" "test" { } resource "aws_bedrockagent_knowledge_base" "test" { - name = %[1]q - role_arn = aws_iam_role.test.arn + name = %[1]q + role_arn = aws_iam_role.test.arn depends_on = [aws_iam_role_policy.test] knowledge_base_configuration { From 45881e275350b2defa3e0db5d38ef7ca25b5a42e Mon Sep 17 00:00:00 2001 From: Aya Kim Date: Sat, 20 Sep 2025 16:56:06 +0000 Subject: [PATCH 13/65] Fix function name capitalization --- internal/service/bedrockagent/knowledge_base_test.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/internal/service/bedrockagent/knowledge_base_test.go b/internal/service/bedrockagent/knowledge_base_test.go index 907ee240223c..52ff3d01c699 100644 --- a/internal/service/bedrockagent/knowledge_base_test.go +++ b/internal/service/bedrockagent/knowledge_base_test.go @@ -404,7 +404,7 @@ func testAccKnowledgeBase_OpenSearch_supplementalDataStorage(t *testing.T) { func testAccKnowledgeBase_Kendra_basic(t *testing.T) { ctx := acctest.Context(t) - kendraIndexArn := skipIfKendraIndexArnEnvVarNotSet(t) + kendraIndexArn := skipIfKendraIndexARNEnvVarNotSet(t) var knowledgebase types.KnowledgeBase rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) @@ -515,7 +515,7 @@ func skipIfOSSCollectionNameEnvVarNotSet(t *testing.T) string { return v } -// skipIfKendraIndexArnEnvVarNotSet handles skipping tests when an environment +// skipIfKendraIndexARNEnvVarNotSet handles skipping tests when an environment // variable providing a valid Kendra index ARN is unset // // This should be called in all acceptance tests currently dependent on a Kendra index. @@ -525,7 +525,7 @@ func skipIfOSSCollectionNameEnvVarNotSet(t *testing.T) string { // 2. Create a new index with "GEN_AI_ENTERPRISE_EDITION" edition // 3. Wait for the index to be in "ACTIVE" status (this can take 20+ minutes) // 4. Copy the index ARN and set it as the TF_AWS_KENDRA_INDEX_ARN environment variable -func skipIfKendraIndexArnEnvVarNotSet(t *testing.T) string { +func skipIfKendraIndexARNEnvVarNotSet(t *testing.T) string { t.Helper() v := os.Getenv("TF_AWS_KENDRA_INDEX_ARN") if v == "" { From ed1641a4ae90c5059205e72c1bf878c40bd41733 Mon Sep 17 00:00:00 2001 From: Stephen Monaghan Date: Sun, 5 Oct 2025 16:44:56 -0400 Subject: [PATCH 14/65] Updating tests Updated tests to now create a managed OpenSearch domain to be used instead of having to pre-create one. --- .../bedrockagent/knowledge_base_test.go | 389 +++++++++++++++--- 1 file changed, 342 insertions(+), 47 deletions(-) diff --git a/internal/service/bedrockagent/knowledge_base_test.go b/internal/service/bedrockagent/knowledge_base_test.go index c188732cc969..7f4db3bc9b84 100644 --- a/internal/service/bedrockagent/knowledge_base_test.go +++ b/internal/service/bedrockagent/knowledge_base_test.go @@ -450,25 +450,40 @@ func testAccCheckKnowledgeBaseExists(ctx context.Context, n string, v *types.Kno } func TestAccBedrockAgentKnowledgeBase_OpenSearchManagedCluster_basic(t *testing.T) { + if testing.Short() { + t.Skip("skipping long-running test in short mode") + } + ctx := acctest.Context(t) - domain := skipIfOSDomainEnvVarNotSet(t) - bedrockIAMRoleName := skipIfIAMRoleVarNotSet(t) var knowledgebase types.KnowledgeBase rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) resourceName := "aws_bedrockagent_knowledge_base.test" foundationModel := "amazon.titan-embed-text-v2:0" + testExternalProviders := map[string]resource.ExternalProvider{ + "opensearch": { + Source: "opensearch-project/opensearch", + VersionConstraint: "~> 2.2.0", + }, + "random": { + Source: "hashicorp/random", + VersionConstraint: "~> 3.5.0", + }, + } + resource.Test(t, resource.TestCase{ PreCheck: func() { acctest.PreCheck(ctx, t) + acctest.PreCheckIAMServiceLinkedRole(ctx, t, "/aws-service-role/opensearchservice.amazonaws.com") }, ErrorCheck: acctest.ErrorCheck(t, names.BedrockAgentServiceID), ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + ExternalProviders: testExternalProviders, CheckDestroy: testAccCheckKnowledgeBaseDestroy(ctx), Steps: []resource.TestStep{ { - Config: testAccKnowledgeBaseConfig_OpenSearchManagedCluster_basic(rName, domain, bedrockIAMRoleName, foundationModel), + Config: testAccKnowledgeBaseConfig_OpenSearchManagedCluster_basic(rName, foundationModel), Check: resource.ComposeTestCheckFunc( testAccCheckKnowledgeBaseExists(ctx, resourceName, &knowledgebase), resource.TestCheckResourceAttr(resourceName, names.AttrName, rName), @@ -486,9 +501,15 @@ func TestAccBedrockAgentKnowledgeBase_OpenSearchManagedCluster_basic(t *testing. ), }, { - ResourceName: resourceName, - ImportState: true, - ImportStateVerify: true, + Config: testAccKnowledgeBaseConfig_OpenSearchManagedCluster_basic(rName, foundationModel), + ResourceName: resourceName, + ImportStateKind: resource.ImportBlockWithID, + ImportState: true, + ImportPlanChecks: resource.ImportPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrID), knownvalue.NotNull()), + }, + }, }, }, }) @@ -531,34 +552,6 @@ func skipIfOSSCollectionNameEnvVarNotSet(t *testing.T) string { return v } -// skipIfOSDomainEnvVarNotSet handles skipping tests when an environment -// variable providing a valid OpenSearch domain name is unset -// -// This should be called in all acceptance tests currently dependent on an OpenSearch -// Managed Cluster domain. -func skipIfOSDomainEnvVarNotSet(t *testing.T) string { - t.Helper() - - v := os.Getenv("TF_AWS_BEDROCK_OS_DOMAIN_NAME") - if v == "" { - acctest.Skip(t, "This test requires external configuration of an OpenSearch domain. "+ - "Set the TF_AWS_BEDROCK_OS_DOMAIN_NAME environment variable to the OpenSearch domain name.") - } - return v -} - -func skipIfIAMRoleVarNotSet(t *testing.T) string { - t.Helper() - - v := os.Getenv("TF_AWS_BEDROCK_IAM_ROLE_ARN") - if v == "" { - acctest.Skip(t, "This test requires external configuration of an IAM Role with permissions on the OpenSearch Cluster."+ - "It must be able to be assumed by the Amazon Bedrock service"+ - "Set the TF_AWS_BEDROCK_IAM_ROLE_ARN environment variable to the IAM Role's ARN.") - } - return v -} - func testAccKnowledgeBaseConfig_basicRDS(rName, model, description string) string { if description == "" { description = "null" @@ -1014,20 +1007,13 @@ resource "aws_bedrockagent_knowledge_base" "test" { `, rName, model)) } -func testAccKnowledgeBaseConfig_OpenSearchManagedCluster_basic(rName, domainName, bedrockRole, model string) string { +func testAccKnowledgeBaseConfig_OpenSearchManagedCluster_basic(rName, model string) string { return acctest.ConfigCompose( + testAccKnowledgeBaseConfig_OpenSearchManagedCluster(rName, model), fmt.Sprintf(` -data "aws_caller_identity" "current" {} -data "aws_region" "current" {} -data "aws_partition" "current" {} - -data "aws_opensearch_domain" "test" { - domain_name = %[4]q -} - resource "aws_bedrockagent_knowledge_base" "test" { name = %[1]q - role_arn = %[3]q + role_arn = aws_iam_role.bedrock_kb_role.arn knowledge_base_configuration { vector_knowledge_base_configuration { @@ -1039,8 +1025,8 @@ resource "aws_bedrockagent_knowledge_base" "test" { storage_configuration { type = "OPENSEARCH_MANAGED_CLUSTER" opensearch_managed_cluster_configuration { - domain_arn = data.aws_opensearch_domain.test.arn - domain_endpoint = "https://${data.aws_opensearch_domain.test.endpoint}" + domain_arn = aws_opensearch_domain.knowledge_base.arn + domain_endpoint = "https://${aws_opensearch_domain.knowledge_base.endpoint}" vector_index_name = "knowledge-index" field_mapping { vector_field = "vector_embedding" @@ -1049,6 +1035,315 @@ resource "aws_bedrockagent_knowledge_base" "test" { } } } + + depends_on = [ + aws_opensearch_domain.knowledge_base, + opensearch_index.vector_index, + opensearch_roles_mapping.mapper, + aws_iam_role_policy_attachment.opensearch_access, + aws_iam_role_policy_attachment.bedrock_models_access, + ] +} +`, rName, model)) +} + +func testAccKnowledgeBaseConfig_OpenSearchManagedCluster(rName, model string) string { + return acctest.ConfigCompose( + fmt.Sprintf(` +terraform { + required_providers { + opensearch = { + source = "opensearch-project/opensearch" + version = "~> 2.2.0" + } + random = { + source = "hashicorp/random" + version = "~> 3.5.0" + } + } +} + +data "aws_partition" "current" {} + +data "aws_region" "current" {} + +data "aws_caller_identity" "current" {} + +data "aws_iam_role" "opensearch" { + name = "AWSServiceRoleForAmazonOpenSearchService" +} + +resource "aws_iam_role" "bedrock_kb_role" { + name = %[1]q + + assume_role_policy = jsonencode({ + Version = "2012-10-17" + Statement = [ + { + Effect = "Allow" + Principal = { + Service = "bedrock.${data.aws_partition.current.dns_suffix}" + } + Action = "sts:AssumeRole" + Condition = { + StringEquals = { + "aws:SourceAccount": data.aws_caller_identity.current.account_id + }, + ArnLike = { + "aws:SourceArn": "arn:${data.aws_partition.current.partition}:bedrock:${data.aws_region.current.region}:${data.aws_caller_identity.current.account_id}:knowledge-base/*" + } + } + } + ] + }) +} + +resource "aws_iam_policy" "bedrock_models_access" { + name = "bedrock-%[1]s" + description = "IAM policy for Amazon Bedrock to access embedding models" + + policy = jsonencode({ + Version = "2012-10-17" + Statement = [ + { + Effect = "Allow" + Action = [ + "bedrock:RetrieveAndGenerate" + ] + Resource = "*" + }, + { + Effect = "Allow" + Action = [ + "bedrock:ListFoundationModels", + "bedrock:ListCustomModels" + ] + Resource = "*" + }, + { + Effect = "Allow" + Action = [ + "bedrock:InvokeModel" + ] + Resource = [ + "arn:${data.aws_partition.current.partition}:bedrock:${data.aws_region.current.region}::foundation-model/%[2]s" + ] + } + ] + }) +} + +resource "aws_iam_policy" "opensearch_access" { + name = "os-%[1]s" + description = "IAM policy for Amazon Bedrock to access OpenSearch domain" + + policy = jsonencode({ + Version = "2012-10-17" + Statement = [ + { + Effect = "Allow" + Action = [ + "es:ESHttpGet", + "es:ESHttpPost", + "es:ESHttpPut", + "es:ESHttpDelete" + ] + Resource = [ + "*" + ] + }, + { + Effect = "Allow" + Action = [ + "es:DescribeDomain", + "es:DescribeElasticsearchDomain" + ] + Resource = [ + "*" + ] + } + ] + }) +} + +resource "aws_iam_role_policy_attachment" "bedrock_models_access" { + role = aws_iam_role.bedrock_kb_role.name + policy_arn = aws_iam_policy.bedrock_models_access.arn +} + +resource "aws_iam_role_policy_attachment" "opensearch_access" { + role = aws_iam_role.bedrock_kb_role.name + policy_arn = aws_iam_policy.opensearch_access.arn +} + +resource "random_password" "opensearch_master" { + length = 16 + special = true + min_lower = 1 + min_numeric = 1 + min_special = 1 + min_upper = 1 + override_special = "!#$&*()-_=+" + + # Don't replace the password on each apply + lifecycle { + ignore_changes = [length, special, override_special] + } +} + +resource "aws_opensearch_domain" "knowledge_base" { + domain_name = substr(%[1]q, 0, 28) + engine_version = "OpenSearch_3.1" + access_policies = local.opensearch_access_policy + + cluster_config { + instance_type = "or2.medium.search" + instance_count = 1 + zone_awareness_enabled = false + dedicated_master_enabled = false + } + + # Configure EBS volumes for the data nodes + ebs_options { + ebs_enabled = true + volume_size = 20 + volume_type = "gp3" + } + + # Enable encryption at rest + encrypt_at_rest { + enabled = true + } + + # Enable node to node encryption + node_to_node_encryption { + enabled = true + } + + # Configure domain endpoint options + domain_endpoint_options { + enforce_https = true + tls_security_policy = "Policy-Min-TLS-1-2-PFS-2023-10" + } + + # Configure advanced security options + advanced_security_options { + enabled = true + internal_user_database_enabled = true + master_user_options { + master_user_name = "admin" + master_user_password = random_password.opensearch_master.result + } + } + + # Auto-Tune options + auto_tune_options { + desired_state = "ENABLED" + } + + # Software update options + software_update_options { + auto_software_update_enabled = true + } + + # This is required to reference the existing service-linked role + depends_on = [ + data.aws_iam_role.opensearch + ] +} + +locals { + opensearch_access_policy = jsonencode({ + Version = "2012-10-17" + Statement = [ + { + Effect = "Allow" + Principal = { + AWS = "*" + } + Action = "es:*" + Resource = "arn:${data.aws_partition.current.partition}:es:${data.aws_region.current.region}:${data.aws_caller_identity.current.account_id}:domain/${substr(%[1]q, 0, 28)}/*" + } + ] + }) +} + +provider "opensearch" { + url = "https://${aws_opensearch_domain.knowledge_base.endpoint}" + username = "admin" + password = random_password.opensearch_master.result + insecure = false + aws_region = data.aws_region.current.region + healthcheck = false + sniff = false + sign_aws_requests = false } -`, rName, model, bedrockRole, domainName)) + +resource "opensearch_role" "os_kb_role" { + role_name = "kb-%[1]s" + description = "Knowledge Base Role" + + cluster_permissions = ["*"] + + index_permissions { + index_patterns = ["*"] + allowed_actions = ["*"] + } + + tenant_permissions { + tenant_patterns = ["*"] + allowed_actions = ["*"] + } +} + +resource "opensearch_roles_mapping" "mapper" { + role_name = opensearch_role.os_kb_role.role_name + description = "Mapping AWS IAM roles to ES role" + backend_roles = [ + aws_iam_role.bedrock_kb_role.arn, + data.aws_caller_identity.current.arn + ] +} + +resource "opensearch_index" "vector_index" { + name = "knowledge-index" + number_of_shards = "5" + number_of_replicas = "1" + index_knn = true + + # Mappings for Bedrock Knowledge Base compatibility + mappings = jsonencode({ + "properties": { + "vector_embedding": { + "type": "knn_vector", + "dimension": 1024, + "space_type": "l2", + "method": { + "name": "hnsw", + "engine": "faiss", + "parameters": { + "ef_construction": 128, + "m": 24 + } + } + }, + "text": { + "type": "text", + "index": true + }, + "metadata": { + "type": "text", + "index": false + } + } + }) + + lifecycle { + ignore_changes = [ mappings ] + } + + depends_on = [ aws_opensearch_domain.knowledge_base ] +} + +`, rName, model)) } From 810d2999a4985365a21ebd95afb67c09617e81ca Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Fri, 5 Dec 2025 11:08:28 -0500 Subject: [PATCH 15/65] Tweak #44388's CHANGELOG entries. --- .changelog/44388.txt | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/.changelog/44388.txt b/.changelog/44388.txt index c2ae45acffe6..30955b45cdac 100644 --- a/.changelog/44388.txt +++ b/.changelog/44388.txt @@ -1,3 +1,7 @@ ```release-note:enhancement -resource/aws_bedrockagent_knowledge_base: Add Kendra support to aws_bedrockagent_knowledge_base +resource/aws_bedrockagent_knowledge_base: Add `knowledge_base_configuration.kendra_knowledge_base_configuration` argument +``` + +```release-note:enhancement +resource/aws_bedrockagent_knowledge_base: Make `knowledge_base_configuration.vector_knowledge_base_configuration` and ``storage_configuration` optional ``` \ No newline at end of file From fd7e4485dc94792f7360608f90216ac5073b346e Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Fri, 5 Dec 2025 11:41:23 -0500 Subject: [PATCH 16/65] r/aws_bedrockagent_knowledge_base: Document 'kendra_knowledge_base_configuration'. --- .../bedrockagent_knowledge_base.html.markdown | 28 +++++++++++++++++-- 1 file changed, 25 insertions(+), 3 deletions(-) diff --git a/website/docs/r/bedrockagent_knowledge_base.html.markdown b/website/docs/r/bedrockagent_knowledge_base.html.markdown index afc09fa2a008..fc432ee79cd8 100644 --- a/website/docs/r/bedrockagent_knowledge_base.html.markdown +++ b/website/docs/r/bedrockagent_knowledge_base.html.markdown @@ -39,6 +39,21 @@ resource "aws_bedrockagent_knowledge_base" "example" { } ``` +### Kendra Knowledge Base + +```hcl +resource "aws_bedrockagent_knowledge_base" "kendra_example" { + name = "example-kendra-kb" + role_arn = aws_iam_role.example.arn + knowledge_base_configuration { + type = "KENDRA" + kendra_knowledge_base_configuration { + kendra_index_arn = "arn:aws:kendra:us-east-1:123456789012:index/example-index-id" + } + } +} +``` + ### OpenSearch Managed Cluster Configuration ```terraform @@ -118,21 +133,28 @@ The following arguments are required: * `knowledge_base_configuration` - (Required, Forces new resource) Details about the embeddings configuration of the knowledge base. See [`knowledge_base_configuration` block](#knowledge_base_configuration-block) for details. * `name` - (Required) Name of the knowledge base. * `role_arn` - (Required) ARN of the IAM role with permissions to invoke API operations on the knowledge base. -* `storage_configuration` - (Required, Forces new resource) Details about the storage configuration of the knowledge base. See [`storage_configuration` block](#storage_configuration-block) for details. The following arguments are optional: -* `region` - (Optional) Region where this resource will be [managed](https://docs.aws.amazon.com/general/latest/gr/rande.html#regional-endpoints). Defaults to the Region set in the [provider configuration](https://registry.terraform.io/providers/hashicorp/aws/latest/docs#aws-configuration-reference). * `description` - (Optional) Description of the knowledge base. +* `region` - (Optional) Region where this resource will be [managed](https://docs.aws.amazon.com/general/latest/gr/rande.html#regional-endpoints). Defaults to the Region set in the [provider configuration](https://registry.terraform.io/providers/hashicorp/aws/latest/docs#aws-configuration-reference). +* `storage_configuration` - (Optional, Forces new resource) Details about the storage configuration of the knowledge base. See [`storage_configuration` block](#storage_configuration-block) for details. * `tags` - (Optional) Map of tags assigned to the resource. If configured with a provider [`default_tags` configuration block](/docs/providers/aws/index.html#default_tags-configuration-block) present, tags with matching keys will overwrite those defined at the provider-level. ### `knowledge_base_configuration` block The `knowledge_base_configuration` configuration block supports the following arguments: -* `type` - (Required) Type of data that the data source is converted into for the knowledge base. Valid Values: `VECTOR`. +* `kendra_knowledge_base_configuration` - (Optional) Configuration for Kendra knowledge base. See [`kendra_knowledge_base_configuration` block](#kendra_knowledge_base_configuration-block) for details. +* `type` - (Required) Type of data that the data source is converted into for the knowledge base. Valid Values: `VECTOR`, `KENDRA`, `SQL`. * `vector_knowledge_base_configuration` - (Optional) Details about the embeddings model that'sused to convert the data source. See [`vector_knowledge_base_configuration` block](#vector_knowledge_base_configuration-block) for details. +### `kendra_knowledge_base_configuration` block + +The `kendra_knowledge_base_configuration` configuration block supports the following arguments: + +* `kendra_index_arn` - (Required) ARN of the Amazon Kendra index. + ### `vector_knowledge_base_configuration` block The `vector_knowledge_base_configuration` configuration block supports the following arguments: From 266cabe21bcd41b7d7055e4aea1f8c2d301e86c6 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Fri, 5 Dec 2025 12:11:34 -0500 Subject: [PATCH 17/65] r/aws_bedrockagent_knowledge_base: Alphabetize attributes. --- internal/service/bedrockagent/data_source.go | 2 +- .../service/bedrockagent/knowledge_base.go | 258 ++++++++++-------- .../bedrockagent_knowledge_base.html.markdown | 19 +- 3 files changed, 151 insertions(+), 128 deletions(-) diff --git a/internal/service/bedrockagent/data_source.go b/internal/service/bedrockagent/data_source.go index 983f6994ae1a..676f39baa1b3 100644 --- a/internal/service/bedrockagent/data_source.go +++ b/internal/service/bedrockagent/data_source.go @@ -1122,7 +1122,7 @@ type intermediateStorageModel struct { } type s3LocationModel struct { - Uri types.String `tfsdk:"uri"` + URI types.String `tfsdk:"uri"` } type transformationModel struct { diff --git a/internal/service/bedrockagent/knowledge_base.go b/internal/service/bedrockagent/knowledge_base.go index 0cf400860a5d..63b2ac7b3dd2 100644 --- a/internal/service/bedrockagent/knowledge_base.go +++ b/internal/service/bedrockagent/knowledge_base.go @@ -18,6 +18,7 @@ import ( "github.com/hashicorp/terraform-plugin-framework-timetypes/timetypes" "github.com/hashicorp/terraform-plugin-framework-validators/listvalidator" "github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator" + "github.com/hashicorp/terraform-plugin-framework/path" "github.com/hashicorp/terraform-plugin-framework/resource" "github.com/hashicorp/terraform-plugin-framework/resource/schema" "github.com/hashicorp/terraform-plugin-framework/resource/schema/listplanmodifier" @@ -105,13 +106,38 @@ func (r *knowledgeBaseResource) Schema(ctx context.Context, request resource.Sch NestedObject: schema.NestedBlockObject{ Attributes: map[string]schema.Attribute{ names.AttrType: schema.StringAttribute{ - Required: true, + CustomType: fwtypes.StringEnumType[awstypes.KnowledgeBaseType](), + Required: true, PlanModifiers: []planmodifier.String{ stringplanmodifier.RequiresReplace(), }, }, }, Blocks: map[string]schema.Block{ + "kendra_knowledge_base_configuration": schema.ListNestedBlock{ + CustomType: fwtypes.NewListNestedObjectTypeOf[kendraKnowledgeBaseConfigurationModel](ctx), + Validators: []validator.List{ + listvalidator.SizeAtMost(1), + listvalidator.ExactlyOneOf( + path.MatchRelative().AtParent().AtName("kendra_knowledge_base_configuration"), + path.MatchRelative().AtParent().AtName("vector_knowledge_base_configuration"), + ), + }, + PlanModifiers: []planmodifier.List{ + listplanmodifier.RequiresReplace(), + }, + NestedObject: schema.NestedBlockObject{ + Attributes: map[string]schema.Attribute{ + "kendra_index_arn": schema.StringAttribute{ + CustomType: fwtypes.ARNType, + Required: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.RequiresReplace(), + }, + }, + }, + }, + }, "vector_knowledge_base_configuration": schema.ListNestedBlock{ CustomType: fwtypes.NewListNestedObjectTypeOf[vectorKnowledgeBaseConfigurationModel](ctx), Validators: []validator.List{ @@ -133,14 +159,12 @@ func (r *knowledgeBaseResource) Schema(ctx context.Context, request resource.Sch Blocks: map[string]schema.Block{ "embedding_model_configuration": schema.ListNestedBlock{ Validators: []validator.List{ - listvalidator.SizeAtLeast(0), listvalidator.SizeAtMost(1), }, NestedObject: schema.NestedBlockObject{ Blocks: map[string]schema.Block{ "bedrock_embedding_model_configuration": schema.ListNestedBlock{ Validators: []validator.List{ - listvalidator.SizeAtLeast(0), listvalidator.SizeAtMost(1), }, NestedObject: schema.NestedBlockObject{ @@ -160,13 +184,13 @@ func (r *knowledgeBaseResource) Schema(ctx context.Context, request resource.Sch }, "supplemental_data_storage_configuration": schema.ListNestedBlock{ Validators: []validator.List{ - listvalidator.SizeAtLeast(0), listvalidator.SizeAtMost(1), }, NestedObject: schema.NestedBlockObject{ Blocks: map[string]schema.Block{ "storage_location": schema.ListNestedBlock{ Validators: []validator.List{ + listvalidator.IsRequired(), listvalidator.SizeAtLeast(1), }, NestedObject: schema.NestedBlockObject{ @@ -204,26 +228,6 @@ func (r *knowledgeBaseResource) Schema(ctx context.Context, request resource.Sch }, }, }, - "kendra_knowledge_base_configuration": schema.ListNestedBlock{ - CustomType: fwtypes.NewListNestedObjectTypeOf[kendraKnowledgeBaseConfigurationModel](ctx), - Validators: []validator.List{ - listvalidator.SizeAtMost(1), - }, - PlanModifiers: []planmodifier.List{ - listplanmodifier.RequiresReplace(), - }, - NestedObject: schema.NestedBlockObject{ - Attributes: map[string]schema.Attribute{ - "kendra_index_arn": schema.StringAttribute{ - CustomType: fwtypes.ARNType, - Required: true, - PlanModifiers: []planmodifier.String{ - stringplanmodifier.RequiresReplace(), - }, - }, - }, - }, - }, }, }, }, @@ -238,38 +242,52 @@ func (r *knowledgeBaseResource) Schema(ctx context.Context, request resource.Sch NestedObject: schema.NestedBlockObject{ Attributes: map[string]schema.Attribute{ names.AttrType: schema.StringAttribute{ - Required: true, + CustomType: fwtypes.StringEnumType[awstypes.KnowledgeBaseStorageType](), + Required: true, PlanModifiers: []planmodifier.String{ stringplanmodifier.RequiresReplace(), }, }, }, Blocks: map[string]schema.Block{ - "pinecone_configuration": schema.ListNestedBlock{ - CustomType: fwtypes.NewListNestedObjectTypeOf[pineconeConfigurationModel](ctx), + "opensearch_managed_cluster_configuration": schema.ListNestedBlock{ + CustomType: fwtypes.NewListNestedObjectTypeOf[openSearchManagedClusterConfigurationModel](ctx), Validators: []validator.List{ listvalidator.SizeAtMost(1), + listvalidator.ExactlyOneOf( + path.MatchRelative().AtParent().AtName("opensearch_managed_cluster_configuration"), + path.MatchRelative().AtParent().AtName("opensearch_serverless_configuration"), + path.MatchRelative().AtParent().AtName("pinecone_configuration"), + path.MatchRelative().AtParent().AtName("rds_configuration"), + path.MatchRelative().AtParent().AtName("redis_enterprise_cloud_configuration"), + ), }, PlanModifiers: []planmodifier.List{ listplanmodifier.RequiresReplace(), }, NestedObject: schema.NestedBlockObject{ Attributes: map[string]schema.Attribute{ - "connection_string": schema.StringAttribute{ - Required: true, + "domain_arn": schema.StringAttribute{ + CustomType: fwtypes.ARNType, + Required: true, PlanModifiers: []planmodifier.String{ stringplanmodifier.RequiresReplace(), }, }, - "credentials_secret_arn": schema.StringAttribute{ - CustomType: fwtypes.ARNType, - Required: true, + "domain_endpoint": schema.StringAttribute{ + Required: true, PlanModifiers: []planmodifier.String{ stringplanmodifier.RequiresReplace(), }, + Validators: []validator.String{ + stringvalidator.RegexMatches( + regexache.MustCompile(`^https://.*$`), + "must be a valid HTTPS URL", + ), + }, }, - names.AttrNamespace: schema.StringAttribute{ - Optional: true, + "vector_index_name": schema.StringAttribute{ + Required: true, PlanModifiers: []planmodifier.String{ stringplanmodifier.RequiresReplace(), }, @@ -277,8 +295,10 @@ func (r *knowledgeBaseResource) Schema(ctx context.Context, request resource.Sch }, Blocks: map[string]schema.Block{ "field_mapping": schema.ListNestedBlock{ - CustomType: fwtypes.NewListNestedObjectTypeOf[pineconeFieldMappingModel](ctx), + CustomType: fwtypes.NewListNestedObjectTypeOf[opensearchManagedClusterFieldMappingModel](ctx), Validators: []validator.List{ + listvalidator.IsRequired(), + listvalidator.SizeAtLeast(1), listvalidator.SizeAtMost(1), }, PlanModifiers: []planmodifier.List{ @@ -287,13 +307,19 @@ func (r *knowledgeBaseResource) Schema(ctx context.Context, request resource.Sch NestedObject: schema.NestedBlockObject{ Attributes: map[string]schema.Attribute{ "metadata_field": schema.StringAttribute{ - Optional: true, + Required: true, PlanModifiers: []planmodifier.String{ stringplanmodifier.RequiresReplace(), }, }, "text_field": schema.StringAttribute{ - Optional: true, + Required: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.RequiresReplace(), + }, + }, + "vector_field": schema.StringAttribute{ + Required: true, PlanModifiers: []planmodifier.String{ stringplanmodifier.RequiresReplace(), }, @@ -304,8 +330,8 @@ func (r *knowledgeBaseResource) Schema(ctx context.Context, request resource.Sch }, }, }, - "rds_configuration": schema.ListNestedBlock{ - CustomType: fwtypes.NewListNestedObjectTypeOf[rdsConfigurationModel](ctx), + "opensearch_serverless_configuration": schema.ListNestedBlock{ + CustomType: fwtypes.NewListNestedObjectTypeOf[openSearchServerlessConfigurationModel](ctx), Validators: []validator.List{ listvalidator.SizeAtMost(1), }, @@ -314,27 +340,14 @@ func (r *knowledgeBaseResource) Schema(ctx context.Context, request resource.Sch }, NestedObject: schema.NestedBlockObject{ Attributes: map[string]schema.Attribute{ - "credentials_secret_arn": schema.StringAttribute{ - CustomType: fwtypes.ARNType, - Required: true, - PlanModifiers: []planmodifier.String{ - stringplanmodifier.RequiresReplace(), - }, - }, - names.AttrDatabaseName: schema.StringAttribute{ - Required: true, - PlanModifiers: []planmodifier.String{ - stringplanmodifier.RequiresReplace(), - }, - }, - names.AttrResourceARN: schema.StringAttribute{ + "collection_arn": schema.StringAttribute{ CustomType: fwtypes.ARNType, Required: true, PlanModifiers: []planmodifier.String{ stringplanmodifier.RequiresReplace(), }, }, - names.AttrTableName: schema.StringAttribute{ + "vector_index_name": schema.StringAttribute{ Required: true, PlanModifiers: []planmodifier.String{ stringplanmodifier.RequiresReplace(), @@ -343,8 +356,10 @@ func (r *knowledgeBaseResource) Schema(ctx context.Context, request resource.Sch }, Blocks: map[string]schema.Block{ "field_mapping": schema.ListNestedBlock{ - CustomType: fwtypes.NewListNestedObjectTypeOf[rdsFieldMappingModel](ctx), + CustomType: fwtypes.NewListNestedObjectTypeOf[openSearchServerlessFieldMappingModel](ctx), Validators: []validator.List{ + listvalidator.IsRequired(), + listvalidator.SizeAtLeast(1), listvalidator.SizeAtMost(1), }, PlanModifiers: []planmodifier.List{ @@ -352,24 +367,12 @@ func (r *knowledgeBaseResource) Schema(ctx context.Context, request resource.Sch }, NestedObject: schema.NestedBlockObject{ Attributes: map[string]schema.Attribute{ - "custom_metadata_field": schema.StringAttribute{ - Optional: true, - PlanModifiers: []planmodifier.String{ - stringplanmodifier.RequiresReplace(), - }, - }, "metadata_field": schema.StringAttribute{ Required: true, PlanModifiers: []planmodifier.String{ stringplanmodifier.RequiresReplace(), }, }, - "primary_key_field": schema.StringAttribute{ - Required: true, - PlanModifiers: []planmodifier.String{ - stringplanmodifier.RequiresReplace(), - }, - }, "text_field": schema.StringAttribute{ Required: true, PlanModifiers: []planmodifier.String{ @@ -388,8 +391,8 @@ func (r *knowledgeBaseResource) Schema(ctx context.Context, request resource.Sch }, }, }, - "redis_enterprise_cloud_configuration": schema.ListNestedBlock{ - CustomType: fwtypes.NewListNestedObjectTypeOf[redisEnterpriseCloudConfigurationModel](ctx), + "pinecone_configuration": schema.ListNestedBlock{ + CustomType: fwtypes.NewListNestedObjectTypeOf[pineconeConfigurationModel](ctx), Validators: []validator.List{ listvalidator.SizeAtMost(1), }, @@ -398,21 +401,21 @@ func (r *knowledgeBaseResource) Schema(ctx context.Context, request resource.Sch }, NestedObject: schema.NestedBlockObject{ Attributes: map[string]schema.Attribute{ - "credentials_secret_arn": schema.StringAttribute{ - CustomType: fwtypes.ARNType, - Required: true, + "connection_string": schema.StringAttribute{ + Required: true, PlanModifiers: []planmodifier.String{ stringplanmodifier.RequiresReplace(), }, }, - names.AttrEndpoint: schema.StringAttribute{ - Required: true, + "credentials_secret_arn": schema.StringAttribute{ + CustomType: fwtypes.ARNType, + Required: true, PlanModifiers: []planmodifier.String{ stringplanmodifier.RequiresReplace(), }, }, - "vector_index_name": schema.StringAttribute{ - Required: true, + names.AttrNamespace: schema.StringAttribute{ + Optional: true, PlanModifiers: []planmodifier.String{ stringplanmodifier.RequiresReplace(), }, @@ -420,8 +423,10 @@ func (r *knowledgeBaseResource) Schema(ctx context.Context, request resource.Sch }, Blocks: map[string]schema.Block{ "field_mapping": schema.ListNestedBlock{ - CustomType: fwtypes.NewListNestedObjectTypeOf[redisEnterpriseCloudFieldMappingModel](ctx), + CustomType: fwtypes.NewListNestedObjectTypeOf[pineconeFieldMappingModel](ctx), Validators: []validator.List{ + listvalidator.IsRequired(), + listvalidator.SizeAtLeast(1), listvalidator.SizeAtMost(1), }, PlanModifiers: []planmodifier.List{ @@ -430,19 +435,13 @@ func (r *knowledgeBaseResource) Schema(ctx context.Context, request resource.Sch NestedObject: schema.NestedBlockObject{ Attributes: map[string]schema.Attribute{ "metadata_field": schema.StringAttribute{ - Optional: true, + Required: true, PlanModifiers: []planmodifier.String{ stringplanmodifier.RequiresReplace(), }, }, "text_field": schema.StringAttribute{ - Optional: true, - PlanModifiers: []planmodifier.String{ - stringplanmodifier.RequiresReplace(), - }, - }, - "vector_field": schema.StringAttribute{ - Optional: true, + Required: true, PlanModifiers: []planmodifier.String{ stringplanmodifier.RequiresReplace(), }, @@ -453,8 +452,8 @@ func (r *knowledgeBaseResource) Schema(ctx context.Context, request resource.Sch }, }, }, - "opensearch_managed_cluster_configuration": schema.ListNestedBlock{ - CustomType: fwtypes.NewListNestedObjectTypeOf[opensearchManagedClusterConfigurationModel](ctx), + "rds_configuration": schema.ListNestedBlock{ + CustomType: fwtypes.NewListNestedObjectTypeOf[rdsConfigurationModel](ctx), Validators: []validator.List{ listvalidator.SizeAtMost(1), }, @@ -463,26 +462,27 @@ func (r *knowledgeBaseResource) Schema(ctx context.Context, request resource.Sch }, NestedObject: schema.NestedBlockObject{ Attributes: map[string]schema.Attribute{ - "domain_arn": schema.StringAttribute{ + "credentials_secret_arn": schema.StringAttribute{ CustomType: fwtypes.ARNType, Required: true, PlanModifiers: []planmodifier.String{ stringplanmodifier.RequiresReplace(), }, }, - "domain_endpoint": schema.StringAttribute{ + names.AttrDatabaseName: schema.StringAttribute{ Required: true, PlanModifiers: []planmodifier.String{ stringplanmodifier.RequiresReplace(), }, - Validators: []validator.String{ - stringvalidator.RegexMatches( - regexache.MustCompile(`^https://.*$`), - "must be a valid HTTPS URL", - ), + }, + names.AttrResourceARN: schema.StringAttribute{ + CustomType: fwtypes.ARNType, + Required: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.RequiresReplace(), }, }, - "vector_index_name": schema.StringAttribute{ + names.AttrTableName: schema.StringAttribute{ Required: true, PlanModifiers: []planmodifier.String{ stringplanmodifier.RequiresReplace(), @@ -491,8 +491,10 @@ func (r *knowledgeBaseResource) Schema(ctx context.Context, request resource.Sch }, Blocks: map[string]schema.Block{ "field_mapping": schema.ListNestedBlock{ - CustomType: fwtypes.NewListNestedObjectTypeOf[opensearchManagedClusterFieldMappingModel](ctx), + CustomType: fwtypes.NewListNestedObjectTypeOf[rdsFieldMappingModel](ctx), Validators: []validator.List{ + listvalidator.IsRequired(), + listvalidator.SizeAtLeast(1), listvalidator.SizeAtMost(1), }, PlanModifiers: []planmodifier.List{ @@ -500,12 +502,24 @@ func (r *knowledgeBaseResource) Schema(ctx context.Context, request resource.Sch }, NestedObject: schema.NestedBlockObject{ Attributes: map[string]schema.Attribute{ + "custom_metadata_field": schema.StringAttribute{ + Optional: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.RequiresReplace(), + }, + }, "metadata_field": schema.StringAttribute{ Required: true, PlanModifiers: []planmodifier.String{ stringplanmodifier.RequiresReplace(), }, }, + "primary_key_field": schema.StringAttribute{ + Required: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.RequiresReplace(), + }, + }, "text_field": schema.StringAttribute{ Required: true, PlanModifiers: []planmodifier.String{ @@ -524,8 +538,8 @@ func (r *knowledgeBaseResource) Schema(ctx context.Context, request resource.Sch }, }, }, - "opensearch_serverless_configuration": schema.ListNestedBlock{ - CustomType: fwtypes.NewListNestedObjectTypeOf[opensearchServerlessConfigurationModel](ctx), + "redis_enterprise_cloud_configuration": schema.ListNestedBlock{ + CustomType: fwtypes.NewListNestedObjectTypeOf[redisEnterpriseCloudConfigurationModel](ctx), Validators: []validator.List{ listvalidator.SizeAtMost(1), }, @@ -534,13 +548,19 @@ func (r *knowledgeBaseResource) Schema(ctx context.Context, request resource.Sch }, NestedObject: schema.NestedBlockObject{ Attributes: map[string]schema.Attribute{ - "collection_arn": schema.StringAttribute{ + "credentials_secret_arn": schema.StringAttribute{ CustomType: fwtypes.ARNType, Required: true, PlanModifiers: []planmodifier.String{ stringplanmodifier.RequiresReplace(), }, }, + names.AttrEndpoint: schema.StringAttribute{ + Required: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.RequiresReplace(), + }, + }, "vector_index_name": schema.StringAttribute{ Required: true, PlanModifiers: []planmodifier.String{ @@ -550,8 +570,10 @@ func (r *knowledgeBaseResource) Schema(ctx context.Context, request resource.Sch }, Blocks: map[string]schema.Block{ "field_mapping": schema.ListNestedBlock{ - CustomType: fwtypes.NewListNestedObjectTypeOf[opensearchServerlessFieldMappingModel](ctx), + CustomType: fwtypes.NewListNestedObjectTypeOf[redisEnterpriseCloudFieldMappingModel](ctx), Validators: []validator.List{ + listvalidator.IsRequired(), + listvalidator.SizeAtLeast(1), listvalidator.SizeAtMost(1), }, PlanModifiers: []planmodifier.List{ @@ -894,9 +916,9 @@ type knowledgeBaseResourceModel struct { } type knowledgeBaseConfigurationModel struct { - Type types.String `tfsdk:"type"` - VectorKnowledgeBaseConfiguration fwtypes.ListNestedObjectValueOf[vectorKnowledgeBaseConfigurationModel] `tfsdk:"vector_knowledge_base_configuration"` KendraKnowledgeBaseConfiguration fwtypes.ListNestedObjectValueOf[kendraKnowledgeBaseConfigurationModel] `tfsdk:"kendra_knowledge_base_configuration"` + Type fwtypes.StringEnum[awstypes.KnowledgeBaseType] `tfsdk:"type"` + VectorKnowledgeBaseConfiguration fwtypes.ListNestedObjectValueOf[vectorKnowledgeBaseConfigurationModel] `tfsdk:"vector_knowledge_base_configuration"` } type vectorKnowledgeBaseConfigurationModel struct { @@ -915,12 +937,12 @@ type bedrockEmbeddingModelConfigurationModel struct { } type supplementalDataStorageConfigurationModel struct { - StorageLocation fwtypes.ListNestedObjectValueOf[storageLocationModel] `tfsdk:"storage_location"` + StorageLocations fwtypes.ListNestedObjectValueOf[storageLocationModel] `tfsdk:"storage_location"` } type storageLocationModel struct { - Type fwtypes.StringEnum[awstypes.SupplementalDataStorageLocationType] `tfsdk:"type"` S3Location fwtypes.ListNestedObjectValueOf[s3LocationModel] `tfsdk:"s3_location"` + Type fwtypes.StringEnum[awstypes.SupplementalDataStorageLocationType] `tfsdk:"type"` } type kendraKnowledgeBaseConfigurationModel struct { @@ -928,34 +950,34 @@ type kendraKnowledgeBaseConfigurationModel struct { } type storageConfigurationModel struct { - OpensearchManagedClusterConfiguration fwtypes.ListNestedObjectValueOf[opensearchManagedClusterConfigurationModel] `tfsdk:"opensearch_managed_cluster_configuration"` - OpensearchServerlessConfiguration fwtypes.ListNestedObjectValueOf[opensearchServerlessConfigurationModel] `tfsdk:"opensearch_serverless_configuration"` + OpensearchManagedClusterConfiguration fwtypes.ListNestedObjectValueOf[openSearchManagedClusterConfigurationModel] `tfsdk:"opensearch_managed_cluster_configuration"` + OpensearchServerlessConfiguration fwtypes.ListNestedObjectValueOf[openSearchServerlessConfigurationModel] `tfsdk:"opensearch_serverless_configuration"` PineconeConfiguration fwtypes.ListNestedObjectValueOf[pineconeConfigurationModel] `tfsdk:"pinecone_configuration"` RDSConfiguration fwtypes.ListNestedObjectValueOf[rdsConfigurationModel] `tfsdk:"rds_configuration"` RedisEnterpriseCloudConfiguration fwtypes.ListNestedObjectValueOf[redisEnterpriseCloudConfigurationModel] `tfsdk:"redis_enterprise_cloud_configuration"` - Type types.String `tfsdk:"type"` + Type fwtypes.StringEnum[awstypes.KnowledgeBaseStorageType] `tfsdk:"type"` } -type opensearchServerlessConfigurationModel struct { - CollectionARN fwtypes.ARN `tfsdk:"collection_arn"` - FieldMapping fwtypes.ListNestedObjectValueOf[opensearchServerlessFieldMappingModel] `tfsdk:"field_mapping"` - VectorIndexName types.String `tfsdk:"vector_index_name"` +type openSearchManagedClusterConfigurationModel struct { + DomainARN fwtypes.ARN `tfsdk:"domain_arn"` + DomainEndpoint types.String `tfsdk:"domain_endpoint"` + FieldMapping fwtypes.ListNestedObjectValueOf[opensearchManagedClusterFieldMappingModel] `tfsdk:"field_mapping"` + VectorIndexName types.String `tfsdk:"vector_index_name"` } -type opensearchServerlessFieldMappingModel struct { +type opensearchManagedClusterFieldMappingModel struct { MetadataField types.String `tfsdk:"metadata_field"` TextField types.String `tfsdk:"text_field"` VectorField types.String `tfsdk:"vector_field"` } -type opensearchManagedClusterConfigurationModel struct { - DomainARN fwtypes.ARN `tfsdk:"domain_arn"` - DomainEndpoint types.String `tfsdk:"domain_endpoint"` - FieldMapping fwtypes.ListNestedObjectValueOf[opensearchManagedClusterFieldMappingModel] `tfsdk:"field_mapping"` - VectorIndexName types.String `tfsdk:"vector_index_name"` +type openSearchServerlessConfigurationModel struct { + CollectionARN fwtypes.ARN `tfsdk:"collection_arn"` + FieldMapping fwtypes.ListNestedObjectValueOf[openSearchServerlessFieldMappingModel] `tfsdk:"field_mapping"` + VectorIndexName types.String `tfsdk:"vector_index_name"` } -type opensearchManagedClusterFieldMappingModel struct { +type openSearchServerlessFieldMappingModel struct { MetadataField types.String `tfsdk:"metadata_field"` TextField types.String `tfsdk:"text_field"` VectorField types.String `tfsdk:"vector_field"` diff --git a/website/docs/r/bedrockagent_knowledge_base.html.markdown b/website/docs/r/bedrockagent_knowledge_base.html.markdown index fc432ee79cd8..b35dcc14ef81 100644 --- a/website/docs/r/bedrockagent_knowledge_base.html.markdown +++ b/website/docs/r/bedrockagent_knowledge_base.html.markdown @@ -145,8 +145,8 @@ The following arguments are optional: The `knowledge_base_configuration` configuration block supports the following arguments: -* `kendra_knowledge_base_configuration` - (Optional) Configuration for Kendra knowledge base. See [`kendra_knowledge_base_configuration` block](#kendra_knowledge_base_configuration-block) for details. * `type` - (Required) Type of data that the data source is converted into for the knowledge base. Valid Values: `VECTOR`, `KENDRA`, `SQL`. +* `kendra_knowledge_base_configuration` - (Optional) Configuration for Kendra knowledge base. See [`kendra_knowledge_base_configuration` block](#kendra_knowledge_base_configuration-block) for details. * `vector_knowledge_base_configuration` - (Optional) Details about the embeddings model that'sused to convert the data source. See [`vector_knowledge_base_configuration` block](#vector_knowledge_base_configuration-block) for details. ### `kendra_knowledge_base_configuration` block @@ -200,29 +200,30 @@ The `s3_location` configuration block supports the following arguments: The `storage_configuration` configuration block supports the following arguments: * `type` - (Required) Vector store service in which the knowledge base is stored. Valid Values: `OPENSEARCH_SERVERLESS`, `OPENSEARCH_MANAGED_CLUSTER`, `PINECONE`, `REDIS_ENTERPRISE_CLOUD`, `RDS`. -* `opensearch_serverless_configuration` - (Optional) The storage configuration of the knowledge base in Amazon OpenSearch Service Serverless. See [`opensearch_serverless_configuration` block](#opensearch_serverless_configuration-block) for details. * `opensearch_managed_cluster_configuration` - (Optional) The storage configuration of the knowledge base in Amazon OpenSearch Service Managed Cluster. See [`opensearch_managed_cluster_configuration` block](#opensearch_managed_cluster_configuration-block) for details. +* `opensearch_serverless_configuration` - (Optional) The storage configuration of the knowledge base in Amazon OpenSearch Service Serverless. See [`opensearch_serverless_configuration` block](#opensearch_serverless_configuration-block) for details. * `pinecone_configuration` - (Optional) The storage configuration of the knowledge base in Pinecone. See [`pinecone_configuration` block](#pinecone_configuration-block) for details. * `rds_configuration` - (Optional) Details about the storage configuration of the knowledge base in Amazon RDS. For more information, see [Create a vector index in Amazon RDS](https://docs.aws.amazon.com/bedrock/latest/userguide/knowledge-base-setup.html). See [`rds_configuration` block](#rds_configuration-block) for details. * `redis_enterprise_cloud_configuration` - (Optional) The storage configuration of the knowledge base in Redis Enterprise Cloud. See [`redis_enterprise_cloud_configuration` block](#redis_enterprise_cloud_configuration-block) for details. -### `opensearch_serverless_configuration` block -The `opensearch_serverless_configuration` configuration block supports the following arguments: +### `opensearch_managed_cluster_configuration` block -* `collection_arn` - (Required) ARN of the OpenSearch Service vector store. +The `opensearch_managed_cluster_configuration` configuration block supports the following arguments: + +* `domain_arn` - (Required) ARN of the OpenSearch domain. +* `domain_endpoint` - (Required) Endpoint URL of the OpenSearch domain. * `field_mapping` - (Required) The names of the fields to which to map information about the vector store. This block supports the following arguments: * `metadata_field` - (Required) Name of the field in which Amazon Bedrock stores metadata about the vector store. * `text_field` - (Required) Name of the field in which Amazon Bedrock stores the raw text from your data. The text is split according to the chunking strategy you choose. * `vector_field` - (Required) Name of the field in which Amazon Bedrock stores the vector embeddings for your data sources. * `vector_index_name` - (Required) Name of the vector store. -### `opensearch_managed_cluster_configuration` block +### `opensearch_serverless_configuration` block -The `opensearch_managed_cluster_configuration` configuration block supports the following arguments: +The `opensearch_serverless_configuration` configuration block supports the following arguments: -* `domain_arn` - (Required) ARN of the OpenSearch domain. -* `domain_endpoint` - (Required) Endpoint URL of the OpenSearch domain. +* `collection_arn` - (Required) ARN of the OpenSearch Service vector store. * `field_mapping` - (Required) The names of the fields to which to map information about the vector store. This block supports the following arguments: * `metadata_field` - (Required) Name of the field in which Amazon Bedrock stores metadata about the vector store. * `text_field` - (Required) Name of the field in which Amazon Bedrock stores the raw text from your data. The text is split according to the chunking strategy you choose. From 81b9e2af67bb12cea023f85f774b30f823647a8a Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Fri, 5 Dec 2025 12:18:59 -0500 Subject: [PATCH 18/65] r/aws_bedrockagent_knowledge_base: Tidy up. --- .../service/bedrockagent/knowledge_base.go | 48 +++++++++++-------- 1 file changed, 27 insertions(+), 21 deletions(-) diff --git a/internal/service/bedrockagent/knowledge_base.go b/internal/service/bedrockagent/knowledge_base.go index 63b2ac7b3dd2..f998d72e69ca 100644 --- a/internal/service/bedrockagent/knowledge_base.go +++ b/internal/service/bedrockagent/knowledge_base.go @@ -626,8 +626,8 @@ func (r *knowledgeBaseResource) Create(ctx context.Context, request resource.Cre conn := r.Meta().BedrockAgentClient(ctx) - input := &bedrockagent.CreateKnowledgeBaseInput{} - response.Diagnostics.Append(fwflex.Expand(ctx, data, input)...) + var input bedrockagent.CreateKnowledgeBaseInput + response.Diagnostics.Append(fwflex.Expand(ctx, data, &input)...) if response.Diagnostics.HasError() { return } @@ -639,7 +639,7 @@ func (r *knowledgeBaseResource) Create(ctx context.Context, request resource.Cre var output *bedrockagent.CreateKnowledgeBaseOutput var err error err = tfresource.Retry(ctx, propagationTimeout, func(ctx context.Context) *tfresource.RetryError { - output, err = conn.CreateKnowledgeBase(ctx, input) + output, err = conn.CreateKnowledgeBase(ctx, &input) // IAM propagation if tfawserr.ErrMessageContains(err, errCodeValidationException, "cannot assume role") { @@ -667,13 +667,14 @@ func (r *knowledgeBaseResource) Create(ctx context.Context, request resource.Cre } kb := output.KnowledgeBase + knowledgeBaseID := aws.ToString(kb.KnowledgeBaseId) data.KnowledgeBaseARN = fwflex.StringToFramework(ctx, kb.KnowledgeBaseArn) - data.KnowledgeBaseID = fwflex.StringToFramework(ctx, kb.KnowledgeBaseId) + data.KnowledgeBaseID = fwflex.StringValueToFramework(ctx, knowledgeBaseID) - kb, err = waitKnowledgeBaseCreated(ctx, conn, data.KnowledgeBaseID.ValueString(), r.CreateTimeout(ctx, data.Timeouts)) + kb, err = waitKnowledgeBaseCreated(ctx, conn, knowledgeBaseID, r.CreateTimeout(ctx, data.Timeouts)) if err != nil { - response.Diagnostics.AddError(fmt.Sprintf("waiting for Bedrock Agent Knowledge Base (%s) create", data.KnowledgeBaseID.ValueString()), err.Error()) + response.Diagnostics.AddError(fmt.Sprintf("waiting for Bedrock Agent Knowledge Base (%s) create", knowledgeBaseID), err.Error()) return } @@ -694,7 +695,8 @@ func (r *knowledgeBaseResource) Read(ctx context.Context, request resource.ReadR conn := r.Meta().BedrockAgentClient(ctx) - kb, err := findKnowledgeBaseByID(ctx, conn, data.KnowledgeBaseID.ValueString()) + knowledgeBaseID := fwflex.StringValueFromFramework(ctx, data.KnowledgeBaseID) + kb, err := findKnowledgeBaseByID(ctx, conn, knowledgeBaseID) if tfresource.NotFound(err) { response.Diagnostics.Append(fwdiag.NewResourceNotFoundWarningDiagnostic(err)) @@ -704,7 +706,7 @@ func (r *knowledgeBaseResource) Read(ctx context.Context, request resource.ReadR } if err != nil { - response.Diagnostics.AddError(fmt.Sprintf("reading Bedrock Agent Knowledge Base (%s)", data.KnowledgeBaseID.ValueString()), err.Error()) + response.Diagnostics.AddError(fmt.Sprintf("reading Bedrock Agent Knowledge Base (%s)", knowledgeBaseID), err.Error()) return } @@ -733,26 +735,27 @@ func (r *knowledgeBaseResource) Update(ctx context.Context, request resource.Upd if !new.Description.Equal(old.Description) || !new.Name.Equal(old.Name) || !new.RoleARN.Equal(old.RoleARN) { - input := &bedrockagent.UpdateKnowledgeBaseInput{} - response.Diagnostics.Append(fwflex.Expand(ctx, new, input)...) + knowledgeBaseID := fwflex.StringValueFromFramework(ctx, new.KnowledgeBaseID) + var input bedrockagent.UpdateKnowledgeBaseInput + response.Diagnostics.Append(fwflex.Expand(ctx, new, &input)...) if response.Diagnostics.HasError() { return } _, err := tfresource.RetryWhenAWSErrMessageContains(ctx, propagationTimeout, func(ctx context.Context) (any, error) { - return conn.UpdateKnowledgeBase(ctx, input) + return conn.UpdateKnowledgeBase(ctx, &input) }, errCodeValidationException, "cannot assume role") if err != nil { - response.Diagnostics.AddError(fmt.Sprintf("updating Bedrock Agent Knowledge Base (%s)", new.KnowledgeBaseID.ValueString()), err.Error()) + response.Diagnostics.AddError(fmt.Sprintf("updating Bedrock Agent Knowledge Base (%s)", knowledgeBaseID), err.Error()) return } - kb, err := waitKnowledgeBaseUpdated(ctx, conn, new.KnowledgeBaseID.ValueString(), r.UpdateTimeout(ctx, new.Timeouts)) + kb, err := waitKnowledgeBaseUpdated(ctx, conn, knowledgeBaseID, r.UpdateTimeout(ctx, new.Timeouts)) if err != nil { - response.Diagnostics.AddError(fmt.Sprintf("waiting for Bedrock Agent Knowledge Base (%s) create", new.KnowledgeBaseID.ValueString()), err.Error()) + response.Diagnostics.AddError(fmt.Sprintf("waiting for Bedrock Agent Knowledge Base (%s) update", knowledgeBaseID), err.Error()) return } @@ -776,8 +779,9 @@ func (r *knowledgeBaseResource) Delete(ctx context.Context, request resource.Del conn := r.Meta().BedrockAgentClient(ctx) + knowledgeBaseID := fwflex.StringValueFromFramework(ctx, data.KnowledgeBaseID) input := bedrockagent.DeleteKnowledgeBaseInput{ - KnowledgeBaseId: data.KnowledgeBaseID.ValueStringPointer(), + KnowledgeBaseId: aws.String(knowledgeBaseID), } _, err := conn.DeleteKnowledgeBase(ctx, &input) @@ -786,15 +790,13 @@ func (r *knowledgeBaseResource) Delete(ctx context.Context, request resource.Del } if err != nil { - response.Diagnostics.AddError(fmt.Sprintf("deleting Bedrock Agent Knowledge Base (%s)", data.KnowledgeBaseID.ValueString()), err.Error()) + response.Diagnostics.AddError(fmt.Sprintf("deleting Bedrock Agent Knowledge Base (%s)", knowledgeBaseID), err.Error()) return } - _, err = waitKnowledgeBaseDeleted(ctx, conn, data.KnowledgeBaseID.ValueString(), r.DeleteTimeout(ctx, data.Timeouts)) - - if err != nil { - response.Diagnostics.AddError(fmt.Sprintf("waiting for Bedrock Agent Knowledge Base (%s) delete", data.KnowledgeBaseID.ValueString()), err.Error()) + if _, err := waitKnowledgeBaseDeleted(ctx, conn, knowledgeBaseID, r.DeleteTimeout(ctx, data.Timeouts)); err != nil { + response.Diagnostics.AddError(fmt.Sprintf("waiting for Bedrock Agent Knowledge Base (%s) delete", knowledgeBaseID), err.Error()) return } @@ -874,10 +876,14 @@ func statusKnowledgeBase(ctx context.Context, conn *bedrockagent.Client, id stri } func findKnowledgeBaseByID(ctx context.Context, conn *bedrockagent.Client, id string) (*awstypes.KnowledgeBase, error) { - input := &bedrockagent.GetKnowledgeBaseInput{ + input := bedrockagent.GetKnowledgeBaseInput{ KnowledgeBaseId: aws.String(id), } + return findKnowledgeBase(ctx, conn, &input) +} + +func findKnowledgeBase(ctx context.Context, conn *bedrockagent.Client, input *bedrockagent.GetKnowledgeBaseInput) (*awstypes.KnowledgeBase, error) { output, err := conn.GetKnowledgeBase(ctx, input) if errs.IsA[*awstypes.ResourceNotFoundException](err) { From 64241a64e6a2e65e6ec3f0f4c6f3fb32137d6bf2 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Fri, 5 Dec 2025 12:21:33 -0500 Subject: [PATCH 19/65] Tweak #44060's CHANGELOG entries. --- .changelog/44060.txt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.changelog/44060.txt b/.changelog/44060.txt index 999abda73ccc..dd0f56f7a5a3 100644 --- a/.changelog/44060.txt +++ b/.changelog/44060.txt @@ -1,3 +1,3 @@ ```release-note:enhancement -resource/aws_bedrockagent_knowledge_base: Add support for OpenSearch managed clusters in `storage_configuration` -``` +resource/aws_bedrockagent_knowledge_base: Add `storage_configuration.opensearch_managed_cluster_configuration` argument +``` \ No newline at end of file From 83fa8ac1df3020dd832f4a3d037cea753381e0aa Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Fri, 5 Dec 2025 14:27:03 -0500 Subject: [PATCH 20/65] Tidy up 'testAccKnowledgeBase_Kendra_basic'. --- docs/acc-test-environment-variables.md | 1 + .../service/bedrockagent/knowledge_base.go | 5 ++ .../bedrockagent/knowledge_base_test.go | 81 +++++++++---------- 3 files changed, 45 insertions(+), 42 deletions(-) diff --git a/docs/acc-test-environment-variables.md b/docs/acc-test-environment-variables.md index 6d50e00f87bb..6a2444a91ebf 100644 --- a/docs/acc-test-environment-variables.md +++ b/docs/acc-test-environment-variables.md @@ -110,6 +110,7 @@ Environment variables (beyond standard AWS Go SDK ones) used by acceptance testi | `TF_AWS_CONTROLTOWER_CONTROL_OU_NAME` | Organizational unit name to be targeted by the Control Tower control. | | `TF_AWS_CONTROLTOWER_BASELINE_ENABLE_BASELINE_ARN` | Enable baseline ARN. | | `TF_AWS_DATAEXCHANGE_DATA_SET_ID` | ID of DataExchange Data Set to use for testing. | +| `TF_AWS_KENDRA_INDEX_ARN` | ARN of Kendra Index to use for testing. | | `TF_AWS_LICENSE_MANAGER_GRANT_HOME_REGION` | Region where a License Manager license is imported. | | `TF_AWS_LICENSE_MANAGER_GRANT_LICENSE_ARN` | ARN for a License Manager license imported into the current account. | | `TF_AWS_LICENSE_MANAGER_GRANT_PRINCIPAL` | ARN of a principal to share the License Manager license with. Either a root user, Organization, or Organizational Unit. | diff --git a/internal/service/bedrockagent/knowledge_base.go b/internal/service/bedrockagent/knowledge_base.go index f998d72e69ca..280a12f91fb2 100644 --- a/internal/service/bedrockagent/knowledge_base.go +++ b/internal/service/bedrockagent/knowledge_base.go @@ -649,6 +649,11 @@ func (r *knowledgeBaseResource) Create(ctx context.Context, request resource.Cre return tfresource.RetryableError(err) } + // Kendra access propagation + if tfawserr.ErrMessageContains(err, errCodeValidationException, "Encountered AccessDeniedException from Kendra") { + return tfresource.RetryableError(err) + } + // OpenSearch data access propagation if tfawserr.ErrMessageContains(err, errCodeValidationException, "storage configuration provided is invalid") { return tfresource.RetryableError(err) diff --git a/internal/service/bedrockagent/knowledge_base_test.go b/internal/service/bedrockagent/knowledge_base_test.go index 80fd07e19f98..547a1481f493 100644 --- a/internal/service/bedrockagent/knowledge_base_test.go +++ b/internal/service/bedrockagent/knowledge_base_test.go @@ -10,7 +10,7 @@ import ( "strconv" "testing" - "github.com/aws/aws-sdk-go-v2/service/bedrockagent/types" + awstypes "github.com/aws/aws-sdk-go-v2/service/bedrockagent/types" sdkacctest "github.com/hashicorp/terraform-plugin-testing/helper/acctest" "github.com/hashicorp/terraform-plugin-testing/helper/resource" "github.com/hashicorp/terraform-plugin-testing/knownvalue" @@ -19,6 +19,7 @@ import ( "github.com/hashicorp/terraform-plugin-testing/terraform" "github.com/hashicorp/terraform-plugin-testing/tfjsonpath" "github.com/hashicorp/terraform-provider-aws/internal/acctest" + tfknownvalue "github.com/hashicorp/terraform-provider-aws/internal/acctest/knownvalue" "github.com/hashicorp/terraform-provider-aws/internal/conns" tfbedrockagent "github.com/hashicorp/terraform-provider-aws/internal/service/bedrockagent" "github.com/hashicorp/terraform-provider-aws/internal/tfresource" @@ -34,7 +35,7 @@ func testAccKnowledgeBase_basic(t *testing.T) { acctest.SkipIfExeNotOnPath(t, "aws") ctx := acctest.Context(t) - var knowledgebase types.KnowledgeBase + var knowledgebase awstypes.KnowledgeBase rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) resourceName := "aws_bedrockagent_knowledge_base.test" foundationModel := "amazon.titan-embed-text-v1" @@ -125,7 +126,7 @@ func testAccKnowledgeBase_disappears(t *testing.T) { acctest.SkipIfExeNotOnPath(t, "aws") ctx := acctest.Context(t) - var knowledgebase types.KnowledgeBase + var knowledgebase awstypes.KnowledgeBase rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) resourceName := "aws_bedrockagent_knowledge_base.test" foundationModel := "amazon.titan-embed-text-v1" @@ -165,7 +166,7 @@ func testAccKnowledgeBase_tags(t *testing.T) { acctest.SkipIfExeNotOnPath(t, "aws") ctx := acctest.Context(t) - var knowledgebase types.KnowledgeBase + var knowledgebase awstypes.KnowledgeBase rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) resourceName := "aws_bedrockagent_knowledge_base.test" foundationModel := "amazon.titan-embed-text-v1" @@ -246,7 +247,7 @@ func testAccKnowledgeBase_OpenSearch_basic(t *testing.T) { ctx := acctest.Context(t) collectionName := skipIfOSSCollectionNameEnvVarNotSet(t) - var knowledgebase types.KnowledgeBase + var knowledgebase awstypes.KnowledgeBase rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) resourceName := "aws_bedrockagent_knowledge_base.test" foundationModel := "amazon.titan-embed-text-v2:0" @@ -290,7 +291,7 @@ func testAccKnowledgeBase_OpenSearch_update(t *testing.T) { ctx := acctest.Context(t) collectionName := skipIfOSSCollectionNameEnvVarNotSet(t) - var knowledgebase types.KnowledgeBase + var knowledgebase awstypes.KnowledgeBase rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) resourceName := "aws_bedrockagent_knowledge_base.test" foundationModel := "amazon.titan-embed-text-v2:0" @@ -360,7 +361,7 @@ func testAccKnowledgeBase_OpenSearch_supplementalDataStorage(t *testing.T) { ctx := acctest.Context(t) collectionName := skipIfOSSCollectionNameEnvVarNotSet(t) - var knowledgebase types.KnowledgeBase + var knowledgebase awstypes.KnowledgeBase rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) resourceName := "aws_bedrockagent_knowledge_base.test" foundationModel := "amazon.titan-embed-text-v2:0" @@ -406,28 +407,37 @@ func testAccKnowledgeBase_OpenSearch_supplementalDataStorage(t *testing.T) { func testAccKnowledgeBase_Kendra_basic(t *testing.T) { ctx := acctest.Context(t) - kendraIndexArn := skipIfKendraIndexARNEnvVarNotSet(t) - - var knowledgebase types.KnowledgeBase + var knowledgebase awstypes.KnowledgeBase rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) resourceName := "aws_bedrockagent_knowledge_base.test" + // Index should be created with the "GEN_AI_ENTERPRISE_EDITION" edition and be "ACTIVE". + kendraIndexARN := acctest.SkipIfEnvVarNotSet(t, "TF_AWS_KENDRA_INDEX_ARN") resource.Test(t, resource.TestCase{ - PreCheck: func() { - acctest.PreCheck(ctx, t) - }, + PreCheck: func() { acctest.PreCheck(ctx, t) }, ErrorCheck: acctest.ErrorCheck(t, names.BedrockAgentServiceID), ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, CheckDestroy: testAccCheckKnowledgeBaseDestroy(ctx), Steps: []resource.TestStep{ { - Config: testAccKnowledgeBaseConfig_Kendra_basic(rName, kendraIndexArn), + Config: testAccKnowledgeBaseConfig_Kendra_basic(rName, kendraIndexARN), Check: resource.ComposeTestCheckFunc( testAccCheckKnowledgeBaseExists(ctx, resourceName, &knowledgebase), - resource.TestCheckResourceAttr(resourceName, "knowledge_base_configuration.#", "1"), - resource.TestCheckResourceAttr(resourceName, "knowledge_base_configuration.0.kendra_knowledge_base_configuration.#", "1"), - resource.TestCheckResourceAttr(resourceName, "knowledge_base_configuration.0.type", "KENDRA"), ), + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + }, + }, + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("knowledge_base_configuration"), knownvalue.ListExact([]knownvalue.Check{ + knownvalue.MapExact(map[string]knownvalue.Check{ + "kendra_knowledge_base_configuration": knownvalue.ListSizeExact(1), + names.AttrType: tfknownvalue.StringExact(awstypes.KnowledgeBaseTypeKendra), + "vector_knowledge_base_configuration": knownvalue.ListSizeExact(0), + }), + })), + }, }, }, }) @@ -440,7 +450,7 @@ func TestAccBedrockAgentKnowledgeBase_OpenSearchManagedCluster_basic(t *testing. ctx := acctest.Context(t) - var knowledgebase types.KnowledgeBase + var knowledgebase awstypes.KnowledgeBase rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) resourceName := "aws_bedrockagent_knowledge_base.test" foundationModel := "amazon.titan-embed-text-v2:0" @@ -525,7 +535,7 @@ func testAccCheckKnowledgeBaseDestroy(ctx context.Context) resource.TestCheckFun } } -func testAccCheckKnowledgeBaseExists(ctx context.Context, n string, v *types.KnowledgeBase) resource.TestCheckFunc { +func testAccCheckKnowledgeBaseExists(ctx context.Context, n string, v *awstypes.KnowledgeBase) resource.TestCheckFunc { return func(s *terraform.State) error { rs, ok := s.RootModule().Resources[n] if !ok { @@ -583,26 +593,6 @@ func skipIfOSSCollectionNameEnvVarNotSet(t *testing.T) string { return v } -// skipIfKendraIndexARNEnvVarNotSet handles skipping tests when an environment -// variable providing a valid Kendra index ARN is unset -// -// This should be called in all acceptance tests currently dependent on a Kendra index. -// -// To create a Kendra index to be used with this environment variable: -// 1. In the AWS console, navigate to Amazon Kendra -// 2. Create a new index with "GEN_AI_ENTERPRISE_EDITION" edition -// 3. Wait for the index to be in "ACTIVE" status (this can take 20+ minutes) -// 4. Copy the index ARN and set it as the TF_AWS_KENDRA_INDEX_ARN environment variable -func skipIfKendraIndexARNEnvVarNotSet(t *testing.T) string { - t.Helper() - v := os.Getenv("TF_AWS_KENDRA_INDEX_ARN") - if v == "" { - acctest.Skip(t, "This test requires a pre-existing Kendra index. "+ - "Set the TF_AWS_KENDRA_INDEX_ARN environment variable to the ARN of an existing Kendra index.") - } - return v -} - func testAccKnowledgeBaseConfig_basicRDS(rName, model, description string) string { if description == "" { description = "null" @@ -1067,8 +1057,10 @@ func testAccKnowledgeBaseConfig_Kendra_basic(rName, kendraIndexArn string) strin data "aws_caller_identity" "current" {} data "aws_region" "current" {} data "aws_partition" "current" {} + resource "aws_iam_role" "test" { name = %[1]q + assume_role_policy = jsonencode({ Version = "2012-10-17" Statement = [ @@ -1090,9 +1082,11 @@ resource "aws_iam_role" "test" { ] }) } + resource "aws_iam_role_policy" "test" { name = "%[1]s-bedrock" role = aws_iam_role.test.id + policy = jsonencode({ Version = "2012-10-17" Statement = [ @@ -1107,16 +1101,19 @@ resource "aws_iam_role_policy" "test" { ] }) } + resource "aws_bedrockagent_knowledge_base" "test" { - name = %[1]q - role_arn = aws_iam_role.test.arn - depends_on = [aws_iam_role_policy.test] + name = %[1]q + role_arn = aws_iam_role.test.arn + knowledge_base_configuration { type = "KENDRA" kendra_knowledge_base_configuration { kendra_index_arn = %[2]q } } + + depends_on = [aws_iam_role_policy.test] } `, rName, kendraIndexArn) } From 9a688c66625f0b9e8646737403fd25b42181b1b8 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Fri, 5 Dec 2025 14:27:47 -0500 Subject: [PATCH 21/65] Acceptance test output: MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit % TF_AWS_KENDRA_INDEX_ARN=arn:aws:kendra:us-west-2:123456789012:index/d1aff557-e6b1-4ce9-87d1-734f005c6a19 make testacc TESTARGS='-run=TestAccBedrockAgent_serial/KnowledgeBase/KendraBasic' PKG=bedrockagent make: Verifying source code with gofmt... ==> Checking that code complies with gofmt requirements... make: Running acceptance tests on branch: 🌿 f-aws_bedrockagent_knowledge_base-enhancements 🌿... TF_ACC=1 go1.24.11 test ./internal/service/bedrockagent/... -v -count 1 -parallel 20 -run=TestAccBedrockAgent_serial/KnowledgeBase/KendraBasic -timeout 360m -vet=off 2025/12/05 14:25:11 Creating Terraform AWS Provider (SDKv2-style)... 2025/12/05 14:25:11 Initializing Terraform AWS Provider (SDKv2-style)... === RUN TestAccBedrockAgent_serial === PAUSE TestAccBedrockAgent_serial === CONT TestAccBedrockAgent_serial === RUN TestAccBedrockAgent_serial/KnowledgeBase === RUN TestAccBedrockAgent_serial/KnowledgeBase/KendraBasic --- PASS: TestAccBedrockAgent_serial (25.71s) --- PASS: TestAccBedrockAgent_serial/KnowledgeBase (25.71s) --- PASS: TestAccBedrockAgent_serial/KnowledgeBase/KendraBasic (25.71s) PASS ok github.com/hashicorp/terraform-provider-aws/internal/service/bedrockagent 31.073s From 92431592248f387e75c2f159188bce4866c38057 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Fri, 5 Dec 2025 16:18:24 -0500 Subject: [PATCH 22/65] 'TestAccBedrockAgentKnowledgeBase_OpenSearchManagedCluster_basic' -> 'testAccKnowledgeBase_OpenSearchManagedCluster_basic'. --- .../service/bedrockagent/bedrockagent_test.go | 1 + .../bedrockagent/knowledge_base_test.go | 142 ++++++++++-------- 2 files changed, 84 insertions(+), 59 deletions(-) diff --git a/internal/service/bedrockagent/bedrockagent_test.go b/internal/service/bedrockagent/bedrockagent_test.go index 5581a9685a17..3ee0f0de6261 100644 --- a/internal/service/bedrockagent/bedrockagent_test.go +++ b/internal/service/bedrockagent/bedrockagent_test.go @@ -21,6 +21,7 @@ func TestAccBedrockAgent_serial(t *testing.T) { "OpenSearchUpdate": testAccKnowledgeBase_OpenSearch_update, "OpenSearchSupplementalDataStorage": testAccKnowledgeBase_OpenSearch_supplementalDataStorage, "KendraBasic": testAccKnowledgeBase_Kendra_basic, + "OpenSearchManagedClusterBasic": testAccKnowledgeBase_OpenSearchManagedCluster_basic, }, "DataSource": { acctest.CtBasic: testAccDataSource_basic, diff --git a/internal/service/bedrockagent/knowledge_base_test.go b/internal/service/bedrockagent/knowledge_base_test.go index 547a1481f493..8ad55b479acb 100644 --- a/internal/service/bedrockagent/knowledge_base_test.go +++ b/internal/service/bedrockagent/knowledge_base_test.go @@ -443,18 +443,12 @@ func testAccKnowledgeBase_Kendra_basic(t *testing.T) { }) } -func TestAccBedrockAgentKnowledgeBase_OpenSearchManagedCluster_basic(t *testing.T) { - if testing.Short() { - t.Skip("skipping long-running test in short mode") - } - +func testAccKnowledgeBase_OpenSearchManagedCluster_basic(t *testing.T) { ctx := acctest.Context(t) - var knowledgebase awstypes.KnowledgeBase rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) resourceName := "aws_bedrockagent_knowledge_base.test" foundationModel := "amazon.titan-embed-text-v2:0" - testExternalProviders := map[string]resource.ExternalProvider{ "opensearch": { Source: "opensearch-project/opensearch", @@ -1118,46 +1112,8 @@ resource "aws_bedrockagent_knowledge_base" "test" { `, rName, kendraIndexArn) } -func testAccKnowledgeBaseConfig_OpenSearchManagedCluster_basic(rName, model string) string { - return acctest.ConfigCompose( - testAccKnowledgeBaseConfig_OpenSearchManagedCluster(rName, model), - fmt.Sprintf(` -resource "aws_bedrockagent_knowledge_base" "test" { - name = %[1]q - role_arn = aws_iam_role.bedrock_kb_role.arn - knowledge_base_configuration { - vector_knowledge_base_configuration { - embedding_model_arn = "arn:${data.aws_partition.current.partition}:bedrock:${data.aws_region.current.region}::foundation-model/%[2]s" - } - type = "VECTOR" - } - storage_configuration { - type = "OPENSEARCH_MANAGED_CLUSTER" - opensearch_managed_cluster_configuration { - domain_arn = aws_opensearch_domain.knowledge_base.arn - domain_endpoint = "https://${aws_opensearch_domain.knowledge_base.endpoint}" - vector_index_name = "knowledge-index" - field_mapping { - vector_field = "vector_embedding" - text_field = "text" - metadata_field = "metadata" - } - } - } - depends_on = [ - aws_opensearch_domain.knowledge_base, - opensearch_index.vector_index, - opensearch_roles_mapping.mapper, - aws_iam_role_policy_attachment.opensearch_access, - aws_iam_role_policy_attachment.bedrock_models_access, - ] -} -`, rName, model)) -} - -func testAccKnowledgeBaseConfig_OpenSearchManagedCluster(rName, model string) string { - return acctest.ConfigCompose( - fmt.Sprintf(` +func testAccKnowledgeBaseConfig_baseOpenSearchManagedCluster(rName, model string) string { + return fmt.Sprintf(` terraform { required_providers { opensearch = { @@ -1170,12 +1126,14 @@ terraform { } } } + data "aws_partition" "current" {} data "aws_region" "current" {} data "aws_caller_identity" "current" {} data "aws_iam_role" "opensearch" { name = "AWSServiceRoleForAmazonOpenSearchService" } + resource "aws_iam_role" "bedrock_kb_role" { name = %[1]q @@ -1200,8 +1158,9 @@ resource "aws_iam_role" "bedrock_kb_role" { ] }) } + resource "aws_iam_policy" "bedrock_models_access" { - name = "bedrock-%[1]s" + name = "bedrock-%[1]s" description = "IAM policy for Amazon Bedrock to access embedding models" policy = jsonencode({ @@ -1234,8 +1193,9 @@ resource "aws_iam_policy" "bedrock_models_access" { ] }) } + resource "aws_iam_policy" "opensearch_access" { - name = "os-%[1]s" + name = "os-%[1]s" description = "IAM policy for Amazon Bedrock to access OpenSearch domain" policy = jsonencode({ @@ -1266,14 +1226,17 @@ resource "aws_iam_policy" "opensearch_access" { ] }) } + resource "aws_iam_role_policy_attachment" "bedrock_models_access" { role = aws_iam_role.bedrock_kb_role.name policy_arn = aws_iam_policy.bedrock_models_access.arn } + resource "aws_iam_role_policy_attachment" "opensearch_access" { role = aws_iam_role.bedrock_kb_role.name policy_arn = aws_iam_policy.opensearch_access.arn } + resource "random_password" "opensearch_master" { length = 16 special = true @@ -1282,41 +1245,48 @@ resource "random_password" "opensearch_master" { min_special = 1 min_upper = 1 override_special = "!#$&*()-_=+" - + # Don't replace the password on each apply lifecycle { ignore_changes = [length, special, override_special] } } + resource "aws_opensearch_domain" "knowledge_base" { domain_name = substr(%[1]q, 0, 28) - engine_version = "OpenSearch_3.1" + engine_version = "OpenSearch_3.1" access_policies = local.opensearch_access_policy + cluster_config { instance_type = "or2.medium.search" instance_count = 1 zone_awareness_enabled = false dedicated_master_enabled = false } + # Configure EBS volumes for the data nodes ebs_options { ebs_enabled = true volume_size = 20 volume_type = "gp3" } + # Enable encryption at rest encrypt_at_rest { enabled = true } + # Enable node to node encryption node_to_node_encryption { enabled = true } + # Configure domain endpoint options domain_endpoint_options { enforce_https = true tls_security_policy = "Policy-Min-TLS-1-2-PFS-2023-10" } + # Configure advanced security options advanced_security_options { enabled = true @@ -1326,19 +1296,23 @@ resource "aws_opensearch_domain" "knowledge_base" { master_user_password = random_password.opensearch_master.result } } + # Auto-Tune options auto_tune_options { desired_state = "ENABLED" } + # Software update options software_update_options { auto_software_update_enabled = true } + # This is required to reference the existing service-linked role depends_on = [ data.aws_iam_role.opensearch ] } + locals { opensearch_access_policy = jsonencode({ Version = "2012-10-17" @@ -1354,37 +1328,45 @@ locals { ] }) } + provider "opensearch" { - url = "https://${aws_opensearch_domain.knowledge_base.endpoint}" - username = "admin" - password = random_password.opensearch_master.result - insecure = false - aws_region = data.aws_region.current.region - healthcheck = false - sniff = false - sign_aws_requests = false + url = "https://${aws_opensearch_domain.knowledge_base.endpoint}" + username = "admin" + password = random_password.opensearch_master.result + insecure = false + aws_region = data.aws_region.current.region + healthcheck = false + sniff = false + sign_aws_requests = false } + resource "opensearch_role" "os_kb_role" { role_name = "kb-%[1]s" description = "Knowledge Base Role" + cluster_permissions = ["*"] + index_permissions { index_patterns = ["*"] allowed_actions = ["*"] } + tenant_permissions { tenant_patterns = ["*"] allowed_actions = ["*"] } } + resource "opensearch_roles_mapping" "mapper" { role_name = opensearch_role.os_kb_role.role_name description = "Mapping AWS IAM roles to ES role" + backend_roles = [ aws_iam_role.bedrock_kb_role.arn, data.aws_caller_identity.current.arn ] } + resource "opensearch_index" "vector_index" { name = "knowledge-index" number_of_shards = "5" @@ -1421,7 +1403,49 @@ resource "opensearch_index" "vector_index" { lifecycle { ignore_changes = [ mappings ] } + depends_on = [ aws_opensearch_domain.knowledge_base ] } +`, rName, model) +} + +func testAccKnowledgeBaseConfig_OpenSearchManagedCluster_basic(rName, model string) string { + return acctest.ConfigCompose(testAccKnowledgeBaseConfig_baseOpenSearchManagedCluster(rName, model), fmt.Sprintf(` +resource "aws_bedrockagent_knowledge_base" "test" { + name = %[1]q + role_arn = aws_iam_role.bedrock_kb_role.arn + + knowledge_base_configuration { + type = "VECTOR" + + vector_knowledge_base_configuration { + embedding_model_arn = "arn:${data.aws_partition.current.partition}:bedrock:${data.aws_region.current.region}::foundation-model/%[2]s" + } + } + + storage_configuration { + type = "OPENSEARCH_MANAGED_CLUSTER" + + opensearch_managed_cluster_configuration { + domain_arn = aws_opensearch_domain.knowledge_base.arn + domain_endpoint = "https://${aws_opensearch_domain.knowledge_base.endpoint}" + vector_index_name = "knowledge-index" + + field_mapping { + vector_field = "vector_embedding" + text_field = "text" + metadata_field = "metadata" + } + } + } + + depends_on = [ + aws_opensearch_domain.knowledge_base, + opensearch_index.vector_index, + opensearch_roles_mapping.mapper, + aws_iam_role_policy_attachment.opensearch_access, + aws_iam_role_policy_attachment.bedrock_models_access, + ] +} `, rName, model)) } From 13769064da747e3ce0c7ceb608e10c4292781c98 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Fri, 5 Dec 2025 16:34:23 -0500 Subject: [PATCH 23/65] Acceptance test output: MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit % make testacc TESTARGS='-run=TestAccBedrockAgent_serial/KnowledgeBase/OpenSearchManagedClusterBasic' PKG=bedrockagent make: Verifying source code with gofmt... ==> Checking that code complies with gofmt requirements... make: Running acceptance tests on branch: 🌿 f-aws_bedrockagent_knowledge_base-enhancements 🌿... TF_ACC=1 go1.24.11 test ./internal/service/bedrockagent/... -v -count 1 -parallel 20 -run=TestAccBedrockAgent_serial/KnowledgeBase/OpenSearchManagedClusterBasic -timeout 360m -vet=off 2025/12/05 15:19:13 Creating Terraform AWS Provider (SDKv2-style)... 2025/12/05 15:19:13 Initializing Terraform AWS Provider (SDKv2-style)... === RUN TestAccBedrockAgent_serial === PAUSE TestAccBedrockAgent_serial === CONT TestAccBedrockAgent_serial === RUN TestAccBedrockAgent_serial/KnowledgeBase === RUN TestAccBedrockAgent_serial/KnowledgeBase/OpenSearchManagedClusterBasic --- PASS: TestAccBedrockAgent_serial (1774.57s) --- PASS: TestAccBedrockAgent_serial/KnowledgeBase (1774.57s) --- PASS: TestAccBedrockAgent_serial/KnowledgeBase/OpenSearchManagedClusterBasic (1774.57s) PASS ok github.com/hashicorp/terraform-provider-aws/internal/service/bedrockagent 1779.976s From fdee938a06cfdd0b1413356bd96415f81e7fc7e3 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Fri, 5 Dec 2025 16:35:26 -0500 Subject: [PATCH 24/65] Fix markdown-lint 'MD012/no-multiple-blanks Multiple consecutive blank lines [Expected: 1; Actual: 2]'. --- website/docs/r/bedrockagent_knowledge_base.html.markdown | 1 - 1 file changed, 1 deletion(-) diff --git a/website/docs/r/bedrockagent_knowledge_base.html.markdown b/website/docs/r/bedrockagent_knowledge_base.html.markdown index b35dcc14ef81..5e1fa6f698dc 100644 --- a/website/docs/r/bedrockagent_knowledge_base.html.markdown +++ b/website/docs/r/bedrockagent_knowledge_base.html.markdown @@ -206,7 +206,6 @@ The `storage_configuration` configuration block supports the following arguments * `rds_configuration` - (Optional) Details about the storage configuration of the knowledge base in Amazon RDS. For more information, see [Create a vector index in Amazon RDS](https://docs.aws.amazon.com/bedrock/latest/userguide/knowledge-base-setup.html). See [`rds_configuration` block](#rds_configuration-block) for details. * `redis_enterprise_cloud_configuration` - (Optional) The storage configuration of the knowledge base in Redis Enterprise Cloud. See [`redis_enterprise_cloud_configuration` block](#redis_enterprise_cloud_configuration-block) for details. - ### `opensearch_managed_cluster_configuration` block The `opensearch_managed_cluster_configuration` configuration block supports the following arguments: From 9243ed77f482c27fe0fe8f8642fe18738d5dc03b Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Fri, 5 Dec 2025 16:41:52 -0500 Subject: [PATCH 25/65] Fix terrafmt errors. --- .../bedrockagent/knowledge_base_test.go | 20 +++++++++---------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/internal/service/bedrockagent/knowledge_base_test.go b/internal/service/bedrockagent/knowledge_base_test.go index 8ad55b479acb..b65443176886 100644 --- a/internal/service/bedrockagent/knowledge_base_test.go +++ b/internal/service/bedrockagent/knowledge_base_test.go @@ -1136,7 +1136,7 @@ data "aws_iam_role" "opensearch" { resource "aws_iam_role" "bedrock_kb_role" { name = %[1]q - + assume_role_policy = jsonencode({ Version = "2012-10-17" Statement = [ @@ -1150,9 +1150,6 @@ resource "aws_iam_role" "bedrock_kb_role" { StringEquals = { "aws:SourceAccount": data.aws_caller_identity.current.account_id }, - ArnLike = { - "aws:SourceArn": "arn:${data.aws_partition.current.partition}:bedrock:${data.aws_region.current.region}:${data.aws_caller_identity.current.account_id}:knowledge-base/*" - } } } ] @@ -1160,9 +1157,9 @@ resource "aws_iam_role" "bedrock_kb_role" { } resource "aws_iam_policy" "bedrock_models_access" { - name = "bedrock-%[1]s" + name. = "bedrock-%[1]s" description = "IAM policy for Amazon Bedrock to access embedding models" - + policy = jsonencode({ Version = "2012-10-17" Statement = [ @@ -1195,9 +1192,9 @@ resource "aws_iam_policy" "bedrock_models_access" { } resource "aws_iam_policy" "opensearch_access" { - name = "os-%[1]s" + name = "os-%[1]s" description = "IAM policy for Amazon Bedrock to access OpenSearch domain" - + policy = jsonencode({ Version = "2012-10-17" Statement = [ @@ -1217,7 +1214,7 @@ resource "aws_iam_policy" "opensearch_access" { Effect = "Allow" Action = [ "es:DescribeDomain", - "es:DescribeElasticsearchDomain" + "es:DescribeElasticsearchDomain" ] Resource = [ "*" @@ -1253,7 +1250,7 @@ resource "random_password" "opensearch_master" { } resource "aws_opensearch_domain" "knowledge_base" { - domain_name = substr(%[1]q, 0, 28) + domain_name = substr(%[1]q, 0, 28) engine_version = "OpenSearch_3.1" access_policies = local.opensearch_access_policy @@ -1291,6 +1288,7 @@ resource "aws_opensearch_domain" "knowledge_base" { advanced_security_options { enabled = true internal_user_database_enabled = true + master_user_options { master_user_name = "admin" master_user_password = random_password.opensearch_master.result @@ -1372,7 +1370,7 @@ resource "opensearch_index" "vector_index" { number_of_shards = "5" number_of_replicas = "1" index_knn = true - + # Mappings for Bedrock Knowledge Base compatibility mappings = jsonencode({ "properties": { From f943238fc66c282a8139aeb6e1ceb952acda50fd Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Fri, 5 Dec 2025 16:53:38 -0500 Subject: [PATCH 26/65] Fix providerlint 'AT004: provider declaration should be omitted'. --- internal/service/bedrockagent/knowledge_base_test.go | 1 + 1 file changed, 1 insertion(+) diff --git a/internal/service/bedrockagent/knowledge_base_test.go b/internal/service/bedrockagent/knowledge_base_test.go index b65443176886..867d37574908 100644 --- a/internal/service/bedrockagent/knowledge_base_test.go +++ b/internal/service/bedrockagent/knowledge_base_test.go @@ -1113,6 +1113,7 @@ resource "aws_bedrockagent_knowledge_base" "test" { } func testAccKnowledgeBaseConfig_baseOpenSearchManagedCluster(rName, model string) string { + // lintignore:AT004 return fmt.Sprintf(` terraform { required_providers { From bffb9f85c3c7ef7bbc3393cfb1323253dddaca79 Mon Sep 17 00:00:00 2001 From: tabito Date: Sat, 6 Dec 2025 11:25:48 +0900 Subject: [PATCH 27/65] Implement s3_vectors_configuration block --- .../service/bedrockagent/knowledge_base.go | 56 +++++++++++++++++++ 1 file changed, 56 insertions(+) diff --git a/internal/service/bedrockagent/knowledge_base.go b/internal/service/bedrockagent/knowledge_base.go index dfabab25bf3f..d22b0b8596ab 100644 --- a/internal/service/bedrockagent/knowledge_base.go +++ b/internal/service/bedrockagent/knowledge_base.go @@ -17,7 +17,9 @@ import ( "github.com/hashicorp/terraform-plugin-framework-timeouts/resource/timeouts" "github.com/hashicorp/terraform-plugin-framework-timetypes/timetypes" "github.com/hashicorp/terraform-plugin-framework-validators/listvalidator" + "github.com/hashicorp/terraform-plugin-framework-validators/objectvalidator" "github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator" + "github.com/hashicorp/terraform-plugin-framework/path" "github.com/hashicorp/terraform-plugin-framework/resource" "github.com/hashicorp/terraform-plugin-framework/resource/schema" "github.com/hashicorp/terraform-plugin-framework/resource/schema/listplanmodifier" @@ -496,6 +498,53 @@ func (r *knowledgeBaseResource) Schema(ctx context.Context, request resource.Sch }, }, }, + "s3_vectors_configuration": schema.ListNestedBlock{ + CustomType: fwtypes.NewListNestedObjectTypeOf[s3VectorsConfigurationModel](ctx), + Validators: []validator.List{ + listvalidator.SizeAtMost(1), + }, + PlanModifiers: []planmodifier.List{ + listplanmodifier.RequiresReplace(), + }, + NestedObject: schema.NestedBlockObject{ + Attributes: map[string]schema.Attribute{ + "index_arn": schema.StringAttribute{ + CustomType: fwtypes.ARNType, + Optional: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.RequiresReplace(), + }, + Validators: []validator.String{ + stringvalidator.ConflictsWith(path.MatchRelative().AtParent().AtName("index_name"), path.MatchRelative().AtParent().AtName("vector_bucket_arn")), + }, + }, + "index_name": schema.StringAttribute{ + Optional: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.RequiresReplace(), + }, + Validators: []validator.String{ + stringvalidator.AlsoRequires(path.MatchRelative().AtParent().AtName("vector_bucket_arn")), + stringvalidator.ConflictsWith(path.MatchRelative().AtParent().AtName("index_arn")), + }, + }, + "vector_bucket_arn": schema.StringAttribute{ + CustomType: fwtypes.ARNType, + Optional: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.RequiresReplace(), + }, + Validators: []validator.String{ + stringvalidator.AlsoRequires(path.MatchRelative().AtParent().AtName("index_name")), + stringvalidator.ConflictsWith(path.MatchRelative().AtParent().AtName("index_arn")), + }, + }, + }, + Validators: []validator.Object{ + objectvalidator.AtLeastOneOf(path.MatchRelative().AtName("index_arn"), path.MatchRelative().AtName("index_name")), + }, + }, + }, }, }, }, @@ -840,6 +889,7 @@ type storageConfigurationModel struct { PineconeConfiguration fwtypes.ListNestedObjectValueOf[pineconeConfigurationModel] `tfsdk:"pinecone_configuration"` RDSConfiguration fwtypes.ListNestedObjectValueOf[rdsConfigurationModel] `tfsdk:"rds_configuration"` RedisEnterpriseCloudConfiguration fwtypes.ListNestedObjectValueOf[redisEnterpriseCloudConfigurationModel] `tfsdk:"redis_enterprise_cloud_configuration"` + S3VectorsConfiguration fwtypes.ListNestedObjectValueOf[s3VectorsConfigurationModel] `tfsdk:"s3_vectors_configuration"` Type types.String `tfsdk:"type"` } @@ -895,3 +945,9 @@ type redisEnterpriseCloudFieldMappingModel struct { TextField types.String `tfsdk:"text_field"` VectorField types.String `tfsdk:"vector_field"` } + +type s3VectorsConfigurationModel struct { + IndexARN fwtypes.ARN `tfsdk:"index_arn"` + IndexName types.String `tfsdk:"index_name"` + VectorBucketARN fwtypes.ARN `tfsdk:"vector_bucket_arn"` +} From 876fefc4d36a5de68fc771129aeaa5f98021abbe Mon Sep 17 00:00:00 2001 From: tabito Date: Sat, 6 Dec 2025 11:52:48 +0900 Subject: [PATCH 28/65] Add an acceptance test for s3_vectors_configuration --- .../service/bedrockagent/bedrockagent_test.go | 1 + .../bedrockagent/knowledge_base_test.go | 198 ++++++++++++++++++ 2 files changed, 199 insertions(+) diff --git a/internal/service/bedrockagent/bedrockagent_test.go b/internal/service/bedrockagent/bedrockagent_test.go index ae39ed34b5c1..c0d81029d5d7 100644 --- a/internal/service/bedrockagent/bedrockagent_test.go +++ b/internal/service/bedrockagent/bedrockagent_test.go @@ -20,6 +20,7 @@ func TestAccBedrockAgent_serial(t *testing.T) { "OpenSearchBasic": testAccKnowledgeBase_OpenSearch_basic, "OpenSearchUpdate": testAccKnowledgeBase_OpenSearch_update, "OpenSearchSupplementalDataStorage": testAccKnowledgeBase_OpenSearch_supplementalDataStorage, + "S3Vectors": testAccKnowledgeBase_S3Vectors, }, "DataSource": { acctest.CtBasic: testAccDataSource_basic, diff --git a/internal/service/bedrockagent/knowledge_base_test.go b/internal/service/bedrockagent/knowledge_base_test.go index b12b4f9ecae4..2ca610e70f54 100644 --- a/internal/service/bedrockagent/knowledge_base_test.go +++ b/internal/service/bedrockagent/knowledge_base_test.go @@ -404,6 +404,69 @@ func testAccKnowledgeBase_OpenSearch_supplementalDataStorage(t *testing.T) { }) } +func testAccKnowledgeBase_S3Vectors(t *testing.T) { + ctx := acctest.Context(t) + + var knowledgebase types.KnowledgeBase + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + resourceName := "aws_bedrockagent_knowledge_base.test" + foundationModel := "amazon.titan-embed-text-v2:0" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { + acctest.PreCheck(ctx, t) + }, + ErrorCheck: acctest.ErrorCheck(t, names.BedrockAgentServiceID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckKnowledgeBaseDestroy(ctx), + Steps: []resource.TestStep{ + { + Config: testAccKnowledgeBaseConfig_S3VectorsByIndexARN(rName, foundationModel), + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + }, + }, + Check: resource.ComposeTestCheckFunc( + testAccCheckKnowledgeBaseExists(ctx, resourceName, &knowledgebase), + resource.TestCheckResourceAttrPair(resourceName, names.AttrRoleARN, "aws_iam_role.test", names.AttrARN), + resource.TestCheckResourceAttr(resourceName, "knowledge_base_configuration.#", "1"), + resource.TestCheckResourceAttr(resourceName, "knowledge_base_configuration.0.vector_knowledge_base_configuration.#", "1"), + resource.TestCheckResourceAttr(resourceName, "knowledge_base_configuration.0.type", "VECTOR"), + resource.TestCheckResourceAttr(resourceName, "storage_configuration.#", "1"), + resource.TestCheckResourceAttr(resourceName, "storage_configuration.0.type", "S3_VECTORS"), + resource.TestCheckResourceAttr(resourceName, "storage_configuration.0.s3_vectors_configuration.#", "1"), + resource.TestCheckResourceAttrPair(resourceName, "storage_configuration.0.s3_vectors_configuration.0.index_arn", "aws_s3vectors_index.test", "index_arn"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + Config: testAccKnowledgeBaseConfig_S3VectorsByIndexName(rName, foundationModel), + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionDestroyBeforeCreate), + }, + }, + Check: resource.ComposeTestCheckFunc( + testAccCheckKnowledgeBaseExists(ctx, resourceName, &knowledgebase), + resource.TestCheckResourceAttrPair(resourceName, names.AttrRoleARN, "aws_iam_role.test", names.AttrARN), + resource.TestCheckResourceAttr(resourceName, "knowledge_base_configuration.#", "1"), + resource.TestCheckResourceAttr(resourceName, "knowledge_base_configuration.0.vector_knowledge_base_configuration.#", "1"), + resource.TestCheckResourceAttr(resourceName, "knowledge_base_configuration.0.type", "VECTOR"), + resource.TestCheckResourceAttr(resourceName, "storage_configuration.#", "1"), + resource.TestCheckResourceAttr(resourceName, "storage_configuration.0.type", "S3_VECTORS"), + resource.TestCheckResourceAttr(resourceName, "storage_configuration.0.s3_vectors_configuration.#", "1"), + resource.TestCheckResourceAttrPair(resourceName, "storage_configuration.0.s3_vectors_configuration.0.index_name", "aws_s3vectors_index.test", "index_name"), + ), + }, + }, + }) +} + func testAccCheckKnowledgeBaseDestroy(ctx context.Context) resource.TestCheckFunc { return func(s *terraform.State) error { conn := acctest.Provider.Meta().(*conns.AWSClient).BedrockAgentClient(ctx) @@ -946,3 +1009,138 @@ resource "aws_bedrockagent_knowledge_base" "test" { } `, rName, model)) } + +func testAccKnowledgeBaseConfig_S3VectorsBase(rName string) string { + return fmt.Sprintf(` +data "aws_region" "current" {} +data "aws_partition" "current" {} + +data "aws_iam_policy_document" "assume_role_bedrock" { + statement { + effect = "Allow" + principals { + type = "Service" + identifiers = ["bedrock.amazonaws.com"] + } + actions = ["sts:AssumeRole"] + } +} + +data "aws_iam_policy_document" "bedrock" { + statement { + effect = "Allow" + actions = ["bedrock:InvokeModel"] + resources = ["*"] + } + statement { + effect = "Allow" + actions = ["s3:ListBucket", "s3:GetObject"] + resources = ["*"] + } + statement { + effect = "Allow" + actions = [ + "s3vectors:GetIndex", + "s3vectors:QueryVectors", + "s3vectors:PutVectors", + "s3vectors:GetVectors", + "s3vectors:DeleteVectors" + ] + resources = ["*"] + } +} + +resource "aws_iam_role" "test" { + assume_role_policy = data.aws_iam_policy_document.assume_role_bedrock.json + name = %[1]q +} + +resource "aws_iam_role_policy" "test" { + role = aws_iam_role.test.name + policy = data.aws_iam_policy_document.bedrock.json +} + +resource "aws_s3vectors_vector_bucket" "test" { + vector_bucket_name = %[1]q + force_destroy = true +} + +resource "aws_s3vectors_index" "test" { + index_name = %[1]q + vector_bucket_name = aws_s3vectors_vector_bucket.test.vector_bucket_name + + data_type = "float32" + dimension = 256 + distance_metric = "euclidean" +} +`, rName) +} + +func testAccKnowledgeBaseConfig_S3VectorsByIndexARN(rName, model string) string { + return acctest.ConfigCompose( + testAccKnowledgeBaseConfig_S3VectorsBase(rName), + fmt.Sprintf(` +resource "aws_bedrockagent_knowledge_base" "test" { + depends_on = [ + aws_iam_role_policy.test, + ] + name = %[1]q + role_arn = aws_iam_role.test.arn + + knowledge_base_configuration { + vector_knowledge_base_configuration { + embedding_model_arn = "arn:${data.aws_partition.current.partition}:bedrock:${data.aws_region.current.region}::foundation-model/%[2]s" + embedding_model_configuration { + bedrock_embedding_model_configuration { + dimensions = 256 + embedding_data_type = "FLOAT32" + } + } + } + type = "VECTOR" + } + + storage_configuration { + type = "S3_VECTORS" + s3_vectors_configuration { + index_arn = aws_s3vectors_index.test.index_arn + } + } +} +`, rName, model)) +} + +func testAccKnowledgeBaseConfig_S3VectorsByIndexName(rName, model string) string { + return acctest.ConfigCompose( + testAccKnowledgeBaseConfig_S3VectorsBase(rName), + fmt.Sprintf(` +resource "aws_bedrockagent_knowledge_base" "test" { + depends_on = [ + aws_iam_role_policy.test, + ] + name = %[1]q + role_arn = aws_iam_role.test.arn + + knowledge_base_configuration { + vector_knowledge_base_configuration { + embedding_model_arn = "arn:${data.aws_partition.current.partition}:bedrock:${data.aws_region.current.region}::foundation-model/%[2]s" + embedding_model_configuration { + bedrock_embedding_model_configuration { + dimensions = 256 + embedding_data_type = "FLOAT32" + } + } + } + type = "VECTOR" + } + + storage_configuration { + type = "S3_VECTORS" + s3_vectors_configuration { + index_name = aws_s3vectors_index.test.index_name + vector_bucket_arn = aws_s3vectors_vector_bucket.test.vector_bucket_arn + } + } +} +`, rName, model)) +} From e8df94bac02ff81f136e20b5e85bbc76a0fce908 Mon Sep 17 00:00:00 2001 From: tabito Date: Sat, 6 Dec 2025 11:53:36 +0900 Subject: [PATCH 29/65] Update the documentation to add description s3_vectors_configuration including an example usage --- .../bedrockagent_knowledge_base.html.markdown | 54 ++++++++++++++++++- 1 file changed, 53 insertions(+), 1 deletion(-) diff --git a/website/docs/r/bedrockagent_knowledge_base.html.markdown b/website/docs/r/bedrockagent_knowledge_base.html.markdown index d25ab2183c34..daee77e14b7c 100644 --- a/website/docs/r/bedrockagent_knowledge_base.html.markdown +++ b/website/docs/r/bedrockagent_knowledge_base.html.markdown @@ -83,6 +83,48 @@ resource "aws_bedrockagent_knowledge_base" "example" { } ``` +### S3 Vectors Configuration + +```terraform +resource "aws_s3vectors_vector_bucket" "example" { + vector_bucket_name = "example-bucket" +} + +resource "aws_s3vectors_index" "example" { + index_name = "example-index" + vector_bucket_name = aws_s3vectors_vector_bucket.example.vector_bucket_name + + data_type = "float32" + dimension = 256 + distance_metric = "euclidean" +} + +resource "aws_bedrockagent_knowledge_base" "example" { + name = "example-s3vectors-kb" + role_arn = aws_iam_role.example.arn + + knowledge_base_configuration { + vector_knowledge_base_configuration { + embedding_model_arn = "arn:aws:bedrock:us-west-2::foundation-model/amazon.titan-embed-text-v2:0" + embedding_model_configuration { + bedrock_embedding_model_configuration { + dimensions = 256 + embedding_data_type = "FLOAT32" + } + } + } + type = "VECTOR" + } + + storage_configuration { + type = "S3_VECTORS" + s3_vectors_configuration { + index_arn = aws_s3vectors_index.example.index_arn + } + } +} +``` + ## Argument Reference The following arguments are required: @@ -149,11 +191,12 @@ The `s3_location` configuration block supports the following arguments: The `storage_configuration` configuration block supports the following arguments: -* `type` - (Required) Vector store service in which the knowledge base is stored. Valid Values: `OPENSEARCH_SERVERLESS`, `PINECONE`, `REDIS_ENTERPRISE_CLOUD`, `RDS`. +* `type` - (Required) Vector store service in which the knowledge base is stored. Valid Values: `OPENSEARCH_SERVERLESS`, `PINECONE`, `REDIS_ENTERPRISE_CLOUD`, `RDS`, `S3_VECTORS`. * `opensearch_serverless_configuration` - (Optional) The storage configuration of the knowledge base in Amazon OpenSearch Service. See [`opensearch_serverless_configuration` block](#opensearch_serverless_configuration-block) for details. * `pinecone_configuration` - (Optional) The storage configuration of the knowledge base in Pinecone. See [`pinecone_configuration` block](#pinecone_configuration-block) for details. * `rds_configuration` - (Optional) Details about the storage configuration of the knowledge base in Amazon RDS. For more information, see [Create a vector index in Amazon RDS](https://docs.aws.amazon.com/bedrock/latest/userguide/knowledge-base-setup.html). See [`rds_configuration` block](#rds_configuration-block) for details. * `redis_enterprise_cloud_configuration` - (Optional) The storage configuration of the knowledge base in Redis Enterprise Cloud. See [`redis_enterprise_cloud_configuration` block](#redis_enterprise_cloud_configuration-block) for details. +* `s3_vectors_configuration` - (Optional) The storage configuration of the knowledge base in Amazon S3 Vectors. See [`s3_vectors_configuration` block](#s3_vectors_configuration-block) for details. ### `opensearch_serverless_configuration` block @@ -204,6 +247,15 @@ The `redis_enterprise_cloud_configuration` configuration block supports the foll * `vector_field` - (Required) Name of the field in which Amazon Bedrock stores the vector embeddings for your data sources. * `vector_index_name` - (Required) Name of the vector index. +### `s3_vectors_configuration` block + +The `s3_vectors_configuration` configuration block supports the following arguments. +Either `index_arn`, or both `index_name` and `vector_bucket_arn` must be specified. + +* `index_arn` - (Optional) ARN of the S3 Vectors index. Conflicts with `index_name` and `vector_bucket_arn`. +* `index_name` - (Optional) Name of the S3 Vectors index. Must be specified with `vector_bucket_arn`. Conflicts with `index_arn`. +* `vector_bucket_arn` - (Optional) ARN of the S3 Vectors vector bucket. Must be specified with `index_name`. Conflicts with `index_arn`. + ## Attribute Reference This resource exports the following attributes in addition to the arguments above: From 64f13dd75e32c1d2a230a6aec71c9143c8ceac6f Mon Sep 17 00:00:00 2001 From: tabito Date: Sat, 6 Dec 2025 12:20:12 +0900 Subject: [PATCH 30/65] add changelog --- .changelog/45468.txt | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 .changelog/45468.txt diff --git a/.changelog/45468.txt b/.changelog/45468.txt new file mode 100644 index 000000000000..e6df71453053 --- /dev/null +++ b/.changelog/45468.txt @@ -0,0 +1,3 @@ +```release-note:enhancement +resource/aws_bedrockagent_knowledge_base: Add storage_configuration.s3_vectors_configuration block +``` From 3fe6175f48e6e65d5c11cbc9e3e630b4eded5f90 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Mon, 8 Dec 2025 12:54:11 -0500 Subject: [PATCH 31/65] Tidy up 'testAccKnowledgeBase_OpenSearchManagedCluster_basic'. --- .../service/bedrockagent/bedrockagent_test.go | 16 +-- .../service/bedrockagent/data_source_test.go | 2 +- .../bedrockagent/knowledge_base_test.go | 122 +++++++----------- 3 files changed, 54 insertions(+), 86 deletions(-) diff --git a/internal/service/bedrockagent/bedrockagent_test.go b/internal/service/bedrockagent/bedrockagent_test.go index 3ee0f0de6261..c9a9872b94a4 100644 --- a/internal/service/bedrockagent/bedrockagent_test.go +++ b/internal/service/bedrockagent/bedrockagent_test.go @@ -14,14 +14,14 @@ func TestAccBedrockAgent_serial(t *testing.T) { testCases := map[string]map[string]func(t *testing.T){ "KnowledgeBase": { - acctest.CtBasic: testAccKnowledgeBase_basic, - acctest.CtDisappears: testAccKnowledgeBase_disappears, - "tags": testAccKnowledgeBase_tags, - "OpenSearchBasic": testAccKnowledgeBase_OpenSearch_basic, - "OpenSearchUpdate": testAccKnowledgeBase_OpenSearch_update, - "OpenSearchSupplementalDataStorage": testAccKnowledgeBase_OpenSearch_supplementalDataStorage, - "KendraBasic": testAccKnowledgeBase_Kendra_basic, - "OpenSearchManagedClusterBasic": testAccKnowledgeBase_OpenSearchManagedCluster_basic, + acctest.CtBasic: testAccKnowledgeBase_basic, + acctest.CtDisappears: testAccKnowledgeBase_disappears, + "tags": testAccKnowledgeBase_tags, + "OpenSearchServerlessBasic": testAccKnowledgeBase_OpenSearchServerless_basic, + "OpenSearchServerlessUpdate": testAccKnowledgeBase_OpenSearchServerless_update, + "OpenSearchServerlessSupplementalDataStorage": testAccKnowledgeBase_OpenSearchServerless_supplementalDataStorage, + "KendraBasic": testAccKnowledgeBase_Kendra_basic, + "OpenSearchManagedClusterBasic": testAccKnowledgeBase_OpenSearchManagedCluster_basic, }, "DataSource": { acctest.CtBasic: testAccDataSource_basic, diff --git a/internal/service/bedrockagent/data_source_test.go b/internal/service/bedrockagent/data_source_test.go index 8c88b8d51085..c9a64a0e0754 100644 --- a/internal/service/bedrockagent/data_source_test.go +++ b/internal/service/bedrockagent/data_source_test.go @@ -834,7 +834,7 @@ resource "aws_bedrockagent_data_source" "test" { } func testAccDataSourceConfig_webConfiguration(rName, collectionName, embeddingModel string) string { - return acctest.ConfigCompose(testAccKnowledgeBaseConfig_OpenSearch_basic(rName, collectionName, embeddingModel), fmt.Sprintf(` + return acctest.ConfigCompose(testAccKnowledgeBaseConfig_OpenSearchServerless_basic(rName, collectionName, embeddingModel), fmt.Sprintf(` resource "aws_bedrockagent_data_source" "test" { name = %[1]q knowledge_base_id = aws_bedrockagent_knowledge_base.test.id diff --git a/internal/service/bedrockagent/knowledge_base_test.go b/internal/service/bedrockagent/knowledge_base_test.go index 867d37574908..6130877668ba 100644 --- a/internal/service/bedrockagent/knowledge_base_test.go +++ b/internal/service/bedrockagent/knowledge_base_test.go @@ -243,10 +243,9 @@ func testAccKnowledgeBase_tags(t *testing.T) { }) } -func testAccKnowledgeBase_OpenSearch_basic(t *testing.T) { +func testAccKnowledgeBase_OpenSearchServerless_basic(t *testing.T) { ctx := acctest.Context(t) collectionName := skipIfOSSCollectionNameEnvVarNotSet(t) - var knowledgebase awstypes.KnowledgeBase rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) resourceName := "aws_bedrockagent_knowledge_base.test" @@ -261,7 +260,7 @@ func testAccKnowledgeBase_OpenSearch_basic(t *testing.T) { CheckDestroy: testAccCheckKnowledgeBaseDestroy(ctx), Steps: []resource.TestStep{ { - Config: testAccKnowledgeBaseConfig_OpenSearch_basic(rName, collectionName, foundationModel), + Config: testAccKnowledgeBaseConfig_OpenSearchServerless_basic(rName, collectionName, foundationModel), Check: resource.ComposeTestCheckFunc( testAccCheckKnowledgeBaseExists(ctx, resourceName, &knowledgebase), resource.TestCheckResourceAttrPair(resourceName, names.AttrRoleARN, "aws_iam_role.test", names.AttrARN), @@ -287,10 +286,9 @@ func testAccKnowledgeBase_OpenSearch_basic(t *testing.T) { }) } -func testAccKnowledgeBase_OpenSearch_update(t *testing.T) { +func testAccKnowledgeBase_OpenSearchServerless_update(t *testing.T) { ctx := acctest.Context(t) collectionName := skipIfOSSCollectionNameEnvVarNotSet(t) - var knowledgebase awstypes.KnowledgeBase rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) resourceName := "aws_bedrockagent_knowledge_base.test" @@ -305,7 +303,7 @@ func testAccKnowledgeBase_OpenSearch_update(t *testing.T) { CheckDestroy: testAccCheckKnowledgeBaseDestroy(ctx), Steps: []resource.TestStep{ { - Config: testAccKnowledgeBaseConfig_OpenSearch_basic(rName, collectionName, foundationModel), + Config: testAccKnowledgeBaseConfig_OpenSearchServerless_basic(rName, collectionName, foundationModel), Check: resource.ComposeTestCheckFunc( testAccCheckKnowledgeBaseExists(ctx, resourceName, &knowledgebase), resource.TestCheckResourceAttr(resourceName, names.AttrName, rName), @@ -329,7 +327,7 @@ func testAccKnowledgeBase_OpenSearch_update(t *testing.T) { ImportStateVerify: true, }, { - Config: testAccKnowledgeBaseConfig_OpenSearch_update(rName, collectionName, foundationModel), + Config: testAccKnowledgeBaseConfig_OpenSearchServerless_update(rName, collectionName, foundationModel), Check: resource.ComposeTestCheckFunc( testAccCheckKnowledgeBaseExists(ctx, resourceName, &knowledgebase), resource.TestCheckResourceAttr(resourceName, names.AttrName, rName+"-updated"), @@ -357,10 +355,9 @@ func testAccKnowledgeBase_OpenSearch_update(t *testing.T) { }) } -func testAccKnowledgeBase_OpenSearch_supplementalDataStorage(t *testing.T) { +func testAccKnowledgeBase_OpenSearchServerless_supplementalDataStorage(t *testing.T) { ctx := acctest.Context(t) collectionName := skipIfOSSCollectionNameEnvVarNotSet(t) - var knowledgebase awstypes.KnowledgeBase rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) resourceName := "aws_bedrockagent_knowledge_base.test" @@ -375,7 +372,7 @@ func testAccKnowledgeBase_OpenSearch_supplementalDataStorage(t *testing.T) { CheckDestroy: testAccCheckKnowledgeBaseDestroy(ctx), Steps: []resource.TestStep{ { - Config: testAccKnowledgeBaseConfig_OpenSearch_supplementalDataStorage(rName, collectionName, foundationModel), + Config: testAccKnowledgeBaseConfig_OpenSearchServerless_supplementalDataStorage(rName, collectionName, foundationModel), Check: resource.ComposeTestCheckFunc( testAccCheckKnowledgeBaseExists(ctx, resourceName, &knowledgebase), resource.TestCheckResourceAttr(resourceName, "knowledge_base_configuration.#", "1"), @@ -449,16 +446,6 @@ func testAccKnowledgeBase_OpenSearchManagedCluster_basic(t *testing.T) { rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) resourceName := "aws_bedrockagent_knowledge_base.test" foundationModel := "amazon.titan-embed-text-v2:0" - testExternalProviders := map[string]resource.ExternalProvider{ - "opensearch": { - Source: "opensearch-project/opensearch", - VersionConstraint: "~> 2.2.0", - }, - "random": { - Source: "hashicorp/random", - VersionConstraint: "~> 3.5.0", - }, - } resource.Test(t, resource.TestCase{ PreCheck: func() { @@ -467,37 +454,43 @@ func testAccKnowledgeBase_OpenSearchManagedCluster_basic(t *testing.T) { }, ErrorCheck: acctest.ErrorCheck(t, names.BedrockAgentServiceID), ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, - ExternalProviders: testExternalProviders, - CheckDestroy: testAccCheckKnowledgeBaseDestroy(ctx), + ExternalProviders: map[string]resource.ExternalProvider{ + "opensearch": { + Source: "opensearch-project/opensearch", + VersionConstraint: "~> 2.2.0", + }, + }, + CheckDestroy: testAccCheckKnowledgeBaseDestroy(ctx), Steps: []resource.TestStep{ { Config: testAccKnowledgeBaseConfig_OpenSearchManagedCluster_basic(rName, foundationModel), Check: resource.ComposeTestCheckFunc( testAccCheckKnowledgeBaseExists(ctx, resourceName, &knowledgebase), - resource.TestCheckResourceAttr(resourceName, names.AttrName, rName), - resource.TestCheckResourceAttr(resourceName, "knowledge_base_configuration.#", "1"), - resource.TestCheckResourceAttr(resourceName, "knowledge_base_configuration.0.vector_knowledge_base_configuration.#", "1"), - resource.TestCheckResourceAttr(resourceName, "knowledge_base_configuration.0.type", "VECTOR"), - resource.TestCheckResourceAttr(resourceName, "storage_configuration.#", "1"), - resource.TestCheckResourceAttr(resourceName, "storage_configuration.0.type", "OPENSEARCH_MANAGED_CLUSTER"), - resource.TestCheckResourceAttr(resourceName, "storage_configuration.0.opensearch_managed_cluster_configuration.#", "1"), - resource.TestCheckResourceAttr(resourceName, "storage_configuration.0.opensearch_managed_cluster_configuration.0.vector_index_name", "knowledge-index"), - resource.TestCheckResourceAttr(resourceName, "storage_configuration.0.opensearch_managed_cluster_configuration.0.field_mapping.#", "1"), - resource.TestCheckResourceAttr(resourceName, "storage_configuration.0.opensearch_managed_cluster_configuration.0.field_mapping.0.vector_field", "vector_embedding"), - resource.TestCheckResourceAttr(resourceName, "storage_configuration.0.opensearch_managed_cluster_configuration.0.field_mapping.0.text_field", "text"), - resource.TestCheckResourceAttr(resourceName, "storage_configuration.0.opensearch_managed_cluster_configuration.0.field_mapping.0.metadata_field", "metadata"), ), - }, - { - Config: testAccKnowledgeBaseConfig_OpenSearchManagedCluster_basic(rName, foundationModel), - ResourceName: resourceName, - ImportStateKind: resource.ImportBlockWithID, - ImportState: true, - ImportPlanChecks: resource.ImportPlanChecks{ + ConfigPlanChecks: resource.ConfigPlanChecks{ PreApply: []plancheck.PlanCheck{ - plancheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrID), knownvalue.NotNull()), + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), }, }, + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("knowledge_base_configuration"), knownvalue.ListExact([]knownvalue.Check{ + knownvalue.MapExact(map[string]knownvalue.Check{ + "kendra_knowledge_base_configuration": knownvalue.ListSizeExact(0), + names.AttrType: tfknownvalue.StringExact(awstypes.KnowledgeBaseTypeVector), + "vector_knowledge_base_configuration": knownvalue.ListSizeExact(1), + }), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("storage_configuration"), knownvalue.ListExact([]knownvalue.Check{ + knownvalue.MapExact(map[string]knownvalue.Check{ + "opensearch_managed_cluster_configuration": knownvalue.ListSizeExact(1), + "opensearch_serverless_configuration": knownvalue.ListSizeExact(0), + names.AttrType: tfknownvalue.StringExact(awstypes.KnowledgeBaseStorageTypeOpensearchManagedCluster), + "pinecone_configuration": knownvalue.ListSizeExact(0), + "rds_configuration": knownvalue.ListSizeExact(0), + "redis_enterprise_cloud_configuration": knownvalue.ListSizeExact(0), + }), + })), + }, }, }, }) @@ -746,7 +739,7 @@ resource "aws_bedrockagent_knowledge_base" "test" { `, rName, model, tag1Key, tag1Value, tag2Key, tag2Value)) } -func testAccKnowledgeBaseConfigBase_openSearch(rName, collectionName, model string) string { +func testAccKnowledgeBaseConfig_baseOpenSearchServerless(rName, collectionName, model string) string { return fmt.Sprintf(` data "aws_caller_identity" "current" {} data "aws_region" "current" {} @@ -884,10 +877,8 @@ resource "aws_opensearchserverless_access_policy" "test" { `, rName, collectionName, model) } -func testAccKnowledgeBaseConfig_OpenSearch_basic(rName, collectionName, model string) string { - return acctest.ConfigCompose( - testAccKnowledgeBaseConfigBase_openSearch(rName, collectionName, model), - fmt.Sprintf(` +func testAccKnowledgeBaseConfig_OpenSearchServerless_basic(rName, collectionName, model string) string { + return acctest.ConfigCompose(testAccKnowledgeBaseConfig_baseOpenSearchServerless(rName, collectionName, model), fmt.Sprintf(` resource "aws_bedrockagent_knowledge_base" "test" { depends_on = [ aws_iam_role_policy_attachment.test, @@ -920,10 +911,8 @@ resource "aws_bedrockagent_knowledge_base" "test" { `, rName, model)) } -func testAccKnowledgeBaseConfig_OpenSearch_update(rName, collectionName, model string) string { - return acctest.ConfigCompose( - testAccKnowledgeBaseConfigBase_openSearch(rName, collectionName, model), - fmt.Sprintf(` +func testAccKnowledgeBaseConfig_OpenSearchServerless_update(rName, collectionName, model string) string { + return acctest.ConfigCompose(testAccKnowledgeBaseConfig_baseOpenSearchServerless(rName, collectionName, model), fmt.Sprintf(` resource "aws_bedrockagent_knowledge_base" "test" { depends_on = [ aws_iam_role_policy_attachment.test, @@ -957,10 +946,8 @@ resource "aws_bedrockagent_knowledge_base" "test" { `, rName, model)) } -func testAccKnowledgeBaseConfig_OpenSearch_supplementalDataStorage(rName, collectionName, model string) string { - return acctest.ConfigCompose( - testAccKnowledgeBaseConfigBase_openSearch(rName, collectionName, model), - fmt.Sprintf(` +func testAccKnowledgeBaseConfig_OpenSearchServerless_supplementalDataStorage(rName, collectionName, model string) string { + return acctest.ConfigCompose(testAccKnowledgeBaseConfig_baseOpenSearchServerless(rName, collectionName, model), fmt.Sprintf(` resource "aws_s3_bucket" "test" { bucket = %[1]q force_destroy = true @@ -1121,10 +1108,6 @@ terraform { source = "opensearch-project/opensearch" version = "~> 2.2.0" } - random = { - source = "hashicorp/random" - version = "~> 3.5.0" - } } } @@ -1158,7 +1141,7 @@ resource "aws_iam_role" "bedrock_kb_role" { } resource "aws_iam_policy" "bedrock_models_access" { - name. = "bedrock-%[1]s" + name = "bedrock-%[1]s" description = "IAM policy for Amazon Bedrock to access embedding models" policy = jsonencode({ @@ -1235,21 +1218,6 @@ resource "aws_iam_role_policy_attachment" "opensearch_access" { policy_arn = aws_iam_policy.opensearch_access.arn } -resource "random_password" "opensearch_master" { - length = 16 - special = true - min_lower = 1 - min_numeric = 1 - min_special = 1 - min_upper = 1 - override_special = "!#$&*()-_=+" - - # Don't replace the password on each apply - lifecycle { - ignore_changes = [length, special, override_special] - } -} - resource "aws_opensearch_domain" "knowledge_base" { domain_name = substr(%[1]q, 0, 28) engine_version = "OpenSearch_3.1" @@ -1292,7 +1260,7 @@ resource "aws_opensearch_domain" "knowledge_base" { master_user_options { master_user_name = "admin" - master_user_password = random_password.opensearch_master.result + master_user_password = "Barbarbarbar1!" } } @@ -1331,7 +1299,7 @@ locals { provider "opensearch" { url = "https://${aws_opensearch_domain.knowledge_base.endpoint}" username = "admin" - password = random_password.opensearch_master.result + password = aws_opensearch_domain.knowledge_base.advanced_security_options[0].master_user_options[0].master_user_password insecure = false aws_region = data.aws_region.current.region healthcheck = false From a6cde670bafeb755d043c6bbb9a4fb0640b38112 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Mon, 8 Dec 2025 14:31:24 -0500 Subject: [PATCH 32/65] Fix terrafmt errors. --- .../bedrockagent/knowledge_base_test.go | 40 +++++++++---------- 1 file changed, 20 insertions(+), 20 deletions(-) diff --git a/internal/service/bedrockagent/knowledge_base_test.go b/internal/service/bedrockagent/knowledge_base_test.go index 6130877668ba..19ea2cb4cfc3 100644 --- a/internal/service/bedrockagent/knowledge_base_test.go +++ b/internal/service/bedrockagent/knowledge_base_test.go @@ -1132,7 +1132,7 @@ resource "aws_iam_role" "bedrock_kb_role" { Action = "sts:AssumeRole" Condition = { StringEquals = { - "aws:SourceAccount": data.aws_caller_identity.current.account_id + "aws:SourceAccount" : data.aws_caller_identity.current.account_id }, } } @@ -1289,7 +1289,7 @@ locals { Principal = { AWS = "*" } - Action = "es:*" + Action = "es:*" Resource = "arn:${data.aws_partition.current.partition}:es:${data.aws_region.current.region}:${data.aws_caller_identity.current.account_id}:domain/${substr(%[1]q, 0, 28)}/*" } ] @@ -1342,27 +1342,27 @@ resource "opensearch_index" "vector_index" { # Mappings for Bedrock Knowledge Base compatibility mappings = jsonencode({ - "properties": { - "vector_embedding": { - "type": "knn_vector", - "dimension": 1024, - "space_type": "l2", - "method": { - "name": "hnsw", - "engine": "faiss", - "parameters": { - "ef_construction": 128, - "m": 24 + "properties" : { + "vector_embedding" : { + "type" : "knn_vector", + "dimension" : 1024, + "space_type" : "l2", + "method" : { + "name" : "hnsw", + "engine" : "faiss", + "parameters" : { + "ef_construction" : 128, + "m" : 24 } } }, - "text": { - "type": "text", - "index": true + "text" : { + "type" : "text", + "index" : true }, - "metadata": { - "type": "text", - "index": false + "metadata" : { + "type" : "text", + "index" : false } } }) @@ -1371,7 +1371,7 @@ resource "opensearch_index" "vector_index" { ignore_changes = [ mappings ] } - depends_on = [ aws_opensearch_domain.knowledge_base ] + depends_on = [aws_opensearch_domain.knowledge_base] } `, rName, model) } From 983c75d812bc21221187bd33b09b8080bfd823cd Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Mon, 8 Dec 2025 14:35:15 -0500 Subject: [PATCH 33/65] Fix terrafmt errors. --- internal/service/bedrockagent/knowledge_base_test.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/internal/service/bedrockagent/knowledge_base_test.go b/internal/service/bedrockagent/knowledge_base_test.go index 19ea2cb4cfc3..08a11363a1ab 100644 --- a/internal/service/bedrockagent/knowledge_base_test.go +++ b/internal/service/bedrockagent/knowledge_base_test.go @@ -1366,9 +1366,9 @@ resource "opensearch_index" "vector_index" { } } }) - + lifecycle { - ignore_changes = [ mappings ] + ignore_changes = [mappings] } depends_on = [aws_opensearch_domain.knowledge_base] From e0425f371f9647f7c846f1c6b1e2105243519ab0 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Mon, 8 Dec 2025 14:38:22 -0500 Subject: [PATCH 34/65] Revert "Update the documentation to add description s3_vectors_configuration" This reverts commit e8df94bac02ff81f136e20b5e85bbc76a0fce908. --- .../bedrockagent_knowledge_base.html.markdown | 54 +------------------ 1 file changed, 1 insertion(+), 53 deletions(-) diff --git a/website/docs/r/bedrockagent_knowledge_base.html.markdown b/website/docs/r/bedrockagent_knowledge_base.html.markdown index daee77e14b7c..d25ab2183c34 100644 --- a/website/docs/r/bedrockagent_knowledge_base.html.markdown +++ b/website/docs/r/bedrockagent_knowledge_base.html.markdown @@ -83,48 +83,6 @@ resource "aws_bedrockagent_knowledge_base" "example" { } ``` -### S3 Vectors Configuration - -```terraform -resource "aws_s3vectors_vector_bucket" "example" { - vector_bucket_name = "example-bucket" -} - -resource "aws_s3vectors_index" "example" { - index_name = "example-index" - vector_bucket_name = aws_s3vectors_vector_bucket.example.vector_bucket_name - - data_type = "float32" - dimension = 256 - distance_metric = "euclidean" -} - -resource "aws_bedrockagent_knowledge_base" "example" { - name = "example-s3vectors-kb" - role_arn = aws_iam_role.example.arn - - knowledge_base_configuration { - vector_knowledge_base_configuration { - embedding_model_arn = "arn:aws:bedrock:us-west-2::foundation-model/amazon.titan-embed-text-v2:0" - embedding_model_configuration { - bedrock_embedding_model_configuration { - dimensions = 256 - embedding_data_type = "FLOAT32" - } - } - } - type = "VECTOR" - } - - storage_configuration { - type = "S3_VECTORS" - s3_vectors_configuration { - index_arn = aws_s3vectors_index.example.index_arn - } - } -} -``` - ## Argument Reference The following arguments are required: @@ -191,12 +149,11 @@ The `s3_location` configuration block supports the following arguments: The `storage_configuration` configuration block supports the following arguments: -* `type` - (Required) Vector store service in which the knowledge base is stored. Valid Values: `OPENSEARCH_SERVERLESS`, `PINECONE`, `REDIS_ENTERPRISE_CLOUD`, `RDS`, `S3_VECTORS`. +* `type` - (Required) Vector store service in which the knowledge base is stored. Valid Values: `OPENSEARCH_SERVERLESS`, `PINECONE`, `REDIS_ENTERPRISE_CLOUD`, `RDS`. * `opensearch_serverless_configuration` - (Optional) The storage configuration of the knowledge base in Amazon OpenSearch Service. See [`opensearch_serverless_configuration` block](#opensearch_serverless_configuration-block) for details. * `pinecone_configuration` - (Optional) The storage configuration of the knowledge base in Pinecone. See [`pinecone_configuration` block](#pinecone_configuration-block) for details. * `rds_configuration` - (Optional) Details about the storage configuration of the knowledge base in Amazon RDS. For more information, see [Create a vector index in Amazon RDS](https://docs.aws.amazon.com/bedrock/latest/userguide/knowledge-base-setup.html). See [`rds_configuration` block](#rds_configuration-block) for details. * `redis_enterprise_cloud_configuration` - (Optional) The storage configuration of the knowledge base in Redis Enterprise Cloud. See [`redis_enterprise_cloud_configuration` block](#redis_enterprise_cloud_configuration-block) for details. -* `s3_vectors_configuration` - (Optional) The storage configuration of the knowledge base in Amazon S3 Vectors. See [`s3_vectors_configuration` block](#s3_vectors_configuration-block) for details. ### `opensearch_serverless_configuration` block @@ -247,15 +204,6 @@ The `redis_enterprise_cloud_configuration` configuration block supports the foll * `vector_field` - (Required) Name of the field in which Amazon Bedrock stores the vector embeddings for your data sources. * `vector_index_name` - (Required) Name of the vector index. -### `s3_vectors_configuration` block - -The `s3_vectors_configuration` configuration block supports the following arguments. -Either `index_arn`, or both `index_name` and `vector_bucket_arn` must be specified. - -* `index_arn` - (Optional) ARN of the S3 Vectors index. Conflicts with `index_name` and `vector_bucket_arn`. -* `index_name` - (Optional) Name of the S3 Vectors index. Must be specified with `vector_bucket_arn`. Conflicts with `index_arn`. -* `vector_bucket_arn` - (Optional) ARN of the S3 Vectors vector bucket. Must be specified with `index_name`. Conflicts with `index_arn`. - ## Attribute Reference This resource exports the following attributes in addition to the arguments above: From 9a2e42300eee05ccc2b9848144457692eeb83014 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Mon, 8 Dec 2025 14:38:28 -0500 Subject: [PATCH 35/65] Revert "Add an acceptance test for s3_vectors_configuration" This reverts commit 876fefc4d36a5de68fc771129aeaa5f98021abbe. --- .../service/bedrockagent/bedrockagent_test.go | 1 - .../bedrockagent/knowledge_base_test.go | 198 ------------------ 2 files changed, 199 deletions(-) diff --git a/internal/service/bedrockagent/bedrockagent_test.go b/internal/service/bedrockagent/bedrockagent_test.go index c0d81029d5d7..ae39ed34b5c1 100644 --- a/internal/service/bedrockagent/bedrockagent_test.go +++ b/internal/service/bedrockagent/bedrockagent_test.go @@ -20,7 +20,6 @@ func TestAccBedrockAgent_serial(t *testing.T) { "OpenSearchBasic": testAccKnowledgeBase_OpenSearch_basic, "OpenSearchUpdate": testAccKnowledgeBase_OpenSearch_update, "OpenSearchSupplementalDataStorage": testAccKnowledgeBase_OpenSearch_supplementalDataStorage, - "S3Vectors": testAccKnowledgeBase_S3Vectors, }, "DataSource": { acctest.CtBasic: testAccDataSource_basic, diff --git a/internal/service/bedrockagent/knowledge_base_test.go b/internal/service/bedrockagent/knowledge_base_test.go index 2ca610e70f54..b12b4f9ecae4 100644 --- a/internal/service/bedrockagent/knowledge_base_test.go +++ b/internal/service/bedrockagent/knowledge_base_test.go @@ -404,69 +404,6 @@ func testAccKnowledgeBase_OpenSearch_supplementalDataStorage(t *testing.T) { }) } -func testAccKnowledgeBase_S3Vectors(t *testing.T) { - ctx := acctest.Context(t) - - var knowledgebase types.KnowledgeBase - rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) - resourceName := "aws_bedrockagent_knowledge_base.test" - foundationModel := "amazon.titan-embed-text-v2:0" - - resource.Test(t, resource.TestCase{ - PreCheck: func() { - acctest.PreCheck(ctx, t) - }, - ErrorCheck: acctest.ErrorCheck(t, names.BedrockAgentServiceID), - ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, - CheckDestroy: testAccCheckKnowledgeBaseDestroy(ctx), - Steps: []resource.TestStep{ - { - Config: testAccKnowledgeBaseConfig_S3VectorsByIndexARN(rName, foundationModel), - ConfigPlanChecks: resource.ConfigPlanChecks{ - PreApply: []plancheck.PlanCheck{ - plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), - }, - }, - Check: resource.ComposeTestCheckFunc( - testAccCheckKnowledgeBaseExists(ctx, resourceName, &knowledgebase), - resource.TestCheckResourceAttrPair(resourceName, names.AttrRoleARN, "aws_iam_role.test", names.AttrARN), - resource.TestCheckResourceAttr(resourceName, "knowledge_base_configuration.#", "1"), - resource.TestCheckResourceAttr(resourceName, "knowledge_base_configuration.0.vector_knowledge_base_configuration.#", "1"), - resource.TestCheckResourceAttr(resourceName, "knowledge_base_configuration.0.type", "VECTOR"), - resource.TestCheckResourceAttr(resourceName, "storage_configuration.#", "1"), - resource.TestCheckResourceAttr(resourceName, "storage_configuration.0.type", "S3_VECTORS"), - resource.TestCheckResourceAttr(resourceName, "storage_configuration.0.s3_vectors_configuration.#", "1"), - resource.TestCheckResourceAttrPair(resourceName, "storage_configuration.0.s3_vectors_configuration.0.index_arn", "aws_s3vectors_index.test", "index_arn"), - ), - }, - { - ResourceName: resourceName, - ImportState: true, - ImportStateVerify: true, - }, - { - Config: testAccKnowledgeBaseConfig_S3VectorsByIndexName(rName, foundationModel), - ConfigPlanChecks: resource.ConfigPlanChecks{ - PreApply: []plancheck.PlanCheck{ - plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionDestroyBeforeCreate), - }, - }, - Check: resource.ComposeTestCheckFunc( - testAccCheckKnowledgeBaseExists(ctx, resourceName, &knowledgebase), - resource.TestCheckResourceAttrPair(resourceName, names.AttrRoleARN, "aws_iam_role.test", names.AttrARN), - resource.TestCheckResourceAttr(resourceName, "knowledge_base_configuration.#", "1"), - resource.TestCheckResourceAttr(resourceName, "knowledge_base_configuration.0.vector_knowledge_base_configuration.#", "1"), - resource.TestCheckResourceAttr(resourceName, "knowledge_base_configuration.0.type", "VECTOR"), - resource.TestCheckResourceAttr(resourceName, "storage_configuration.#", "1"), - resource.TestCheckResourceAttr(resourceName, "storage_configuration.0.type", "S3_VECTORS"), - resource.TestCheckResourceAttr(resourceName, "storage_configuration.0.s3_vectors_configuration.#", "1"), - resource.TestCheckResourceAttrPair(resourceName, "storage_configuration.0.s3_vectors_configuration.0.index_name", "aws_s3vectors_index.test", "index_name"), - ), - }, - }, - }) -} - func testAccCheckKnowledgeBaseDestroy(ctx context.Context) resource.TestCheckFunc { return func(s *terraform.State) error { conn := acctest.Provider.Meta().(*conns.AWSClient).BedrockAgentClient(ctx) @@ -1009,138 +946,3 @@ resource "aws_bedrockagent_knowledge_base" "test" { } `, rName, model)) } - -func testAccKnowledgeBaseConfig_S3VectorsBase(rName string) string { - return fmt.Sprintf(` -data "aws_region" "current" {} -data "aws_partition" "current" {} - -data "aws_iam_policy_document" "assume_role_bedrock" { - statement { - effect = "Allow" - principals { - type = "Service" - identifiers = ["bedrock.amazonaws.com"] - } - actions = ["sts:AssumeRole"] - } -} - -data "aws_iam_policy_document" "bedrock" { - statement { - effect = "Allow" - actions = ["bedrock:InvokeModel"] - resources = ["*"] - } - statement { - effect = "Allow" - actions = ["s3:ListBucket", "s3:GetObject"] - resources = ["*"] - } - statement { - effect = "Allow" - actions = [ - "s3vectors:GetIndex", - "s3vectors:QueryVectors", - "s3vectors:PutVectors", - "s3vectors:GetVectors", - "s3vectors:DeleteVectors" - ] - resources = ["*"] - } -} - -resource "aws_iam_role" "test" { - assume_role_policy = data.aws_iam_policy_document.assume_role_bedrock.json - name = %[1]q -} - -resource "aws_iam_role_policy" "test" { - role = aws_iam_role.test.name - policy = data.aws_iam_policy_document.bedrock.json -} - -resource "aws_s3vectors_vector_bucket" "test" { - vector_bucket_name = %[1]q - force_destroy = true -} - -resource "aws_s3vectors_index" "test" { - index_name = %[1]q - vector_bucket_name = aws_s3vectors_vector_bucket.test.vector_bucket_name - - data_type = "float32" - dimension = 256 - distance_metric = "euclidean" -} -`, rName) -} - -func testAccKnowledgeBaseConfig_S3VectorsByIndexARN(rName, model string) string { - return acctest.ConfigCompose( - testAccKnowledgeBaseConfig_S3VectorsBase(rName), - fmt.Sprintf(` -resource "aws_bedrockagent_knowledge_base" "test" { - depends_on = [ - aws_iam_role_policy.test, - ] - name = %[1]q - role_arn = aws_iam_role.test.arn - - knowledge_base_configuration { - vector_knowledge_base_configuration { - embedding_model_arn = "arn:${data.aws_partition.current.partition}:bedrock:${data.aws_region.current.region}::foundation-model/%[2]s" - embedding_model_configuration { - bedrock_embedding_model_configuration { - dimensions = 256 - embedding_data_type = "FLOAT32" - } - } - } - type = "VECTOR" - } - - storage_configuration { - type = "S3_VECTORS" - s3_vectors_configuration { - index_arn = aws_s3vectors_index.test.index_arn - } - } -} -`, rName, model)) -} - -func testAccKnowledgeBaseConfig_S3VectorsByIndexName(rName, model string) string { - return acctest.ConfigCompose( - testAccKnowledgeBaseConfig_S3VectorsBase(rName), - fmt.Sprintf(` -resource "aws_bedrockagent_knowledge_base" "test" { - depends_on = [ - aws_iam_role_policy.test, - ] - name = %[1]q - role_arn = aws_iam_role.test.arn - - knowledge_base_configuration { - vector_knowledge_base_configuration { - embedding_model_arn = "arn:${data.aws_partition.current.partition}:bedrock:${data.aws_region.current.region}::foundation-model/%[2]s" - embedding_model_configuration { - bedrock_embedding_model_configuration { - dimensions = 256 - embedding_data_type = "FLOAT32" - } - } - } - type = "VECTOR" - } - - storage_configuration { - type = "S3_VECTORS" - s3_vectors_configuration { - index_name = aws_s3vectors_index.test.index_name - vector_bucket_arn = aws_s3vectors_vector_bucket.test.vector_bucket_arn - } - } -} -`, rName, model)) -} From 79407e6c33a3576480ba6f5e1b25664768e5a4e1 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Mon, 8 Dec 2025 14:38:35 -0500 Subject: [PATCH 36/65] Revert "Implement s3_vectors_configuration block" This reverts commit bffb9f85c3c7ef7bbc3393cfb1323253dddaca79. --- .../service/bedrockagent/knowledge_base.go | 56 ------------------- 1 file changed, 56 deletions(-) diff --git a/internal/service/bedrockagent/knowledge_base.go b/internal/service/bedrockagent/knowledge_base.go index d22b0b8596ab..dfabab25bf3f 100644 --- a/internal/service/bedrockagent/knowledge_base.go +++ b/internal/service/bedrockagent/knowledge_base.go @@ -17,9 +17,7 @@ import ( "github.com/hashicorp/terraform-plugin-framework-timeouts/resource/timeouts" "github.com/hashicorp/terraform-plugin-framework-timetypes/timetypes" "github.com/hashicorp/terraform-plugin-framework-validators/listvalidator" - "github.com/hashicorp/terraform-plugin-framework-validators/objectvalidator" "github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator" - "github.com/hashicorp/terraform-plugin-framework/path" "github.com/hashicorp/terraform-plugin-framework/resource" "github.com/hashicorp/terraform-plugin-framework/resource/schema" "github.com/hashicorp/terraform-plugin-framework/resource/schema/listplanmodifier" @@ -498,53 +496,6 @@ func (r *knowledgeBaseResource) Schema(ctx context.Context, request resource.Sch }, }, }, - "s3_vectors_configuration": schema.ListNestedBlock{ - CustomType: fwtypes.NewListNestedObjectTypeOf[s3VectorsConfigurationModel](ctx), - Validators: []validator.List{ - listvalidator.SizeAtMost(1), - }, - PlanModifiers: []planmodifier.List{ - listplanmodifier.RequiresReplace(), - }, - NestedObject: schema.NestedBlockObject{ - Attributes: map[string]schema.Attribute{ - "index_arn": schema.StringAttribute{ - CustomType: fwtypes.ARNType, - Optional: true, - PlanModifiers: []planmodifier.String{ - stringplanmodifier.RequiresReplace(), - }, - Validators: []validator.String{ - stringvalidator.ConflictsWith(path.MatchRelative().AtParent().AtName("index_name"), path.MatchRelative().AtParent().AtName("vector_bucket_arn")), - }, - }, - "index_name": schema.StringAttribute{ - Optional: true, - PlanModifiers: []planmodifier.String{ - stringplanmodifier.RequiresReplace(), - }, - Validators: []validator.String{ - stringvalidator.AlsoRequires(path.MatchRelative().AtParent().AtName("vector_bucket_arn")), - stringvalidator.ConflictsWith(path.MatchRelative().AtParent().AtName("index_arn")), - }, - }, - "vector_bucket_arn": schema.StringAttribute{ - CustomType: fwtypes.ARNType, - Optional: true, - PlanModifiers: []planmodifier.String{ - stringplanmodifier.RequiresReplace(), - }, - Validators: []validator.String{ - stringvalidator.AlsoRequires(path.MatchRelative().AtParent().AtName("index_name")), - stringvalidator.ConflictsWith(path.MatchRelative().AtParent().AtName("index_arn")), - }, - }, - }, - Validators: []validator.Object{ - objectvalidator.AtLeastOneOf(path.MatchRelative().AtName("index_arn"), path.MatchRelative().AtName("index_name")), - }, - }, - }, }, }, }, @@ -889,7 +840,6 @@ type storageConfigurationModel struct { PineconeConfiguration fwtypes.ListNestedObjectValueOf[pineconeConfigurationModel] `tfsdk:"pinecone_configuration"` RDSConfiguration fwtypes.ListNestedObjectValueOf[rdsConfigurationModel] `tfsdk:"rds_configuration"` RedisEnterpriseCloudConfiguration fwtypes.ListNestedObjectValueOf[redisEnterpriseCloudConfigurationModel] `tfsdk:"redis_enterprise_cloud_configuration"` - S3VectorsConfiguration fwtypes.ListNestedObjectValueOf[s3VectorsConfigurationModel] `tfsdk:"s3_vectors_configuration"` Type types.String `tfsdk:"type"` } @@ -945,9 +895,3 @@ type redisEnterpriseCloudFieldMappingModel struct { TextField types.String `tfsdk:"text_field"` VectorField types.String `tfsdk:"vector_field"` } - -type s3VectorsConfigurationModel struct { - IndexARN fwtypes.ARN `tfsdk:"index_arn"` - IndexName types.String `tfsdk:"index_name"` - VectorBucketARN fwtypes.ARN `tfsdk:"vector_bucket_arn"` -} From bedb43b85a38936cfd922724935038c511d420b3 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Mon, 8 Dec 2025 14:40:03 -0500 Subject: [PATCH 37/65] Tweak CHANGELOG entry. --- .changelog/45468.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.changelog/45468.txt b/.changelog/45468.txt index e6df71453053..cf8b77a307fa 100644 --- a/.changelog/45468.txt +++ b/.changelog/45468.txt @@ -1,3 +1,3 @@ ```release-note:enhancement -resource/aws_bedrockagent_knowledge_base: Add storage_configuration.s3_vectors_configuration block +resource/aws_bedrockagent_knowledge_base: Add `storage_configuration.s3_vectors_configuration` block ``` From 4691f65c6e436c10e01c9babcff218d59b1ac1e3 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Mon, 8 Dec 2025 14:58:08 -0500 Subject: [PATCH 38/65] r/aws_bedrockagent_knowledge_base: Additions from #45468. --- .../service/bedrockagent/bedrockagent_test.go | 1 + .../service/bedrockagent/knowledge_base.go | 56 +++++ .../bedrockagent/knowledge_base_test.go | 210 ++++++++++++++++++ .../bedrockagent_knowledge_base.html.markdown | 60 ++++- 4 files changed, 326 insertions(+), 1 deletion(-) diff --git a/internal/service/bedrockagent/bedrockagent_test.go b/internal/service/bedrockagent/bedrockagent_test.go index c9a9872b94a4..8ec208957801 100644 --- a/internal/service/bedrockagent/bedrockagent_test.go +++ b/internal/service/bedrockagent/bedrockagent_test.go @@ -22,6 +22,7 @@ func TestAccBedrockAgent_serial(t *testing.T) { "OpenSearchServerlessSupplementalDataStorage": testAccKnowledgeBase_OpenSearchServerless_supplementalDataStorage, "KendraBasic": testAccKnowledgeBase_Kendra_basic, "OpenSearchManagedClusterBasic": testAccKnowledgeBase_OpenSearchManagedCluster_basic, + "S3Vectors": testAccKnowledgeBase_S3Vectors_update, }, "DataSource": { acctest.CtBasic: testAccDataSource_basic, diff --git a/internal/service/bedrockagent/knowledge_base.go b/internal/service/bedrockagent/knowledge_base.go index 280a12f91fb2..ca558735a3be 100644 --- a/internal/service/bedrockagent/knowledge_base.go +++ b/internal/service/bedrockagent/knowledge_base.go @@ -17,6 +17,7 @@ import ( "github.com/hashicorp/terraform-plugin-framework-timeouts/resource/timeouts" "github.com/hashicorp/terraform-plugin-framework-timetypes/timetypes" "github.com/hashicorp/terraform-plugin-framework-validators/listvalidator" + "github.com/hashicorp/terraform-plugin-framework-validators/objectvalidator" "github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator" "github.com/hashicorp/terraform-plugin-framework/path" "github.com/hashicorp/terraform-plugin-framework/resource" @@ -260,6 +261,7 @@ func (r *knowledgeBaseResource) Schema(ctx context.Context, request resource.Sch path.MatchRelative().AtParent().AtName("pinecone_configuration"), path.MatchRelative().AtParent().AtName("rds_configuration"), path.MatchRelative().AtParent().AtName("redis_enterprise_cloud_configuration"), + path.MatchRelative().AtParent().AtName("s3_vectors_configuration"), ), }, PlanModifiers: []planmodifier.List{ @@ -605,6 +607,53 @@ func (r *knowledgeBaseResource) Schema(ctx context.Context, request resource.Sch }, }, }, + "s3_vectors_configuration": schema.ListNestedBlock{ + CustomType: fwtypes.NewListNestedObjectTypeOf[s3VectorsConfigurationModel](ctx), + Validators: []validator.List{ + listvalidator.SizeAtMost(1), + }, + PlanModifiers: []planmodifier.List{ + listplanmodifier.RequiresReplace(), + }, + NestedObject: schema.NestedBlockObject{ + Attributes: map[string]schema.Attribute{ + "index_arn": schema.StringAttribute{ + CustomType: fwtypes.ARNType, + Optional: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.RequiresReplace(), + }, + Validators: []validator.String{ + stringvalidator.ConflictsWith(path.MatchRelative().AtParent().AtName("index_name"), path.MatchRelative().AtParent().AtName("vector_bucket_arn")), + }, + }, + "index_name": schema.StringAttribute{ + Optional: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.RequiresReplace(), + }, + Validators: []validator.String{ + stringvalidator.AlsoRequires(path.MatchRelative().AtParent().AtName("vector_bucket_arn")), + stringvalidator.ConflictsWith(path.MatchRelative().AtParent().AtName("index_arn")), + }, + }, + "vector_bucket_arn": schema.StringAttribute{ + CustomType: fwtypes.ARNType, + Optional: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.RequiresReplace(), + }, + Validators: []validator.String{ + stringvalidator.AlsoRequires(path.MatchRelative().AtParent().AtName("index_name")), + stringvalidator.ConflictsWith(path.MatchRelative().AtParent().AtName("index_arn")), + }, + }, + }, + Validators: []validator.Object{ + objectvalidator.AtLeastOneOf(path.MatchRelative().AtName("index_arn"), path.MatchRelative().AtName("index_name")), + }, + }, + }, }, }, }, @@ -966,6 +1015,7 @@ type storageConfigurationModel struct { PineconeConfiguration fwtypes.ListNestedObjectValueOf[pineconeConfigurationModel] `tfsdk:"pinecone_configuration"` RDSConfiguration fwtypes.ListNestedObjectValueOf[rdsConfigurationModel] `tfsdk:"rds_configuration"` RedisEnterpriseCloudConfiguration fwtypes.ListNestedObjectValueOf[redisEnterpriseCloudConfigurationModel] `tfsdk:"redis_enterprise_cloud_configuration"` + S3VectorsConfiguration fwtypes.ListNestedObjectValueOf[s3VectorsConfigurationModel] `tfsdk:"s3_vectors_configuration"` Type fwtypes.StringEnum[awstypes.KnowledgeBaseStorageType] `tfsdk:"type"` } @@ -1034,3 +1084,9 @@ type redisEnterpriseCloudFieldMappingModel struct { TextField types.String `tfsdk:"text_field"` VectorField types.String `tfsdk:"vector_field"` } + +type s3VectorsConfigurationModel struct { + IndexARN fwtypes.ARN `tfsdk:"index_arn"` + IndexName types.String `tfsdk:"index_name"` + VectorBucketARN fwtypes.ARN `tfsdk:"vector_bucket_arn"` +} diff --git a/internal/service/bedrockagent/knowledge_base_test.go b/internal/service/bedrockagent/knowledge_base_test.go index 08a11363a1ab..e2463f90d8f0 100644 --- a/internal/service/bedrockagent/knowledge_base_test.go +++ b/internal/service/bedrockagent/knowledge_base_test.go @@ -488,6 +488,79 @@ func testAccKnowledgeBase_OpenSearchManagedCluster_basic(t *testing.T) { "pinecone_configuration": knownvalue.ListSizeExact(0), "rds_configuration": knownvalue.ListSizeExact(0), "redis_enterprise_cloud_configuration": knownvalue.ListSizeExact(0), + "s3_vectors": knownvalue.ListSizeExact(0), + }), + })), + }, + }, + }, + }) +} + +func testAccKnowledgeBase_S3Vectors_update(t *testing.T) { + ctx := acctest.Context(t) + var knowledgebase awstypes.KnowledgeBase + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + resourceName := "aws_bedrockagent_knowledge_base.test" + foundationModel := "amazon.titan-embed-text-v2:0" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { + acctest.PreCheck(ctx, t) + }, + ErrorCheck: acctest.ErrorCheck(t, names.BedrockAgentServiceID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckKnowledgeBaseDestroy(ctx), + Steps: []resource.TestStep{ + { + Config: testAccKnowledgeBaseConfig_S3VectorsByIndexARN(rName, foundationModel), + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + }, + }, + Check: resource.ComposeTestCheckFunc( + testAccCheckKnowledgeBaseExists(ctx, resourceName, &knowledgebase), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("storage_configuration"), knownvalue.ListExact([]knownvalue.Check{ + knownvalue.MapExact(map[string]knownvalue.Check{ + "opensearch_managed_cluster_configuration": knownvalue.ListSizeExact(0), + "opensearch_serverless_configuration": knownvalue.ListSizeExact(0), + names.AttrType: tfknownvalue.StringExact(awstypes.KnowledgeBaseStorageTypeS3Vectors), + "pinecone_configuration": knownvalue.ListSizeExact(0), + "rds_configuration": knownvalue.ListSizeExact(0), + "redis_enterprise_cloud_configuration": knownvalue.ListSizeExact(0), + "s3_vectors_configuration": knownvalue.ListSizeExact(1), + }), + })), + }, + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + }, + { + Config: testAccKnowledgeBaseConfig_S3VectorsByIndexName(rName, foundationModel), + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionDestroyBeforeCreate), + }, + }, + Check: resource.ComposeTestCheckFunc( + testAccCheckKnowledgeBaseExists(ctx, resourceName, &knowledgebase), + ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("storage_configuration"), knownvalue.ListExact([]knownvalue.Check{ + knownvalue.MapExact(map[string]knownvalue.Check{ + "opensearch_managed_cluster_configuration": knownvalue.ListSizeExact(0), + "opensearch_serverless_configuration": knownvalue.ListSizeExact(0), + names.AttrType: tfknownvalue.StringExact(awstypes.KnowledgeBaseStorageTypeS3Vectors), + "pinecone_configuration": knownvalue.ListSizeExact(0), + "rds_configuration": knownvalue.ListSizeExact(0), + "redis_enterprise_cloud_configuration": knownvalue.ListSizeExact(0), + "s3_vectors_configuration": knownvalue.ListSizeExact(1), }), })), }, @@ -1416,3 +1489,140 @@ resource "aws_bedrockagent_knowledge_base" "test" { } `, rName, model)) } + +func testAccKnowledgeBaseConfig_baseS3Vectors(rName string) string { + return fmt.Sprintf(` +data "aws_region" "current" {} +data "aws_partition" "current" {} + +data "aws_iam_policy_document" "assume_role_bedrock" { + statement { + effect = "Allow" + principals { + type = "Service" + identifiers = ["bedrock.amazonaws.com"] + } + actions = ["sts:AssumeRole"] + } +} + +data "aws_iam_policy_document" "bedrock" { + statement { + effect = "Allow" + actions = ["bedrock:InvokeModel"] + resources = ["*"] + } + statement { + effect = "Allow" + actions = ["s3:ListBucket", "s3:GetObject"] + resources = ["*"] + } + statement { + effect = "Allow" + actions = [ + "s3vectors:GetIndex", + "s3vectors:QueryVectors", + "s3vectors:PutVectors", + "s3vectors:GetVectors", + "s3vectors:DeleteVectors" + ] + resources = ["*"] + } +} + +resource "aws_iam_role" "test" { + assume_role_policy = data.aws_iam_policy_document.assume_role_bedrock.json + name = %[1]q +} + +resource "aws_iam_role_policy" "test" { + role = aws_iam_role.test.name + policy = data.aws_iam_policy_document.bedrock.json +} + +resource "aws_s3vectors_vector_bucket" "test" { + vector_bucket_name = %[1]q + force_destroy = true +} + +resource "aws_s3vectors_index" "test" { + index_name = %[1]q + vector_bucket_name = aws_s3vectors_vector_bucket.test.vector_bucket_name + + data_type = "float32" + dimension = 256 + distance_metric = "euclidean" +} +`, rName) +} + +func testAccKnowledgeBaseConfig_S3VectorsByIndexARN(rName, model string) string { + return acctest.ConfigCompose(testAccKnowledgeBaseConfig_baseS3Vectors(rName), fmt.Sprintf(` +resource "aws_bedrockagent_knowledge_base" "test" { + depends_on = [ + aws_iam_role_policy.test, + ] + + name = %[1]q + role_arn = aws_iam_role.test.arn + + knowledge_base_configuration { + type = "VECTOR" + + vector_knowledge_base_configuration { + embedding_model_arn = "arn:${data.aws_partition.current.partition}:bedrock:${data.aws_region.current.region}::foundation-model/%[2]s" + embedding_model_configuration { + bedrock_embedding_model_configuration { + dimensions = 256 + embedding_data_type = "FLOAT32" + } + } + } + } + + storage_configuration { + type = "S3_VECTORS" + + s3_vectors_configuration { + index_arn = aws_s3vectors_index.test.index_arn + } + } +} +`, rName, model)) +} + +func testAccKnowledgeBaseConfig_S3VectorsByIndexName(rName, model string) string { + return acctest.ConfigCompose(testAccKnowledgeBaseConfig_baseS3Vectors(rName), fmt.Sprintf(` +resource "aws_bedrockagent_knowledge_base" "test" { + depends_on = [ + aws_iam_role_policy.test, + ] + + name = %[1]q + role_arn = aws_iam_role.test.arn + + knowledge_base_configuration { + type = "VECTOR" + + vector_knowledge_base_configuration { + embedding_model_arn = "arn:${data.aws_partition.current.partition}:bedrock:${data.aws_region.current.region}::foundation-model/%[2]s" + embedding_model_configuration { + bedrock_embedding_model_configuration { + dimensions = 256 + embedding_data_type = "FLOAT32" + } + } + } + } + + storage_configuration { + type = "S3_VECTORS" + + s3_vectors_configuration { + index_name = aws_s3vectors_index.test.index_name + vector_bucket_arn = aws_s3vectors_vector_bucket.test.vector_bucket_arn + } + } +} +`, rName, model)) +} diff --git a/website/docs/r/bedrockagent_knowledge_base.html.markdown b/website/docs/r/bedrockagent_knowledge_base.html.markdown index 5e1fa6f698dc..ab9c8dc682f5 100644 --- a/website/docs/r/bedrockagent_knowledge_base.html.markdown +++ b/website/docs/r/bedrockagent_knowledge_base.html.markdown @@ -45,6 +45,7 @@ resource "aws_bedrockagent_knowledge_base" "example" { resource "aws_bedrockagent_knowledge_base" "kendra_example" { name = "example-kendra-kb" role_arn = aws_iam_role.example.arn + knowledge_base_configuration { type = "KENDRA" kendra_knowledge_base_configuration { @@ -60,18 +61,21 @@ resource "aws_bedrockagent_knowledge_base" "kendra_example" { resource "aws_bedrockagent_knowledge_base" "example" { name = "example" role_arn = aws_iam_role.example.arn + knowledge_base_configuration { vector_knowledge_base_configuration { embedding_model_arn = "arn:aws:bedrock:us-west-2::foundation-model/amazon.titan-embed-text-v2:0" } type = "VECTOR" } + storage_configuration { type = "OPENSEARCH_MANAGED_CLUSTER" opensearch_managed_cluster_configuration { domain_arn = "arn:aws:es:us-west-2:123456789012:domain/example-domain" domain_endpoint = "https://search-example-domain.us-west-2.es.amazonaws.com" vector_index_name = "example_index" + field_mapping { metadata_field = "metadata" text_field = "chunks" @@ -111,6 +115,7 @@ resource "aws_bedrockagent_knowledge_base" "example" { } type = "VECTOR" } + storage_configuration { type = "OPENSEARCH_SERVERLESS" opensearch_serverless_configuration { @@ -126,6 +131,48 @@ resource "aws_bedrockagent_knowledge_base" "example" { } ``` +### S3 Vectors Configuration + +```terraform +resource "aws_s3vectors_vector_bucket" "example" { + vector_bucket_name = "example-bucket" +} + +resource "aws_s3vectors_index" "example" { + index_name = "example-index" + vector_bucket_name = aws_s3vectors_vector_bucket.example.vector_bucket_name + + data_type = "float32" + dimension = 256 + distance_metric = "euclidean" +} + +resource "aws_bedrockagent_knowledge_base" "example" { + name = "example-s3vectors-kb" + role_arn = aws_iam_role.example.arn + + knowledge_base_configuration { + vector_knowledge_base_configuration { + embedding_model_arn = "arn:aws:bedrock:us-west-2::foundation-model/amazon.titan-embed-text-v2:0" + embedding_model_configuration { + bedrock_embedding_model_configuration { + dimensions = 256 + embedding_data_type = "FLOAT32" + } + } + } + type = "VECTOR" + } + + storage_configuration { + type = "S3_VECTORS" + s3_vectors_configuration { + index_arn = aws_s3vectors_index.example.index_arn + } + } +} +``` + ## Argument Reference The following arguments are required: @@ -199,12 +246,13 @@ The `s3_location` configuration block supports the following arguments: The `storage_configuration` configuration block supports the following arguments: -* `type` - (Required) Vector store service in which the knowledge base is stored. Valid Values: `OPENSEARCH_SERVERLESS`, `OPENSEARCH_MANAGED_CLUSTER`, `PINECONE`, `REDIS_ENTERPRISE_CLOUD`, `RDS`. +* `type` - (Required) Vector store service in which the knowledge base is stored. Valid Values: `OPENSEARCH_SERVERLESS`, `OPENSEARCH_MANAGED_CLUSTER`, `PINECONE`, `REDIS_ENTERPRISE_CLOUD`, `RDS`, `S3_VECTORS`. * `opensearch_managed_cluster_configuration` - (Optional) The storage configuration of the knowledge base in Amazon OpenSearch Service Managed Cluster. See [`opensearch_managed_cluster_configuration` block](#opensearch_managed_cluster_configuration-block) for details. * `opensearch_serverless_configuration` - (Optional) The storage configuration of the knowledge base in Amazon OpenSearch Service Serverless. See [`opensearch_serverless_configuration` block](#opensearch_serverless_configuration-block) for details. * `pinecone_configuration` - (Optional) The storage configuration of the knowledge base in Pinecone. See [`pinecone_configuration` block](#pinecone_configuration-block) for details. * `rds_configuration` - (Optional) Details about the storage configuration of the knowledge base in Amazon RDS. For more information, see [Create a vector index in Amazon RDS](https://docs.aws.amazon.com/bedrock/latest/userguide/knowledge-base-setup.html). See [`rds_configuration` block](#rds_configuration-block) for details. * `redis_enterprise_cloud_configuration` - (Optional) The storage configuration of the knowledge base in Redis Enterprise Cloud. See [`redis_enterprise_cloud_configuration` block](#redis_enterprise_cloud_configuration-block) for details. +* `s3_vectors_configuration` - (Optional) The storage configuration of the knowledge base in Amazon S3 Vectors. See [`s3_vectors_configuration` block](#s3_vectors_configuration-block) for details. ### `opensearch_managed_cluster_configuration` block @@ -267,6 +315,16 @@ The `redis_enterprise_cloud_configuration` configuration block supports the foll * `vector_field` - (Required) Name of the field in which Amazon Bedrock stores the vector embeddings for your data sources. * `vector_index_name` - (Required) Name of the vector index. + +### `s3_vectors_configuration` block + +The `s3_vectors_configuration` configuration block supports the following arguments. +Either `index_arn`, or both `index_name` and `vector_bucket_arn` must be specified. + +* `index_arn` - (Optional) ARN of the S3 Vectors index. Conflicts with `index_name` and `vector_bucket_arn`. +* `index_name` - (Optional) Name of the S3 Vectors index. Must be specified with `vector_bucket_arn`. Conflicts with `index_arn`. +* `vector_bucket_arn` - (Optional) ARN of the S3 Vectors vector bucket. Must be specified with `index_name`. Conflicts with `index_arn`. + ## Attribute Reference This resource exports the following attributes in addition to the arguments above: From 7412b6fdfea2fa92a361dcd782c149e583be3455 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Mon, 8 Dec 2025 15:09:09 -0500 Subject: [PATCH 39/65] Acceptance test output: MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit % make testacc TESTARGS='-run=TestAccBedrockAgent_serial/KnowledgeBase/S3Vectors' PKG=bedrockagent make: Verifying source code with gofmt... ==> Checking that code complies with gofmt requirements... make: Running acceptance tests on branch: 🌿 f-aws_bedrockagent_knowledge_base-enhancements 🌿... TF_ACC=1 go1.24.11 test ./internal/service/bedrockagent/... -v -count 1 -parallel 20 -run=TestAccBedrockAgent_serial/KnowledgeBase/S3Vectors -timeout 360m -vet=off 2025/12/08 15:07:21 Creating Terraform AWS Provider (SDKv2-style)... 2025/12/08 15:07:21 Initializing Terraform AWS Provider (SDKv2-style)... === RUN TestAccBedrockAgent_serial === PAUSE TestAccBedrockAgent_serial === CONT TestAccBedrockAgent_serial === RUN TestAccBedrockAgent_serial/KnowledgeBase === RUN TestAccBedrockAgent_serial/KnowledgeBase/S3Vectors --- PASS: TestAccBedrockAgent_serial (42.81s) --- PASS: TestAccBedrockAgent_serial/KnowledgeBase (42.81s) --- PASS: TestAccBedrockAgent_serial/KnowledgeBase/S3Vectors (42.81s) PASS ok github.com/hashicorp/terraform-provider-aws/internal/service/bedrockagent 48.179s From b428e48ff33b5f5ac49ebb3d6d66d30983aec7b5 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Mon, 8 Dec 2025 15:16:38 -0500 Subject: [PATCH 40/65] Fix markdown-lint 'MD012/no-multiple-blanks Multiple consecutive blank lines [Expected: 1; Actual: 2]'. --- website/docs/r/bedrockagent_knowledge_base.html.markdown | 1 - 1 file changed, 1 deletion(-) diff --git a/website/docs/r/bedrockagent_knowledge_base.html.markdown b/website/docs/r/bedrockagent_knowledge_base.html.markdown index ab9c8dc682f5..7faefceb9ac0 100644 --- a/website/docs/r/bedrockagent_knowledge_base.html.markdown +++ b/website/docs/r/bedrockagent_knowledge_base.html.markdown @@ -315,7 +315,6 @@ The `redis_enterprise_cloud_configuration` configuration block supports the foll * `vector_field` - (Required) Name of the field in which Amazon Bedrock stores the vector embeddings for your data sources. * `vector_index_name` - (Required) Name of the vector index. - ### `s3_vectors_configuration` block The `s3_vectors_configuration` configuration block supports the following arguments. From 41ac93efc17f2e4c6f6318e65ffd802c9d617e68 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Mon, 8 Dec 2025 15:38:34 -0500 Subject: [PATCH 41/65] r/aws_bedrockagent_knowledge_base: Add `storage_configuration.mongo_db_atlas_configuration` argument. --- .changelog/37220.txt | 3 + .../service/bedrockagent/knowledge_base.go | 118 +++++++++++++++++- .../bedrockagent/knowledge_base_test.go | 3 + .../bedrockagent_knowledge_base.html.markdown | 19 ++- 4 files changed, 138 insertions(+), 5 deletions(-) create mode 100644 .changelog/37220.txt diff --git a/.changelog/37220.txt b/.changelog/37220.txt new file mode 100644 index 000000000000..b6b6d1aeb715 --- /dev/null +++ b/.changelog/37220.txt @@ -0,0 +1,3 @@ +```release-note:enhancement +resource/aws_bedrockagent_knowledge_base: Add `storage_configuration.mongo_db_atlas_configuration` argument +``` \ No newline at end of file diff --git a/internal/service/bedrockagent/knowledge_base.go b/internal/service/bedrockagent/knowledge_base.go index ca558735a3be..3020348d8ac6 100644 --- a/internal/service/bedrockagent/knowledge_base.go +++ b/internal/service/bedrockagent/knowledge_base.go @@ -251,11 +251,12 @@ func (r *knowledgeBaseResource) Schema(ctx context.Context, request resource.Sch }, }, Blocks: map[string]schema.Block{ - "opensearch_managed_cluster_configuration": schema.ListNestedBlock{ - CustomType: fwtypes.NewListNestedObjectTypeOf[openSearchManagedClusterConfigurationModel](ctx), + "mongo_db_atlas_configuration": schema.ListNestedBlock{ + CustomType: fwtypes.NewListNestedObjectTypeOf[mongoDBAtlasConfigurationModel](ctx), Validators: []validator.List{ listvalidator.SizeAtMost(1), listvalidator.ExactlyOneOf( + path.MatchRelative().AtParent().AtName("mongo_db_atlas_configuration"), path.MatchRelative().AtParent().AtName("opensearch_managed_cluster_configuration"), path.MatchRelative().AtParent().AtName("opensearch_serverless_configuration"), path.MatchRelative().AtParent().AtName("pinecone_configuration"), @@ -267,6 +268,97 @@ func (r *knowledgeBaseResource) Schema(ctx context.Context, request resource.Sch PlanModifiers: []planmodifier.List{ listplanmodifier.RequiresReplace(), }, + NestedObject: schema.NestedBlockObject{ + Attributes: map[string]schema.Attribute{ + "collection_name": schema.StringAttribute{ + Required: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.RequiresReplace(), + }, + }, + "credentials_secret_arn": schema.StringAttribute{ + CustomType: fwtypes.ARNType, + Required: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.RequiresReplace(), + }, + }, + "database_name": schema.StringAttribute{ + Required: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.RequiresReplace(), + }, + }, + "endpoint": schema.StringAttribute{ + Required: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.RequiresReplace(), + }, + }, + "endpoint_service_name": schema.StringAttribute{ + Optional: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.RequiresReplace(), + }, + }, + "text_index_name": schema.StringAttribute{ + Optional: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.RequiresReplace(), + }, + }, + "vector_index_name": schema.StringAttribute{ + Required: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.RequiresReplace(), + }, + }, + }, + Blocks: map[string]schema.Block{ + "field_mapping": schema.ListNestedBlock{ + CustomType: fwtypes.NewListNestedObjectTypeOf[mongoDBAtlasFieldMappingModel](ctx), + Validators: []validator.List{ + listvalidator.IsRequired(), + listvalidator.SizeAtLeast(1), + listvalidator.SizeAtMost(1), + }, + PlanModifiers: []planmodifier.List{ + listplanmodifier.RequiresReplace(), + }, + NestedObject: schema.NestedBlockObject{ + Attributes: map[string]schema.Attribute{ + "metadata_field": schema.StringAttribute{ + Required: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.RequiresReplace(), + }, + }, + "text_field": schema.StringAttribute{ + Required: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.RequiresReplace(), + }, + }, + "vector_field": schema.StringAttribute{ + Required: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.RequiresReplace(), + }, + }, + }, + }, + }, + }, + }, + }, + "opensearch_managed_cluster_configuration": schema.ListNestedBlock{ + CustomType: fwtypes.NewListNestedObjectTypeOf[openSearchManagedClusterConfigurationModel](ctx), + Validators: []validator.List{ + listvalidator.SizeAtMost(1), + }, + PlanModifiers: []planmodifier.List{ + listplanmodifier.RequiresReplace(), + }, NestedObject: schema.NestedBlockObject{ Attributes: map[string]schema.Attribute{ "domain_arn": schema.StringAttribute{ @@ -1010,8 +1102,9 @@ type kendraKnowledgeBaseConfigurationModel struct { } type storageConfigurationModel struct { - OpensearchManagedClusterConfiguration fwtypes.ListNestedObjectValueOf[openSearchManagedClusterConfigurationModel] `tfsdk:"opensearch_managed_cluster_configuration"` - OpensearchServerlessConfiguration fwtypes.ListNestedObjectValueOf[openSearchServerlessConfigurationModel] `tfsdk:"opensearch_serverless_configuration"` + MongoDBAtlasConfiguration fwtypes.ListNestedObjectValueOf[mongoDBAtlasConfigurationModel] `tfsdk:"mongo_db_atlas_configuration"` + OpenSearchManagedClusterConfiguration fwtypes.ListNestedObjectValueOf[openSearchManagedClusterConfigurationModel] `tfsdk:"opensearch_managed_cluster_configuration"` + OpenSearchServerlessConfiguration fwtypes.ListNestedObjectValueOf[openSearchServerlessConfigurationModel] `tfsdk:"opensearch_serverless_configuration"` PineconeConfiguration fwtypes.ListNestedObjectValueOf[pineconeConfigurationModel] `tfsdk:"pinecone_configuration"` RDSConfiguration fwtypes.ListNestedObjectValueOf[rdsConfigurationModel] `tfsdk:"rds_configuration"` RedisEnterpriseCloudConfiguration fwtypes.ListNestedObjectValueOf[redisEnterpriseCloudConfigurationModel] `tfsdk:"redis_enterprise_cloud_configuration"` @@ -1019,6 +1112,23 @@ type storageConfigurationModel struct { Type fwtypes.StringEnum[awstypes.KnowledgeBaseStorageType] `tfsdk:"type"` } +type mongoDBAtlasConfigurationModel struct { + CollectionName types.String `tfsdk:"collection_name"` + CredentialsSecretARN fwtypes.ARN `tfsdk:"credentials_secret_arn"` + DatabaseName types.String `tfsdk:"database_name"` + Endpoint types.String `tfsdk:"endpoint"` + EndpointServiceName types.String `tfsdk:"endpoint_service_name"` + FieldMapping fwtypes.ListNestedObjectValueOf[mongoDBAtlasFieldMappingModel] `tfsdk:"field_mapping"` + TextIndexName types.String `tfsdk:"text_index_name"` + VectorIndexName types.String `tfsdk:"vector_index_name"` +} + +type mongoDBAtlasFieldMappingModel struct { + MetadataField types.String `tfsdk:"metadata_field"` + TextField types.String `tfsdk:"text_field"` + VectorField types.String `tfsdk:"vector_field"` +} + type openSearchManagedClusterConfigurationModel struct { DomainARN fwtypes.ARN `tfsdk:"domain_arn"` DomainEndpoint types.String `tfsdk:"domain_endpoint"` diff --git a/internal/service/bedrockagent/knowledge_base_test.go b/internal/service/bedrockagent/knowledge_base_test.go index e2463f90d8f0..c97dd7171fe7 100644 --- a/internal/service/bedrockagent/knowledge_base_test.go +++ b/internal/service/bedrockagent/knowledge_base_test.go @@ -482,6 +482,7 @@ func testAccKnowledgeBase_OpenSearchManagedCluster_basic(t *testing.T) { })), statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("storage_configuration"), knownvalue.ListExact([]knownvalue.Check{ knownvalue.MapExact(map[string]knownvalue.Check{ + "mongo_db_atlas_configuration": knownvalue.ListSizeExact(0), "opensearch_managed_cluster_configuration": knownvalue.ListSizeExact(1), "opensearch_serverless_configuration": knownvalue.ListSizeExact(0), names.AttrType: tfknownvalue.StringExact(awstypes.KnowledgeBaseStorageTypeOpensearchManagedCluster), @@ -525,6 +526,7 @@ func testAccKnowledgeBase_S3Vectors_update(t *testing.T) { ConfigStateChecks: []statecheck.StateCheck{ statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("storage_configuration"), knownvalue.ListExact([]knownvalue.Check{ knownvalue.MapExact(map[string]knownvalue.Check{ + "mongo_db_atlas_configuration": knownvalue.ListSizeExact(0), "opensearch_managed_cluster_configuration": knownvalue.ListSizeExact(0), "opensearch_serverless_configuration": knownvalue.ListSizeExact(0), names.AttrType: tfknownvalue.StringExact(awstypes.KnowledgeBaseStorageTypeS3Vectors), @@ -554,6 +556,7 @@ func testAccKnowledgeBase_S3Vectors_update(t *testing.T) { ConfigStateChecks: []statecheck.StateCheck{ statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("storage_configuration"), knownvalue.ListExact([]knownvalue.Check{ knownvalue.MapExact(map[string]knownvalue.Check{ + "mongo_db_atlas_configuration": knownvalue.ListSizeExact(0), "opensearch_managed_cluster_configuration": knownvalue.ListSizeExact(0), "opensearch_serverless_configuration": knownvalue.ListSizeExact(0), names.AttrType: tfknownvalue.StringExact(awstypes.KnowledgeBaseStorageTypeS3Vectors), diff --git a/website/docs/r/bedrockagent_knowledge_base.html.markdown b/website/docs/r/bedrockagent_knowledge_base.html.markdown index 7faefceb9ac0..77be7071e88e 100644 --- a/website/docs/r/bedrockagent_knowledge_base.html.markdown +++ b/website/docs/r/bedrockagent_knowledge_base.html.markdown @@ -246,7 +246,8 @@ The `s3_location` configuration block supports the following arguments: The `storage_configuration` configuration block supports the following arguments: -* `type` - (Required) Vector store service in which the knowledge base is stored. Valid Values: `OPENSEARCH_SERVERLESS`, `OPENSEARCH_MANAGED_CLUSTER`, `PINECONE`, `REDIS_ENTERPRISE_CLOUD`, `RDS`, `S3_VECTORS`. +* `type` - (Required) Vector store service in which the knowledge base is stored. Valid Values: `MONGO_DB_ATLAS`, `OPENSEARCH_SERVERLESS`, `OPENSEARCH_MANAGED_CLUSTER`, `PINECONE`, `REDIS_ENTERPRISE_CLOUD`, `RDS`, `S3_VECTORS`. +* `mongo_db_atlas_configuration` – (Optional) The storage configuration of the knowledge base in MongoDB Atlas. See [`opensearch_managed_cluster_comongo_db_atlas_configurationnfiguration` block](#mongo_db_atlas_configuration-block) for details. * `opensearch_managed_cluster_configuration` - (Optional) The storage configuration of the knowledge base in Amazon OpenSearch Service Managed Cluster. See [`opensearch_managed_cluster_configuration` block](#opensearch_managed_cluster_configuration-block) for details. * `opensearch_serverless_configuration` - (Optional) The storage configuration of the knowledge base in Amazon OpenSearch Service Serverless. See [`opensearch_serverless_configuration` block](#opensearch_serverless_configuration-block) for details. * `pinecone_configuration` - (Optional) The storage configuration of the knowledge base in Pinecone. See [`pinecone_configuration` block](#pinecone_configuration-block) for details. @@ -254,6 +255,22 @@ The `storage_configuration` configuration block supports the following arguments * `redis_enterprise_cloud_configuration` - (Optional) The storage configuration of the knowledge base in Redis Enterprise Cloud. See [`redis_enterprise_cloud_configuration` block](#redis_enterprise_cloud_configuration-block) for details. * `s3_vectors_configuration` - (Optional) The storage configuration of the knowledge base in Amazon S3 Vectors. See [`s3_vectors_configuration` block](#s3_vectors_configuration-block) for details. +### `mongo_db_atlas_configuration` block + +The `mongo_db_atlas_configuration` configuration block supports the following arguments: + +* `collection_name` – (Required) The name of the collection in the MongoDB Atlas database. +* `credentials_secret_arn` – (Required) The ARN of the secret that you created in AWS Secrets Manager that is linked to your MongoDB Atlas database. +* `database_name` – (Required) The name of the database in the MongoDB Atlas database. +* `endpoint` – (Required) The endpoint URL of the MongoDB Atlas database. +* `field_mapping` – (Required) Contains the names of the fields to which to map information about the vector store. + * `metadata_field` – (Required) The name of the field in which Amazon Bedrock stores metadata about the vector store. + * `text_field` – (Required) The name of the field in which Amazon Bedrock stores the raw text from your data. The text is split according to the chunking strategy you choose. + * `vector_field` – (Required) The name of the field in which Amazon Bedrock stores the vector embeddings for your data sources. +* `vector_index_name` – (Required) The name of the vector index. +* `endpoint_service_name` – (Optional) The name of the service that hosts the MongoDB Atlas database. +* `text_index_name` – (Optional) The name of the vector index. + ### `opensearch_managed_cluster_configuration` block The `opensearch_managed_cluster_configuration` configuration block supports the following arguments: From 949118c8ea7976cb2a8189df5d21e81047eabe84 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Mon, 8 Dec 2025 16:15:47 -0500 Subject: [PATCH 42/65] Run 'make fix-constants PKG=bedrockagent'. --- internal/service/bedrockagent/knowledge_base.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/internal/service/bedrockagent/knowledge_base.go b/internal/service/bedrockagent/knowledge_base.go index 3020348d8ac6..69bd07eff67d 100644 --- a/internal/service/bedrockagent/knowledge_base.go +++ b/internal/service/bedrockagent/knowledge_base.go @@ -283,13 +283,13 @@ func (r *knowledgeBaseResource) Schema(ctx context.Context, request resource.Sch stringplanmodifier.RequiresReplace(), }, }, - "database_name": schema.StringAttribute{ + names.AttrDatabaseName: schema.StringAttribute{ Required: true, PlanModifiers: []planmodifier.String{ stringplanmodifier.RequiresReplace(), }, }, - "endpoint": schema.StringAttribute{ + names.AttrEndpoint: schema.StringAttribute{ Required: true, PlanModifiers: []planmodifier.String{ stringplanmodifier.RequiresReplace(), From 650036dbb49a7a96a08d717c575ddd53abe62980 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Mon, 8 Dec 2025 16:19:58 -0500 Subject: [PATCH 43/65] testAccKnowledgeBase_disappears: Use S3 Vectors instead of RDS. --- .../service/bedrockagent/bedrockagent_test.go | 2 +- .../bedrockagent/knowledge_base_test.go | 197 +++++++++--------- 2 files changed, 95 insertions(+), 104 deletions(-) diff --git a/internal/service/bedrockagent/bedrockagent_test.go b/internal/service/bedrockagent/bedrockagent_test.go index 8ec208957801..a419bb715a35 100644 --- a/internal/service/bedrockagent/bedrockagent_test.go +++ b/internal/service/bedrockagent/bedrockagent_test.go @@ -14,7 +14,7 @@ func TestAccBedrockAgent_serial(t *testing.T) { testCases := map[string]map[string]func(t *testing.T){ "KnowledgeBase": { - acctest.CtBasic: testAccKnowledgeBase_basic, + "RDSBasic": testAccKnowledgeBase_RDS_basic, acctest.CtDisappears: testAccKnowledgeBase_disappears, "tags": testAccKnowledgeBase_tags, "OpenSearchServerlessBasic": testAccKnowledgeBase_OpenSearchServerless_basic, diff --git a/internal/service/bedrockagent/knowledge_base_test.go b/internal/service/bedrockagent/knowledge_base_test.go index c97dd7171fe7..7ca0286f8839 100644 --- a/internal/service/bedrockagent/knowledge_base_test.go +++ b/internal/service/bedrockagent/knowledge_base_test.go @@ -26,10 +26,43 @@ import ( "github.com/hashicorp/terraform-provider-aws/names" ) +func testAccKnowledgeBase_disappears(t *testing.T) { + ctx := acctest.Context(t) + var knowledgebase awstypes.KnowledgeBase + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + resourceName := "aws_bedrockagent_knowledge_base.test" + foundationModel := "amazon.titan-embed-text-v2:0" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.BedrockAgentServiceID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckKnowledgeBaseDestroy(ctx), + Steps: []resource.TestStep{ + { + Config: testAccKnowledgeBaseConfig_S3VectorsByIndexARN(rName, foundationModel), + Check: resource.ComposeTestCheckFunc( + testAccCheckKnowledgeBaseExists(ctx, resourceName, &knowledgebase), + acctest.CheckFrameworkResourceDisappears(ctx, acctest.Provider, tfbedrockagent.ResourceKnowledgeBase, resourceName), + ), + ExpectNonEmptyPlan: true, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + }, + PostApplyPostRefresh: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + }, + }, + }, + }, + }) +} + // Prerequisites: // * psql run via null_resource/provisioner "local-exec" // * jq for parsing output from aws cli to retrieve postgres password -func testAccKnowledgeBase_basic(t *testing.T) { +func testAccKnowledgeBase_tags(t *testing.T) { acctest.SkipIfExeNotOnPath(t, "psql") acctest.SkipIfExeNotOnPath(t, "jq") acctest.SkipIfExeNotOnPath(t, "aws") @@ -55,30 +88,19 @@ func testAccKnowledgeBase_basic(t *testing.T) { CheckDestroy: testAccCheckKnowledgeBaseDestroy(ctx), Steps: []resource.TestStep{ { - Config: testAccKnowledgeBaseConfig_basicRDS(rName, foundationModel, ""), + Config: testAccKnowledgeBaseConfig_tags1(rName, foundationModel, acctest.CtKey1, acctest.CtValue1), ConfigPlanChecks: resource.ConfigPlanChecks{ PreApply: []plancheck.PlanCheck{ plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), }, }, + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), + })), + }, Check: resource.ComposeTestCheckFunc( testAccCheckKnowledgeBaseExists(ctx, resourceName, &knowledgebase), - resource.TestCheckNoResourceAttr(resourceName, names.AttrDescription), - resource.TestCheckResourceAttr(resourceName, "knowledge_base_configuration.#", "1"), - resource.TestCheckResourceAttr(resourceName, "knowledge_base_configuration.0.vector_knowledge_base_configuration.#", "1"), - resource.TestCheckResourceAttr(resourceName, "knowledge_base_configuration.0.type", "VECTOR"), - resource.TestCheckResourceAttr(resourceName, names.AttrName, rName), - resource.TestCheckResourceAttrPair(resourceName, names.AttrRoleARN, "aws_iam_role.test", names.AttrARN), - resource.TestCheckResourceAttr(resourceName, "storage_configuration.#", "1"), - resource.TestCheckResourceAttr(resourceName, "storage_configuration.0.type", "RDS"), - resource.TestCheckResourceAttr(resourceName, "storage_configuration.0.rds_configuration.#", "1"), - resource.TestCheckResourceAttr(resourceName, "storage_configuration.0.rds_configuration.0.table_name", "bedrock_integration.bedrock_kb"), - resource.TestCheckResourceAttr(resourceName, "storage_configuration.0.rds_configuration.0.field_mapping.#", "1"), - resource.TestCheckResourceAttr(resourceName, "storage_configuration.0.rds_configuration.0.field_mapping.0.vector_field", "embedding"), - resource.TestCheckResourceAttr(resourceName, "storage_configuration.0.rds_configuration.0.field_mapping.0.text_field", "chunks"), - resource.TestCheckResourceAttr(resourceName, "storage_configuration.0.rds_configuration.0.field_mapping.0.metadata_field", "metadata"), - resource.TestCheckResourceAttr(resourceName, "storage_configuration.0.rds_configuration.0.field_mapping.0.primary_key_field", names.AttrID), - resource.TestCheckResourceAttr(resourceName, "storage_configuration.0.rds_configuration.0.field_mapping.0.custom_metadata_field", "custom_metadata"), ), }, { @@ -87,71 +109,37 @@ func testAccKnowledgeBase_basic(t *testing.T) { ImportStateVerify: true, }, { - Config: testAccKnowledgeBaseConfig_updateRDS(rName, foundationModel, "test description"), + Config: testAccKnowledgeBaseConfig_tags2(rName, foundationModel, acctest.CtKey1, acctest.CtValue1Updated, acctest.CtKey2, acctest.CtValue2), ConfigPlanChecks: resource.ConfigPlanChecks{ PreApply: []plancheck.PlanCheck{ plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), }, }, + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1Updated), + acctest.CtKey2: knownvalue.StringExact(acctest.CtValue2), + })), + }, Check: resource.ComposeTestCheckFunc( testAccCheckKnowledgeBaseExists(ctx, resourceName, &knowledgebase), - resource.TestCheckResourceAttr(resourceName, names.AttrDescription, "test description"), - resource.TestCheckResourceAttr(resourceName, "knowledge_base_configuration.#", "1"), - resource.TestCheckResourceAttr(resourceName, "knowledge_base_configuration.0.vector_knowledge_base_configuration.#", "1"), - resource.TestCheckResourceAttr(resourceName, "knowledge_base_configuration.0.type", "VECTOR"), - resource.TestCheckResourceAttr(resourceName, names.AttrName, rName+"-update"), - resource.TestCheckResourceAttrPair(resourceName, names.AttrRoleARN, "aws_iam_role.test_update", names.AttrARN), - resource.TestCheckResourceAttr(resourceName, "storage_configuration.#", "1"), - resource.TestCheckResourceAttr(resourceName, "storage_configuration.0.type", "RDS"), - resource.TestCheckResourceAttr(resourceName, "storage_configuration.0.rds_configuration.#", "1"), - resource.TestCheckResourceAttr(resourceName, "storage_configuration.0.rds_configuration.0.table_name", "bedrock_integration.bedrock_kb"), - resource.TestCheckResourceAttr(resourceName, "storage_configuration.0.rds_configuration.0.field_mapping.#", "1"), - resource.TestCheckResourceAttr(resourceName, "storage_configuration.0.rds_configuration.0.field_mapping.0.vector_field", "embedding"), - resource.TestCheckResourceAttr(resourceName, "storage_configuration.0.rds_configuration.0.field_mapping.0.text_field", "chunks"), - resource.TestCheckResourceAttr(resourceName, "storage_configuration.0.rds_configuration.0.field_mapping.0.metadata_field", "metadata"), - resource.TestCheckResourceAttr(resourceName, "storage_configuration.0.rds_configuration.0.field_mapping.0.primary_key_field", names.AttrID), - resource.TestCheckResourceAttr(resourceName, "storage_configuration.0.rds_configuration.0.field_mapping.0.custom_metadata_field", "custom_metadata"), ), }, - }, - }) -} - -// Prerequisites: -// * psql run via null_resource/provisioner "local-exec" -// * jq for parsing output from aws cli to retrieve postgres password -func testAccKnowledgeBase_disappears(t *testing.T) { - acctest.SkipIfExeNotOnPath(t, "psql") - acctest.SkipIfExeNotOnPath(t, "jq") - acctest.SkipIfExeNotOnPath(t, "aws") - - ctx := acctest.Context(t) - var knowledgebase awstypes.KnowledgeBase - rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) - resourceName := "aws_bedrockagent_knowledge_base.test" - foundationModel := "amazon.titan-embed-text-v1" - - resource.Test(t, resource.TestCase{ - PreCheck: func() { - acctest.PreCheck(ctx, t) - }, - ErrorCheck: acctest.ErrorCheck(t, names.BedrockAgentServiceID), - ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, - ExternalProviders: map[string]resource.ExternalProvider{ - "null": { - Source: "hashicorp/null", - VersionConstraint: "3.2.2", - }, - }, - CheckDestroy: testAccCheckKnowledgeBaseDestroy(ctx), - Steps: []resource.TestStep{ { - Config: testAccKnowledgeBaseConfig_basicRDS(rName, foundationModel, ""), + Config: testAccKnowledgeBaseConfig_tags1(rName, foundationModel, acctest.CtKey2, acctest.CtValue2), + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + }, + }, + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ + acctest.CtKey2: knownvalue.StringExact(acctest.CtValue2), + })), + }, Check: resource.ComposeTestCheckFunc( testAccCheckKnowledgeBaseExists(ctx, resourceName, &knowledgebase), - acctest.CheckFrameworkResourceDisappears(ctx, acctest.Provider, tfbedrockagent.ResourceKnowledgeBase, resourceName), ), - ExpectNonEmptyPlan: true, }, }, }) @@ -160,7 +148,7 @@ func testAccKnowledgeBase_disappears(t *testing.T) { // Prerequisites: // * psql run via null_resource/provisioner "local-exec" // * jq for parsing output from aws cli to retrieve postgres password -func testAccKnowledgeBase_tags(t *testing.T) { +func testAccKnowledgeBase_RDS_basic(t *testing.T) { acctest.SkipIfExeNotOnPath(t, "psql") acctest.SkipIfExeNotOnPath(t, "jq") acctest.SkipIfExeNotOnPath(t, "aws") @@ -186,19 +174,30 @@ func testAccKnowledgeBase_tags(t *testing.T) { CheckDestroy: testAccCheckKnowledgeBaseDestroy(ctx), Steps: []resource.TestStep{ { - Config: testAccKnowledgeBaseConfig_tags1(rName, foundationModel, acctest.CtKey1, acctest.CtValue1), + Config: testAccKnowledgeBaseConfig_basicRDS(rName, foundationModel, ""), ConfigPlanChecks: resource.ConfigPlanChecks{ PreApply: []plancheck.PlanCheck{ plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), }, }, - ConfigStateChecks: []statecheck.StateCheck{ - statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ - acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), - })), - }, Check: resource.ComposeTestCheckFunc( testAccCheckKnowledgeBaseExists(ctx, resourceName, &knowledgebase), + resource.TestCheckNoResourceAttr(resourceName, names.AttrDescription), + resource.TestCheckResourceAttr(resourceName, "knowledge_base_configuration.#", "1"), + resource.TestCheckResourceAttr(resourceName, "knowledge_base_configuration.0.vector_knowledge_base_configuration.#", "1"), + resource.TestCheckResourceAttr(resourceName, "knowledge_base_configuration.0.type", "VECTOR"), + resource.TestCheckResourceAttr(resourceName, names.AttrName, rName), + resource.TestCheckResourceAttrPair(resourceName, names.AttrRoleARN, "aws_iam_role.test", names.AttrARN), + resource.TestCheckResourceAttr(resourceName, "storage_configuration.#", "1"), + resource.TestCheckResourceAttr(resourceName, "storage_configuration.0.type", "RDS"), + resource.TestCheckResourceAttr(resourceName, "storage_configuration.0.rds_configuration.#", "1"), + resource.TestCheckResourceAttr(resourceName, "storage_configuration.0.rds_configuration.0.table_name", "bedrock_integration.bedrock_kb"), + resource.TestCheckResourceAttr(resourceName, "storage_configuration.0.rds_configuration.0.field_mapping.#", "1"), + resource.TestCheckResourceAttr(resourceName, "storage_configuration.0.rds_configuration.0.field_mapping.0.vector_field", "embedding"), + resource.TestCheckResourceAttr(resourceName, "storage_configuration.0.rds_configuration.0.field_mapping.0.text_field", "chunks"), + resource.TestCheckResourceAttr(resourceName, "storage_configuration.0.rds_configuration.0.field_mapping.0.metadata_field", "metadata"), + resource.TestCheckResourceAttr(resourceName, "storage_configuration.0.rds_configuration.0.field_mapping.0.primary_key_field", names.AttrID), + resource.TestCheckResourceAttr(resourceName, "storage_configuration.0.rds_configuration.0.field_mapping.0.custom_metadata_field", "custom_metadata"), ), }, { @@ -207,36 +206,30 @@ func testAccKnowledgeBase_tags(t *testing.T) { ImportStateVerify: true, }, { - Config: testAccKnowledgeBaseConfig_tags2(rName, foundationModel, acctest.CtKey1, acctest.CtValue1Updated, acctest.CtKey2, acctest.CtValue2), - ConfigPlanChecks: resource.ConfigPlanChecks{ - PreApply: []plancheck.PlanCheck{ - plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), - }, - }, - ConfigStateChecks: []statecheck.StateCheck{ - statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ - acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1Updated), - acctest.CtKey2: knownvalue.StringExact(acctest.CtValue2), - })), - }, - Check: resource.ComposeTestCheckFunc( - testAccCheckKnowledgeBaseExists(ctx, resourceName, &knowledgebase), - ), - }, - { - Config: testAccKnowledgeBaseConfig_tags1(rName, foundationModel, acctest.CtKey2, acctest.CtValue2), + Config: testAccKnowledgeBaseConfig_updateRDS(rName, foundationModel, "test description"), ConfigPlanChecks: resource.ConfigPlanChecks{ PreApply: []plancheck.PlanCheck{ plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), }, }, - ConfigStateChecks: []statecheck.StateCheck{ - statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.MapExact(map[string]knownvalue.Check{ - acctest.CtKey2: knownvalue.StringExact(acctest.CtValue2), - })), - }, Check: resource.ComposeTestCheckFunc( testAccCheckKnowledgeBaseExists(ctx, resourceName, &knowledgebase), + resource.TestCheckResourceAttr(resourceName, names.AttrDescription, "test description"), + resource.TestCheckResourceAttr(resourceName, "knowledge_base_configuration.#", "1"), + resource.TestCheckResourceAttr(resourceName, "knowledge_base_configuration.0.vector_knowledge_base_configuration.#", "1"), + resource.TestCheckResourceAttr(resourceName, "knowledge_base_configuration.0.type", "VECTOR"), + resource.TestCheckResourceAttr(resourceName, names.AttrName, rName+"-update"), + resource.TestCheckResourceAttrPair(resourceName, names.AttrRoleARN, "aws_iam_role.test_update", names.AttrARN), + resource.TestCheckResourceAttr(resourceName, "storage_configuration.#", "1"), + resource.TestCheckResourceAttr(resourceName, "storage_configuration.0.type", "RDS"), + resource.TestCheckResourceAttr(resourceName, "storage_configuration.0.rds_configuration.#", "1"), + resource.TestCheckResourceAttr(resourceName, "storage_configuration.0.rds_configuration.0.table_name", "bedrock_integration.bedrock_kb"), + resource.TestCheckResourceAttr(resourceName, "storage_configuration.0.rds_configuration.0.field_mapping.#", "1"), + resource.TestCheckResourceAttr(resourceName, "storage_configuration.0.rds_configuration.0.field_mapping.0.vector_field", "embedding"), + resource.TestCheckResourceAttr(resourceName, "storage_configuration.0.rds_configuration.0.field_mapping.0.text_field", "chunks"), + resource.TestCheckResourceAttr(resourceName, "storage_configuration.0.rds_configuration.0.field_mapping.0.metadata_field", "metadata"), + resource.TestCheckResourceAttr(resourceName, "storage_configuration.0.rds_configuration.0.field_mapping.0.primary_key_field", names.AttrID), + resource.TestCheckResourceAttr(resourceName, "storage_configuration.0.rds_configuration.0.field_mapping.0.custom_metadata_field", "custom_metadata"), ), }, }, @@ -506,9 +499,7 @@ func testAccKnowledgeBase_S3Vectors_update(t *testing.T) { foundationModel := "amazon.titan-embed-text-v2:0" resource.Test(t, resource.TestCase{ - PreCheck: func() { - acctest.PreCheck(ctx, t) - }, + PreCheck: func() { acctest.PreCheck(ctx, t) }, ErrorCheck: acctest.ErrorCheck(t, names.BedrockAgentServiceID), ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, CheckDestroy: testAccCheckKnowledgeBaseDestroy(ctx), From e6ec5fb355c0474f68a65289f983fa77ae16a092 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Mon, 8 Dec 2025 16:24:57 -0500 Subject: [PATCH 44/65] testAccKnowledgeBase_tags: Use S3 Vectors instead of RDS. --- .../bedrockagent/knowledge_base_test.go | 107 ++++++++---------- 1 file changed, 46 insertions(+), 61 deletions(-) diff --git a/internal/service/bedrockagent/knowledge_base_test.go b/internal/service/bedrockagent/knowledge_base_test.go index 7ca0286f8839..d3bce2391e30 100644 --- a/internal/service/bedrockagent/knowledge_base_test.go +++ b/internal/service/bedrockagent/knowledge_base_test.go @@ -59,36 +59,24 @@ func testAccKnowledgeBase_disappears(t *testing.T) { }) } -// Prerequisites: -// * psql run via null_resource/provisioner "local-exec" -// * jq for parsing output from aws cli to retrieve postgres password func testAccKnowledgeBase_tags(t *testing.T) { - acctest.SkipIfExeNotOnPath(t, "psql") - acctest.SkipIfExeNotOnPath(t, "jq") - acctest.SkipIfExeNotOnPath(t, "aws") - ctx := acctest.Context(t) var knowledgebase awstypes.KnowledgeBase rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) resourceName := "aws_bedrockagent_knowledge_base.test" - foundationModel := "amazon.titan-embed-text-v1" + foundationModel := "amazon.titan-embed-text-v2:0" resource.Test(t, resource.TestCase{ - PreCheck: func() { - acctest.PreCheck(ctx, t) - }, + PreCheck: func() { acctest.PreCheck(ctx, t) }, ErrorCheck: acctest.ErrorCheck(t, names.BedrockAgentServiceID), ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, - ExternalProviders: map[string]resource.ExternalProvider{ - "null": { - Source: "hashicorp/null", - VersionConstraint: "3.2.2", - }, - }, - CheckDestroy: testAccCheckKnowledgeBaseDestroy(ctx), + CheckDestroy: testAccCheckKnowledgeBaseDestroy(ctx), Steps: []resource.TestStep{ { Config: testAccKnowledgeBaseConfig_tags1(rName, foundationModel, acctest.CtKey1, acctest.CtValue1), + Check: resource.ComposeTestCheckFunc( + testAccCheckKnowledgeBaseExists(ctx, resourceName, &knowledgebase), + ), ConfigPlanChecks: resource.ConfigPlanChecks{ PreApply: []plancheck.PlanCheck{ plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), @@ -99,9 +87,6 @@ func testAccKnowledgeBase_tags(t *testing.T) { acctest.CtKey1: knownvalue.StringExact(acctest.CtValue1), })), }, - Check: resource.ComposeTestCheckFunc( - testAccCheckKnowledgeBaseExists(ctx, resourceName, &knowledgebase), - ), }, { ResourceName: resourceName, @@ -110,6 +95,9 @@ func testAccKnowledgeBase_tags(t *testing.T) { }, { Config: testAccKnowledgeBaseConfig_tags2(rName, foundationModel, acctest.CtKey1, acctest.CtValue1Updated, acctest.CtKey2, acctest.CtValue2), + Check: resource.ComposeTestCheckFunc( + testAccCheckKnowledgeBaseExists(ctx, resourceName, &knowledgebase), + ), ConfigPlanChecks: resource.ConfigPlanChecks{ PreApply: []plancheck.PlanCheck{ plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), @@ -121,12 +109,12 @@ func testAccKnowledgeBase_tags(t *testing.T) { acctest.CtKey2: knownvalue.StringExact(acctest.CtValue2), })), }, - Check: resource.ComposeTestCheckFunc( - testAccCheckKnowledgeBaseExists(ctx, resourceName, &knowledgebase), - ), }, { Config: testAccKnowledgeBaseConfig_tags1(rName, foundationModel, acctest.CtKey2, acctest.CtValue2), + Check: resource.ComposeTestCheckFunc( + testAccCheckKnowledgeBaseExists(ctx, resourceName, &knowledgebase), + ), ConfigPlanChecks: resource.ConfigPlanChecks{ PreApply: []plancheck.PlanCheck{ plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), @@ -137,9 +125,6 @@ func testAccKnowledgeBase_tags(t *testing.T) { acctest.CtKey2: knownvalue.StringExact(acctest.CtValue2), })), }, - Check: resource.ComposeTestCheckFunc( - testAccCheckKnowledgeBaseExists(ctx, resourceName, &knowledgebase), - ), }, }, }) @@ -728,71 +713,73 @@ resource "aws_bedrockagent_knowledge_base" "test" { } func testAccKnowledgeBaseConfig_tags1(rName, model, tag1Key, tag1Value string) string { - return acctest.ConfigCompose(acctest.ConfigBedrockAgentKnowledgeBaseRDSBase(rName, model), fmt.Sprintf(` + return acctest.ConfigCompose(testAccKnowledgeBaseConfig_baseS3Vectors(rName), fmt.Sprintf(` resource "aws_bedrockagent_knowledge_base" "test" { + depends_on = [ + aws_iam_role_policy.test, + ] + name = %[1]q role_arn = aws_iam_role.test.arn knowledge_base_configuration { + type = "VECTOR" + vector_knowledge_base_configuration { embedding_model_arn = "arn:${data.aws_partition.current.partition}:bedrock:${data.aws_region.current.region}::foundation-model/%[2]s" + embedding_model_configuration { + bedrock_embedding_model_configuration { + dimensions = 256 + embedding_data_type = "FLOAT32" + } + } } - type = "VECTOR" } storage_configuration { - type = "RDS" - rds_configuration { - resource_arn = aws_rds_cluster.test.arn - credentials_secret_arn = tolist(aws_rds_cluster.test.master_user_secret)[0].secret_arn - database_name = aws_rds_cluster.test.database_name - table_name = "bedrock_integration.bedrock_kb" - field_mapping { - vector_field = "embedding" - text_field = "chunks" - metadata_field = "metadata" - primary_key_field = "id" - custom_metadata_field = "custom_metadata" - } + type = "S3_VECTORS" + + s3_vectors_configuration { + index_arn = aws_s3vectors_index.test.index_arn } } tags = { %[3]q = %[4]q } - - depends_on = [aws_iam_role_policy.test, null_resource.db_setup] } `, rName, model, tag1Key, tag1Value)) } func testAccKnowledgeBaseConfig_tags2(rName, model, tag1Key, tag1Value, tag2Key, tag2Value string) string { - return acctest.ConfigCompose(acctest.ConfigBedrockAgentKnowledgeBaseRDSBase(rName, model), fmt.Sprintf(` + return acctest.ConfigCompose(testAccKnowledgeBaseConfig_baseS3Vectors(rName), fmt.Sprintf(` resource "aws_bedrockagent_knowledge_base" "test" { + depends_on = [ + aws_iam_role_policy.test, + ] + name = %[1]q role_arn = aws_iam_role.test.arn knowledge_base_configuration { + type = "VECTOR" + vector_knowledge_base_configuration { embedding_model_arn = "arn:${data.aws_partition.current.partition}:bedrock:${data.aws_region.current.region}::foundation-model/%[2]s" + embedding_model_configuration { + bedrock_embedding_model_configuration { + dimensions = 256 + embedding_data_type = "FLOAT32" + } + } } - type = "VECTOR" } storage_configuration { - type = "RDS" - rds_configuration { - resource_arn = aws_rds_cluster.test.arn - credentials_secret_arn = tolist(aws_rds_cluster.test.master_user_secret)[0].secret_arn - database_name = aws_rds_cluster.test.database_name - table_name = "bedrock_integration.bedrock_kb" - field_mapping { - vector_field = "embedding" - text_field = "chunks" - metadata_field = "metadata" - primary_key_field = "id" - custom_metadata_field = "custom_metadata" - } + type = "S3_VECTORS" + + s3_vectors_configuration { + index_arn = aws_s3vectors_index.test.index_arn } } @@ -800,8 +787,6 @@ resource "aws_bedrockagent_knowledge_base" "test" { %[3]q = %[4]q %[5]q = %[6]q } - - depends_on = [aws_iam_role_policy.test, null_resource.db_setup] } `, rName, model, tag1Key, tag1Value, tag2Key, tag2Value)) } From 8f28c18a56d4a0be2e6df8f75c370159a57b5511 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Mon, 8 Dec 2025 16:38:02 -0500 Subject: [PATCH 45/65] Acceptance test output: MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit % make testacc TESTARGS='-run=TestAccBedrockAgent_serial/KnowledgeBase/\(disappears\|tags\)' PKG=bedrockagent make: Verifying source code with gofmt... ==> Checking that code complies with gofmt requirements... make: Running acceptance tests on branch: 🌿 f-aws_bedrockagent_knowledge_base-enhancements 🌿... TF_ACC=1 go1.24.11 test ./internal/service/bedrockagent/... -v -count 1 -parallel 20 -run=TestAccBedrockAgent_serial/KnowledgeBase/\(disappears\|tags\) -timeout 360m -vet=off 2025/12/08 16:36:13 Creating Terraform AWS Provider (SDKv2-style)... 2025/12/08 16:36:13 Initializing Terraform AWS Provider (SDKv2-style)... === RUN TestAccBedrockAgent_serial === PAUSE TestAccBedrockAgent_serial === CONT TestAccBedrockAgent_serial === RUN TestAccBedrockAgent_serial/KnowledgeBase === RUN TestAccBedrockAgent_serial/KnowledgeBase/tags === RUN TestAccBedrockAgent_serial/KnowledgeBase/disappears --- PASS: TestAccBedrockAgent_serial (73.62s) --- PASS: TestAccBedrockAgent_serial/KnowledgeBase (73.62s) --- PASS: TestAccBedrockAgent_serial/KnowledgeBase/tags (49.23s) --- PASS: TestAccBedrockAgent_serial/KnowledgeBase/disappears (24.39s) PASS ok github.com/hashicorp/terraform-provider-aws/internal/service/bedrockagent 79.008s From 21cd2019334d6164ce15d29a815055565c96fe45 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Mon, 8 Dec 2025 16:50:33 -0500 Subject: [PATCH 46/65] 'acctest.ConfigBedrockAgentKnowledgeBaseRDSBase' -> 'acctest.ConfigBedrockAgentKnowledgeBaseS3VectorsBase'. --- internal/acctest/configs.go | 260 +++------------ .../bedrockagent/knowledge_base_test.go | 306 +++++++++++++----- internal/service/logs/delivery_source_test.go | 67 ++-- internal/service/logs/delivery_test.go | 48 +-- 4 files changed, 301 insertions(+), 380 deletions(-) diff --git a/internal/acctest/configs.go b/internal/acctest/configs.go index a1a0a758416c..cef2daac5a81 100644 --- a/internal/acctest/configs.go +++ b/internal/acctest/configs.go @@ -728,240 +728,70 @@ resource "aws_subnet" "test" { ) } -func ConfigBedrockAgentKnowledgeBaseRDSBase(rName, model string) string { - return ConfigCompose( - ConfigVPCWithSubnetsEnableDNSHostnames(rName, 2), //nolint:mnd // 2 subnets required - fmt.Sprintf(` -data "aws_partition" "current" {} +func ConfigBedrockAgentKnowledgeBaseS3VectorsBase(rName string) string { + return fmt.Sprintf(` data "aws_region" "current" {} +data "aws_partition" "current" {} -resource "aws_iam_role" "test" { - name = %[1]q - path = "/service-role/" - assume_role_policy = < Date: Mon, 8 Dec 2025 17:03:39 -0500 Subject: [PATCH 47/65] 'testAccKnowledgeBase_RDS_basic' -> 'testAccKnowledgeBase_RDS_update'. --- internal/service/bedrockagent/bedrockagent_test.go | 2 +- internal/service/bedrockagent/knowledge_base_test.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/internal/service/bedrockagent/bedrockagent_test.go b/internal/service/bedrockagent/bedrockagent_test.go index a419bb715a35..a9d4286c4e11 100644 --- a/internal/service/bedrockagent/bedrockagent_test.go +++ b/internal/service/bedrockagent/bedrockagent_test.go @@ -14,7 +14,7 @@ func TestAccBedrockAgent_serial(t *testing.T) { testCases := map[string]map[string]func(t *testing.T){ "KnowledgeBase": { - "RDSBasic": testAccKnowledgeBase_RDS_basic, + "RDS": testAccKnowledgeBase_RDS_update, acctest.CtDisappears: testAccKnowledgeBase_disappears, "tags": testAccKnowledgeBase_tags, "OpenSearchServerlessBasic": testAccKnowledgeBase_OpenSearchServerless_basic, diff --git a/internal/service/bedrockagent/knowledge_base_test.go b/internal/service/bedrockagent/knowledge_base_test.go index fea1ccb09384..ecd17cf6577a 100644 --- a/internal/service/bedrockagent/knowledge_base_test.go +++ b/internal/service/bedrockagent/knowledge_base_test.go @@ -133,7 +133,7 @@ func testAccKnowledgeBase_tags(t *testing.T) { // Prerequisites: // * psql run via null_resource/provisioner "local-exec" // * jq for parsing output from aws cli to retrieve postgres password -func testAccKnowledgeBase_RDS_basic(t *testing.T) { +func testAccKnowledgeBase_RDS_update(t *testing.T) { acctest.SkipIfExeNotOnPath(t, "psql") acctest.SkipIfExeNotOnPath(t, "jq") acctest.SkipIfExeNotOnPath(t, "aws") From d35467121c5f1b8a93a949a94d134f69fd1d7158 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Mon, 8 Dec 2025 17:34:18 -0500 Subject: [PATCH 48/65] Acceptance test output: MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit % make testacc TESTARGS='-run=TestAccBedrockAgent_serial/KnowledgeBase/RDS' PKG=bedrockagent make: Verifying source code with gofmt... ==> Checking that code complies with gofmt requirements... make: Running acceptance tests on branch: 🌿 f-aws_bedrockagent_knowledge_base-enhancements 🌿... TF_ACC=1 go1.24.11 test ./internal/service/bedrockagent/... -v -count 1 -parallel 20 -run=TestAccBedrockAgent_serial/KnowledgeBase/RDS -timeout 360m -vet=off 2025/12/08 17:04:05 Creating Terraform AWS Provider (SDKv2-style)... 2025/12/08 17:04:05 Initializing Terraform AWS Provider (SDKv2-style)... === RUN TestAccBedrockAgent_serial === PAUSE TestAccBedrockAgent_serial === CONT TestAccBedrockAgent_serial === RUN TestAccBedrockAgent_serial/KnowledgeBase === RUN TestAccBedrockAgent_serial/KnowledgeBase/RDS --- PASS: TestAccBedrockAgent_serial (786.69s) --- PASS: TestAccBedrockAgent_serial/KnowledgeBase (786.69s) --- PASS: TestAccBedrockAgent_serial/KnowledgeBase/RDS (786.69s) PASS ok github.com/hashicorp/terraform-provider-aws/internal/service/bedrockagent 792.271s From a57f3b3fbd0512a75c294a970b1ccd43a5c8dd1f Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Tue, 9 Dec 2025 15:35:24 -0500 Subject: [PATCH 49/65] r/aws_bedrockagent_knowledge_base: Add `knowledge_base_configuration.sql_knowledge_base_configuration` argument. --- .changelog/45465.txt | 7 + .../service/bedrockagent/knowledge_base.go | 524 +++++++++++++++++- .../bedrockagent/knowledge_base_test.go | 10 + 3 files changed, 525 insertions(+), 16 deletions(-) create mode 100644 .changelog/45465.txt diff --git a/.changelog/45465.txt b/.changelog/45465.txt new file mode 100644 index 000000000000..72ab5ff316c5 --- /dev/null +++ b/.changelog/45465.txt @@ -0,0 +1,7 @@ +```release-note:enhancement +resource/aws_bedrockagent_knowledge_base: Add `knowledge_base_configuration.sql_knowledge_base_configuration` argument +``` + +```release-note:bug +resource/aws_bedrockagent_knowledge_base: Mark `knowledge_base_configuration.vector_knowledge_base_configuration.embedding_model_configuration` and `knowledge_base_configuration.vector_knowledge_base_configuration.supplemental_data_storage_configuration` as `ForceNew` +``` \ No newline at end of file diff --git a/internal/service/bedrockagent/knowledge_base.go b/internal/service/bedrockagent/knowledge_base.go index 69bd07eff67d..054acd2f0e0b 100644 --- a/internal/service/bedrockagent/knowledge_base.go +++ b/internal/service/bedrockagent/knowledge_base.go @@ -16,14 +16,17 @@ import ( "github.com/hashicorp/aws-sdk-go-base/v2/tfawserr" "github.com/hashicorp/terraform-plugin-framework-timeouts/resource/timeouts" "github.com/hashicorp/terraform-plugin-framework-timetypes/timetypes" + "github.com/hashicorp/terraform-plugin-framework-validators/int64validator" "github.com/hashicorp/terraform-plugin-framework-validators/listvalidator" "github.com/hashicorp/terraform-plugin-framework-validators/objectvalidator" "github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator" "github.com/hashicorp/terraform-plugin-framework/path" "github.com/hashicorp/terraform-plugin-framework/resource" "github.com/hashicorp/terraform-plugin-framework/resource/schema" + "github.com/hashicorp/terraform-plugin-framework/resource/schema/int64planmodifier" "github.com/hashicorp/terraform-plugin-framework/resource/schema/listplanmodifier" "github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier" + "github.com/hashicorp/terraform-plugin-framework/resource/schema/setplanmodifier" "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier" "github.com/hashicorp/terraform-plugin-framework/schema/validator" "github.com/hashicorp/terraform-plugin-framework/types" @@ -121,6 +124,7 @@ func (r *knowledgeBaseResource) Schema(ctx context.Context, request resource.Sch listvalidator.SizeAtMost(1), listvalidator.ExactlyOneOf( path.MatchRelative().AtParent().AtName("kendra_knowledge_base_configuration"), + path.MatchRelative().AtParent().AtName("sql_knowledge_base_configuration"), path.MatchRelative().AtParent().AtName("vector_knowledge_base_configuration"), ), }, @@ -139,6 +143,380 @@ func (r *knowledgeBaseResource) Schema(ctx context.Context, request resource.Sch }, }, }, + "sql_knowledge_base_configuration": schema.ListNestedBlock{ + CustomType: fwtypes.NewListNestedObjectTypeOf[sqlKnowledgeBaseConfigurationModel](ctx), + Validators: []validator.List{ + listvalidator.SizeAtMost(1), + }, + PlanModifiers: []planmodifier.List{ + listplanmodifier.RequiresReplace(), + }, + NestedObject: schema.NestedBlockObject{ + Attributes: map[string]schema.Attribute{ + names.AttrType: schema.StringAttribute{ + CustomType: fwtypes.StringEnumType[awstypes.QueryEngineType](), + Required: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.RequiresReplace(), + }, + }, + }, + Blocks: map[string]schema.Block{ + "redshift_configuration": schema.ListNestedBlock{ + CustomType: fwtypes.NewListNestedObjectTypeOf[redshiftConfigurationModel](ctx), + Validators: []validator.List{ + listvalidator.SizeAtMost(1), + listvalidator.ExactlyOneOf( + path.MatchRelative().AtParent().AtName("redshift_configuration"), + ), + }, + PlanModifiers: []planmodifier.List{ + listplanmodifier.RequiresReplace(), + }, + NestedObject: schema.NestedBlockObject{ + Blocks: map[string]schema.Block{ + "query_engine_configuration": schema.ListNestedBlock{ + CustomType: fwtypes.NewListNestedObjectTypeOf[redshiftQueryEngineConfigurationModel](ctx), + Validators: []validator.List{ + listvalidator.IsRequired(), + listvalidator.SizeAtLeast(1), + listvalidator.SizeAtMost(1), + }, + PlanModifiers: []planmodifier.List{ + listplanmodifier.RequiresReplace(), + }, + NestedObject: schema.NestedBlockObject{ + Attributes: map[string]schema.Attribute{ + names.AttrType: schema.StringAttribute{ + CustomType: fwtypes.StringEnumType[awstypes.RedshiftQueryEngineType](), + Required: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.RequiresReplace(), + }, + }, + }, + Blocks: map[string]schema.Block{ + "provisioned_configuration": schema.ListNestedBlock{ + CustomType: fwtypes.NewListNestedObjectTypeOf[redshiftProvisionedConfigurationModel](ctx), + Validators: []validator.List{ + listvalidator.SizeAtMost(1), + listvalidator.ExactlyOneOf( + path.MatchRelative().AtParent().AtName("provisioned_configuration"), + path.MatchRelative().AtParent().AtName("serverless_configuration"), + ), + }, + PlanModifiers: []planmodifier.List{ + listplanmodifier.RequiresReplace(), + }, + NestedObject: schema.NestedBlockObject{ + Attributes: map[string]schema.Attribute{ + names.AttrClusterIdentifier: schema.StringAttribute{ + Required: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.RequiresReplace(), + }, + }, + }, + Blocks: map[string]schema.Block{ + "auth_configuration": schema.ListNestedBlock{ + CustomType: fwtypes.NewListNestedObjectTypeOf[redshiftProvisionedAuthConfigurationModel](ctx), + Validators: []validator.List{ + listvalidator.IsRequired(), + listvalidator.SizeAtLeast(1), + listvalidator.SizeAtMost(1), + }, + PlanModifiers: []planmodifier.List{ + listplanmodifier.RequiresReplace(), + }, + NestedObject: schema.NestedBlockObject{ + Attributes: map[string]schema.Attribute{ + "database_user": schema.StringAttribute{ + Optional: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.RequiresReplace(), + }, + }, + names.AttrType: schema.StringAttribute{ + CustomType: fwtypes.StringEnumType[awstypes.RedshiftProvisionedAuthType](), + Required: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.RequiresReplace(), + }, + }, + "username_password_secret_arn": schema.StringAttribute{ + CustomType: fwtypes.ARNType, + Optional: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.RequiresReplace(), + }, + }, + }, + }, + }, + }, + }, + }, + "serverless_configuration": schema.ListNestedBlock{ + CustomType: fwtypes.NewListNestedObjectTypeOf[redshiftServerlessConfigurationModel](ctx), + Validators: []validator.List{ + listvalidator.SizeAtMost(1), + }, + PlanModifiers: []planmodifier.List{ + listplanmodifier.RequiresReplace(), + }, + NestedObject: schema.NestedBlockObject{ + Attributes: map[string]schema.Attribute{ + "workgroup_arn": schema.StringAttribute{ + CustomType: fwtypes.ARNType, + Required: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.RequiresReplace(), + }, + }, + }, + Blocks: map[string]schema.Block{ + "auth_configuration": schema.ListNestedBlock{ + CustomType: fwtypes.NewListNestedObjectTypeOf[redshiftServerlessAuthConfigurationModel](ctx), + Validators: []validator.List{ + listvalidator.IsRequired(), + listvalidator.SizeAtLeast(1), + listvalidator.SizeAtMost(1), + }, + PlanModifiers: []planmodifier.List{ + listplanmodifier.RequiresReplace(), + }, + NestedObject: schema.NestedBlockObject{ + Attributes: map[string]schema.Attribute{ + names.AttrType: schema.StringAttribute{ + CustomType: fwtypes.StringEnumType[awstypes.RedshiftServerlessAuthType](), + Required: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.RequiresReplace(), + }, + }, + "username_password_secret_arn": schema.StringAttribute{ + CustomType: fwtypes.ARNType, + Optional: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.RequiresReplace(), + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + "query_generation_configuration": schema.ListNestedBlock{ + CustomType: fwtypes.NewListNestedObjectTypeOf[queryGenerationConfigurationModel](ctx), + Validators: []validator.List{ + listvalidator.SizeAtMost(1), + }, + PlanModifiers: []planmodifier.List{ + listplanmodifier.RequiresReplace(), + }, + NestedObject: schema.NestedBlockObject{ + Attributes: map[string]schema.Attribute{ + "execution_timeout_seconds": schema.Int64Attribute{ + Optional: true, + Validators: []validator.Int64{ + int64validator.Between(1, 200), + }, + PlanModifiers: []planmodifier.Int64{ + int64planmodifier.RequiresReplace(), + }, + }, + }, + Blocks: map[string]schema.Block{ + "generation_context": schema.ListNestedBlock{ + CustomType: fwtypes.NewListNestedObjectTypeOf[queryGenerationContextModel](ctx), + Validators: []validator.List{ + listvalidator.SizeAtMost(1), + }, + PlanModifiers: []planmodifier.List{ + listplanmodifier.RequiresReplace(), + }, + NestedObject: schema.NestedBlockObject{ + Blocks: map[string]schema.Block{ + "curated_query": schema.ListNestedBlock{ + CustomType: fwtypes.NewListNestedObjectTypeOf[curatedQueryModel](ctx), + Validators: []validator.List{ + listvalidator.SizeAtMost(10), + }, + PlanModifiers: []planmodifier.List{ + listplanmodifier.RequiresReplace(), + }, + NestedObject: schema.NestedBlockObject{ + Attributes: map[string]schema.Attribute{ + "natural_language": schema.StringAttribute{ + Required: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.RequiresReplace(), + }, + }, + "sql": schema.StringAttribute{ + Required: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.RequiresReplace(), + }, + }, + }, + }, + }, + "table": schema.ListNestedBlock{ + CustomType: fwtypes.NewListNestedObjectTypeOf[queryGenerationTableModel](ctx), + Validators: []validator.List{ + listvalidator.SizeAtMost(50), + }, + PlanModifiers: []planmodifier.List{ + listplanmodifier.RequiresReplace(), + }, + NestedObject: schema.NestedBlockObject{ + Attributes: map[string]schema.Attribute{ + names.AttrDescription: schema.StringAttribute{ + Optional: true, + Validators: []validator.String{ + stringvalidator.LengthBetween(1, 200), + }, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.RequiresReplace(), + }, + }, + "inclusion": schema.StringAttribute{ + CustomType: fwtypes.StringEnumType[awstypes.IncludeExclude](), + Optional: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.RequiresReplace(), + }, + }, + names.AttrName: schema.StringAttribute{ + Required: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.RequiresReplace(), + }, + }, + }, + Blocks: map[string]schema.Block{ + "column": schema.ListNestedBlock{ + CustomType: fwtypes.NewListNestedObjectTypeOf[queryGenerationColumnModel](ctx), + PlanModifiers: []planmodifier.List{ + listplanmodifier.RequiresReplace(), + }, + NestedObject: schema.NestedBlockObject{ + Attributes: map[string]schema.Attribute{ + names.AttrDescription: schema.StringAttribute{ + Optional: true, + Validators: []validator.String{ + stringvalidator.LengthBetween(1, 200), + }, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.RequiresReplace(), + }, + }, + "inclusion": schema.StringAttribute{ + CustomType: fwtypes.StringEnumType[awstypes.IncludeExclude](), + Optional: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.RequiresReplace(), + }, + }, + names.AttrName: schema.StringAttribute{ + Optional: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.RequiresReplace(), + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + "storage_configuration": schema.ListNestedBlock{ + CustomType: fwtypes.NewListNestedObjectTypeOf[redshiftQueryEngineStorageConfigurationModel](ctx), + Validators: []validator.List{ + listvalidator.IsRequired(), + listvalidator.SizeAtLeast(1), + listvalidator.SizeAtMost(1), + }, + PlanModifiers: []planmodifier.List{ + listplanmodifier.RequiresReplace(), + }, + NestedObject: schema.NestedBlockObject{ + Attributes: map[string]schema.Attribute{ + names.AttrType: schema.StringAttribute{ + CustomType: fwtypes.StringEnumType[awstypes.RedshiftQueryEngineStorageType](), + Required: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.RequiresReplace(), + }, + }, + }, + Blocks: map[string]schema.Block{ + "aws_data_catalog_configuration": schema.ListNestedBlock{ + CustomType: fwtypes.NewListNestedObjectTypeOf[redshiftQueryEngineAWSDataCatalogStorageConfigurationModel](ctx), + Validators: []validator.List{ + listvalidator.SizeAtMost(1), + listvalidator.ExactlyOneOf( + path.MatchRelative().AtParent().AtName("aws_data_catalog_configuration"), + path.MatchRelative().AtParent().AtName("redshift_configuration"), + ), + }, + PlanModifiers: []planmodifier.List{ + listplanmodifier.RequiresReplace(), + }, + NestedObject: schema.NestedBlockObject{ + Attributes: map[string]schema.Attribute{ + "table_names": schema.SetAttribute{ + CustomType: fwtypes.SetOfStringType, + Required: true, + PlanModifiers: []planmodifier.Set{ + setplanmodifier.RequiresReplace(), + }, + }, + }, + }, + }, + "redshift_configuration": schema.ListNestedBlock{ + CustomType: fwtypes.NewListNestedObjectTypeOf[redshiftQueryEngineRedshiftStorageConfigurationModel](ctx), + Validators: []validator.List{ + listvalidator.SizeAtMost(1), + }, + PlanModifiers: []planmodifier.List{ + listplanmodifier.RequiresReplace(), + }, + NestedObject: schema.NestedBlockObject{ + Attributes: map[string]schema.Attribute{ + names.AttrDatabaseName: schema.StringAttribute{ + Required: true, + Validators: []validator.String{ + stringvalidator.LengthBetween(1, 200), + }, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.RequiresReplace(), + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, + }, "vector_knowledge_base_configuration": schema.ListNestedBlock{ CustomType: fwtypes.NewListNestedObjectTypeOf[vectorKnowledgeBaseConfigurationModel](ctx), Validators: []validator.List{ @@ -159,23 +537,37 @@ func (r *knowledgeBaseResource) Schema(ctx context.Context, request resource.Sch }, Blocks: map[string]schema.Block{ "embedding_model_configuration": schema.ListNestedBlock{ + CustomType: fwtypes.NewListNestedObjectTypeOf[embeddingModelConfigurationModel](ctx), Validators: []validator.List{ listvalidator.SizeAtMost(1), }, + PlanModifiers: []planmodifier.List{ + listplanmodifier.RequiresReplace(), + }, NestedObject: schema.NestedBlockObject{ Blocks: map[string]schema.Block{ "bedrock_embedding_model_configuration": schema.ListNestedBlock{ + CustomType: fwtypes.NewListNestedObjectTypeOf[bedrockEmbeddingModelConfigurationModel](ctx), Validators: []validator.List{ listvalidator.SizeAtMost(1), }, + PlanModifiers: []planmodifier.List{ + listplanmodifier.RequiresReplace(), + }, NestedObject: schema.NestedBlockObject{ Attributes: map[string]schema.Attribute{ "dimensions": schema.Int64Attribute{ Optional: true, + PlanModifiers: []planmodifier.Int64{ + int64planmodifier.RequiresReplace(), + }, }, "embedding_data_type": schema.StringAttribute{ CustomType: fwtypes.StringEnumType[awstypes.EmbeddingDataType](), Optional: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.RequiresReplace(), + }, }, }, }, @@ -184,28 +576,44 @@ func (r *knowledgeBaseResource) Schema(ctx context.Context, request resource.Sch }, }, "supplemental_data_storage_configuration": schema.ListNestedBlock{ + CustomType: fwtypes.NewListNestedObjectTypeOf[supplementalDataStorageConfigurationModel](ctx), Validators: []validator.List{ listvalidator.SizeAtMost(1), }, + PlanModifiers: []planmodifier.List{ + listplanmodifier.RequiresReplace(), + }, NestedObject: schema.NestedBlockObject{ Blocks: map[string]schema.Block{ "storage_location": schema.ListNestedBlock{ + CustomType: fwtypes.NewListNestedObjectTypeOf[storageLocationModel](ctx), Validators: []validator.List{ listvalidator.IsRequired(), listvalidator.SizeAtLeast(1), + listvalidator.SizeAtMost(1), + }, + PlanModifiers: []planmodifier.List{ + listplanmodifier.RequiresReplace(), }, NestedObject: schema.NestedBlockObject{ Attributes: map[string]schema.Attribute{ names.AttrType: schema.StringAttribute{ CustomType: fwtypes.StringEnumType[awstypes.SupplementalDataStorageLocationType](), Required: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.RequiresReplace(), + }, }, }, Blocks: map[string]schema.Block{ "s3_location": schema.ListNestedBlock{ + CustomType: fwtypes.NewListNestedObjectTypeOf[s3LocationModel](ctx), Validators: []validator.List{ listvalidator.SizeAtMost(1), }, + PlanModifiers: []planmodifier.List{ + listplanmodifier.RequiresReplace(), + }, NestedObject: schema.NestedBlockObject{ Attributes: map[string]schema.Attribute{ names.AttrURI: schema.StringAttribute{ @@ -216,6 +624,9 @@ func (r *knowledgeBaseResource) Schema(ctx context.Context, request resource.Sch "must be a valid S3 URI", ), }, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.RequiresReplace(), + }, }, }, }, @@ -370,15 +781,15 @@ func (r *knowledgeBaseResource) Schema(ctx context.Context, request resource.Sch }, "domain_endpoint": schema.StringAttribute{ Required: true, - PlanModifiers: []planmodifier.String{ - stringplanmodifier.RequiresReplace(), - }, Validators: []validator.String{ stringvalidator.RegexMatches( regexache.MustCompile(`^https://.*$`), "must be a valid HTTPS URL", ), }, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.RequiresReplace(), + }, }, "vector_index_name": schema.StringAttribute{ Required: true, @@ -712,33 +1123,33 @@ func (r *knowledgeBaseResource) Schema(ctx context.Context, request resource.Sch "index_arn": schema.StringAttribute{ CustomType: fwtypes.ARNType, Optional: true, - PlanModifiers: []planmodifier.String{ - stringplanmodifier.RequiresReplace(), - }, Validators: []validator.String{ stringvalidator.ConflictsWith(path.MatchRelative().AtParent().AtName("index_name"), path.MatchRelative().AtParent().AtName("vector_bucket_arn")), }, - }, - "index_name": schema.StringAttribute{ - Optional: true, PlanModifiers: []planmodifier.String{ stringplanmodifier.RequiresReplace(), }, + }, + "index_name": schema.StringAttribute{ + Optional: true, Validators: []validator.String{ stringvalidator.AlsoRequires(path.MatchRelative().AtParent().AtName("vector_bucket_arn")), stringvalidator.ConflictsWith(path.MatchRelative().AtParent().AtName("index_arn")), }, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.RequiresReplace(), + }, }, "vector_bucket_arn": schema.StringAttribute{ CustomType: fwtypes.ARNType, Optional: true, - PlanModifiers: []planmodifier.String{ - stringplanmodifier.RequiresReplace(), - }, Validators: []validator.String{ stringvalidator.AlsoRequires(path.MatchRelative().AtParent().AtName("index_name")), stringvalidator.ConflictsWith(path.MatchRelative().AtParent().AtName("index_arn")), }, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.RequiresReplace(), + }, }, }, Validators: []validator.Object{ @@ -1069,10 +1480,95 @@ type knowledgeBaseResourceModel struct { type knowledgeBaseConfigurationModel struct { KendraKnowledgeBaseConfiguration fwtypes.ListNestedObjectValueOf[kendraKnowledgeBaseConfigurationModel] `tfsdk:"kendra_knowledge_base_configuration"` + SQLKnowledgeBaseConfiguration fwtypes.ListNestedObjectValueOf[sqlKnowledgeBaseConfigurationModel] `tfsdk:"sql_knowledge_base_configuration"` Type fwtypes.StringEnum[awstypes.KnowledgeBaseType] `tfsdk:"type"` VectorKnowledgeBaseConfiguration fwtypes.ListNestedObjectValueOf[vectorKnowledgeBaseConfigurationModel] `tfsdk:"vector_knowledge_base_configuration"` } +type kendraKnowledgeBaseConfigurationModel struct { + KendraIndexARN fwtypes.ARN `tfsdk:"kendra_index_arn"` +} + +type sqlKnowledgeBaseConfigurationModel struct { + RedshiftConfiguration fwtypes.ListNestedObjectValueOf[redshiftConfigurationModel] `tfsdk:"redshift_configuration"` + Type fwtypes.StringEnum[awstypes.QueryEngineType] `tfsdk:"type"` +} + +type redshiftConfigurationModel struct { + QueryEngineConfiguration fwtypes.ListNestedObjectValueOf[redshiftQueryEngineConfigurationModel] `tfsdk:"query_engine_configuration"` + QueryGenerationConfiguration fwtypes.ListNestedObjectValueOf[queryGenerationConfigurationModel] `tfsdk:"query_generation_configuration"` + StorageConfigurations fwtypes.ListNestedObjectValueOf[redshiftQueryEngineStorageConfigurationModel] `tfsdk:"storage_configuration"` +} + +type redshiftQueryEngineConfigurationModel struct { + ProvisionedConfiguration fwtypes.ListNestedObjectValueOf[redshiftProvisionedConfigurationModel] `tfsdk:"provisioned_configuration"` + ServerlessConfiguration fwtypes.ListNestedObjectValueOf[redshiftServerlessConfigurationModel] `tfsdk:"serverless_configuration"` + Type fwtypes.StringEnum[awstypes.RedshiftQueryEngineType] `tfsdk:"type"` +} + +type redshiftProvisionedConfigurationModel struct { + AuthConfiguration fwtypes.ListNestedObjectValueOf[redshiftProvisionedAuthConfigurationModel] `tfsdk:"auth_configuration"` + ClusterIdentifier types.String `tfsdk:"cluster_identifier"` +} + +type redshiftProvisionedAuthConfigurationModel struct { + DatabaseUser types.String `tfsdk:"database_user"` + Type fwtypes.StringEnum[awstypes.RedshiftProvisionedAuthType] `tfsdk:"type"` + UsernamePasswordSecretARN fwtypes.ARN `tfsdk:"username_password_secret_arn"` +} + +type redshiftServerlessConfigurationModel struct { + AuthConfiguration fwtypes.ListNestedObjectValueOf[redshiftServerlessAuthConfigurationModel] `tfsdk:"auth_configuration"` + WorkgroupARN fwtypes.ARN `tfsdk:"workgroup_arn"` +} + +type redshiftServerlessAuthConfigurationModel struct { + Type fwtypes.StringEnum[awstypes.RedshiftServerlessAuthType] `tfsdk:"type"` + UsernamePasswordSecretARN fwtypes.ARN `tfsdk:"username_password_secret_arn"` +} + +type queryGenerationConfigurationModel struct { + ExecutionTimeoutSeconds types.Int64 `tfsdk:"execution_timeout_seconds"` + GenerationContext fwtypes.ListNestedObjectValueOf[queryGenerationContextModel] `tfsdk:"generation_context"` +} + +type queryGenerationContextModel struct { + CuratedQueries fwtypes.ListNestedObjectValueOf[curatedQueryModel] `tfsdk:"curated_query"` + Tables fwtypes.ListNestedObjectValueOf[queryGenerationTableModel] `tfsdk:"table"` +} + +type curatedQueryModel struct { + NaturalLanguage types.String `tfsdk:"natural_language"` + SQL types.String `tfsdk:"sql"` +} + +type queryGenerationTableModel struct { + Columns fwtypes.ListNestedObjectValueOf[queryGenerationColumnModel] `tfsdk:"column"` + Description types.String `tfsdk:"description"` + Inclusion fwtypes.StringEnum[awstypes.IncludeExclude] `tfsdk:"inclusion"` + Name types.String `tfsdk:"name"` +} + +type queryGenerationColumnModel struct { + Description types.String `tfsdk:"description"` + Inclusion fwtypes.StringEnum[awstypes.IncludeExclude] `tfsdk:"inclusion"` + Name types.String `tfsdk:"name"` +} + +type redshiftQueryEngineStorageConfigurationModel struct { + AWSDataCatalogConfiguration fwtypes.ListNestedObjectValueOf[redshiftQueryEngineAWSDataCatalogStorageConfigurationModel] `tfsdk:"aws_data_catalog_configuration"` + RedshiftConfiguration fwtypes.ListNestedObjectValueOf[redshiftQueryEngineRedshiftStorageConfigurationModel] `tfsdk:"redshift_configuration"` + Type fwtypes.StringEnum[awstypes.RedshiftQueryEngineStorageType] `tfsdk:"type"` +} + +type redshiftQueryEngineAWSDataCatalogStorageConfigurationModel struct { + TableNames fwtypes.SetOfString `tfsdk:"table_names"` +} + +type redshiftQueryEngineRedshiftStorageConfigurationModel struct { + DatabaseName types.String `tfsdk:"database_name"` +} + type vectorKnowledgeBaseConfigurationModel struct { EmbeddingModelARN fwtypes.ARN `tfsdk:"embedding_model_arn"` EmbeddingModelConfiguration fwtypes.ListNestedObjectValueOf[embeddingModelConfigurationModel] `tfsdk:"embedding_model_configuration"` @@ -1097,10 +1593,6 @@ type storageLocationModel struct { Type fwtypes.StringEnum[awstypes.SupplementalDataStorageLocationType] `tfsdk:"type"` } -type kendraKnowledgeBaseConfigurationModel struct { - KendraIndexARN fwtypes.ARN `tfsdk:"kendra_index_arn"` -} - type storageConfigurationModel struct { MongoDBAtlasConfiguration fwtypes.ListNestedObjectValueOf[mongoDBAtlasConfigurationModel] `tfsdk:"mongo_db_atlas_configuration"` OpenSearchManagedClusterConfiguration fwtypes.ListNestedObjectValueOf[openSearchManagedClusterConfigurationModel] `tfsdk:"opensearch_managed_cluster_configuration"` diff --git a/internal/service/bedrockagent/knowledge_base_test.go b/internal/service/bedrockagent/knowledge_base_test.go index ecd17cf6577a..a175b52c045a 100644 --- a/internal/service/bedrockagent/knowledge_base_test.go +++ b/internal/service/bedrockagent/knowledge_base_test.go @@ -408,6 +408,7 @@ func testAccKnowledgeBase_Kendra_basic(t *testing.T) { statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("knowledge_base_configuration"), knownvalue.ListExact([]knownvalue.Check{ knownvalue.MapExact(map[string]knownvalue.Check{ "kendra_knowledge_base_configuration": knownvalue.ListSizeExact(1), + "sql_knowledge_base_configuration": knownvalue.ListSizeExact(0), names.AttrType: tfknownvalue.StringExact(awstypes.KnowledgeBaseTypeKendra), "vector_knowledge_base_configuration": knownvalue.ListSizeExact(0), }), @@ -454,6 +455,7 @@ func testAccKnowledgeBase_OpenSearchManagedCluster_basic(t *testing.T) { statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("knowledge_base_configuration"), knownvalue.ListExact([]knownvalue.Check{ knownvalue.MapExact(map[string]knownvalue.Check{ "kendra_knowledge_base_configuration": knownvalue.ListSizeExact(0), + "sql_knowledge_base_configuration": knownvalue.ListSizeExact(0), names.AttrType: tfknownvalue.StringExact(awstypes.KnowledgeBaseTypeVector), "vector_knowledge_base_configuration": knownvalue.ListSizeExact(1), }), @@ -500,6 +502,14 @@ func testAccKnowledgeBase_S3Vectors_update(t *testing.T) { testAccCheckKnowledgeBaseExists(ctx, resourceName, &knowledgebase), ), ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("knowledge_base_configuration"), knownvalue.ListExact([]knownvalue.Check{ + knownvalue.MapExact(map[string]knownvalue.Check{ + "kendra_knowledge_base_configuration": knownvalue.ListSizeExact(0), + "sql_knowledge_base_configuration": knownvalue.ListSizeExact(0), + names.AttrType: tfknownvalue.StringExact(awstypes.KnowledgeBaseTypeVector), + "vector_knowledge_base_configuration": knownvalue.ListSizeExact(1), + }), + })), statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("storage_configuration"), knownvalue.ListExact([]knownvalue.Check{ knownvalue.MapExact(map[string]knownvalue.Check{ "mongo_db_atlas_configuration": knownvalue.ListSizeExact(0), From 436fd16f7150296bacb3a7b384e6eb946cbd9368 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Tue, 9 Dec 2025 15:40:37 -0500 Subject: [PATCH 50/65] Acceptance test output: MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit % make testacc TESTARGS='-run=TestAccBedrockAgent_serial/KnowledgeBase/S3Vectors' PKG=bedrockagent make: Verifying source code with gofmt... ==> Checking that code complies with gofmt requirements... make: Running acceptance tests on branch: 🌿 f-aws_bedrockagent_knowledge_base-enhancements 🌿... TF_ACC=1 go1.24.11 test ./internal/service/bedrockagent/... -v -count 1 -parallel 20 -run=TestAccBedrockAgent_serial/KnowledgeBase/S3Vectors -timeout 360m -vet=off 2025/12/09 15:39:23 Creating Terraform AWS Provider (SDKv2-style)... 2025/12/09 15:39:23 Initializing Terraform AWS Provider (SDKv2-style)... === RUN TestAccBedrockAgent_serial === PAUSE TestAccBedrockAgent_serial === CONT TestAccBedrockAgent_serial === RUN TestAccBedrockAgent_serial/KnowledgeBase === RUN TestAccBedrockAgent_serial/KnowledgeBase/S3Vectors --- PASS: TestAccBedrockAgent_serial (51.22s) --- PASS: TestAccBedrockAgent_serial/KnowledgeBase (51.22s) --- PASS: TestAccBedrockAgent_serial/KnowledgeBase/S3Vectors (51.22s) PASS ok github.com/hashicorp/terraform-provider-aws/internal/service/bedrockagent 56.715s From 8872beba5a1c706b9f79b978a1789d0a5248d764 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Wed, 10 Dec 2025 11:04:51 -0500 Subject: [PATCH 51/65] r/aws_bedrockagent_knowledge_base: Document 'sql_knowledge_base_configuration'. --- .../bedrockagent_knowledge_base.html.markdown | 115 +++++++++++++++++- 1 file changed, 113 insertions(+), 2 deletions(-) diff --git a/website/docs/r/bedrockagent_knowledge_base.html.markdown b/website/docs/r/bedrockagent_knowledge_base.html.markdown index 77be7071e88e..badd104cc49c 100644 --- a/website/docs/r/bedrockagent_knowledge_base.html.markdown +++ b/website/docs/r/bedrockagent_knowledge_base.html.markdown @@ -193,8 +193,9 @@ The following arguments are optional: The `knowledge_base_configuration` configuration block supports the following arguments: * `type` - (Required) Type of data that the data source is converted into for the knowledge base. Valid Values: `VECTOR`, `KENDRA`, `SQL`. -* `kendra_knowledge_base_configuration` - (Optional) Configuration for Kendra knowledge base. See [`kendra_knowledge_base_configuration` block](#kendra_knowledge_base_configuration-block) for details. -* `vector_knowledge_base_configuration` - (Optional) Details about the embeddings model that'sused to convert the data source. See [`vector_knowledge_base_configuration` block](#vector_knowledge_base_configuration-block) for details. +* `kendra_knowledge_base_configuration` - (Optional) Settings for an Amazon Kendra knowledge base. See [`kendra_knowledge_base_configuration` block](#kendra_knowledge_base_configuration-block) for details. +* `sql_knowledge_base_configuration` - (Optional) Configurations for a knowledge base connected to an SQL database. See [`sql_knowledge_base_configuration` block](#sql_knowledge_base_configuration-block) for details. +* `vector_knowledge_base_configuration` - (Optional) Details about the model that's used to convert the data source into vector embeddings. See [`vector_knowledge_base_configuration` block](#vector_knowledge_base_configuration-block) for details. ### `kendra_knowledge_base_configuration` block @@ -202,6 +203,116 @@ The `kendra_knowledge_base_configuration` configuration block supports the follo * `kendra_index_arn` - (Required) ARN of the Amazon Kendra index. +### `sql_knowledge_base_configuration` block + +The `sql_knowledge_base_configuration` configuration block supports the following arguments: + +* `redshift_configuration` - (Optional) Configurations for a knowledge base connected to an Amazon Redshift database. See [`redshift_configuration` block](#knowledge-base-redshift_configuration-block) for details. +* `type` - (Required) Type of SQL database to connect to the knowledge base. Valid values: `REDSHIFT`. + +### Knowledge Base `redshift_configuration` block + +The `redshift_configuration` configuration block supports the following arguments: + +* `query_engine_configuration` - (Required) Configurations for an Amazon Redshift query engine. See [`query_engine_configuration` block](#query_engine_configuration-block) for details. +* `query_generation_configuration` - (Optional) Configurations for generating queries. See [`query_generation_configuration` block](#query_generation_configuration-block) for details. +* `storage_configuration` - (Required) Configurations for Amazon Redshift database storage. See [`storage_configuration` block](#storage_configuration-block) for details. + +### `query_engine_configuration` block + +The `query_engine_configuration` configuration block supports the following arguments: + +* `provisioned_configuration` - (Optional) Configurations for a provisioned Amazon Redshift query engine. See [`provisioned_configuration` block](#provisioned_configuration-block) for details. +* `serverless_configuration` - (Optional) Configurations for a serverless Amazon Redshift query engine. See [`serverless_configuration` block](#serverless_configuration-block) for details. +* `type` - (Required) Type of query engine. Valid values: `SERVERLESS`, `PROVISIONED`. + +### `provisioned_configuration` block + +The `provisioned_configuration` configuration block supports the following arguments: + +* `auth_configuration` - (Required) Configurations for authentication to Amazon Redshift. See [`auth_configuration` block](#provisioned-auth_configuration-block) for details. +* `cluster_identifier` - (Required) ID of the Amazon Redshift cluster. + +### Provisioned `auth_configuration` block + +The `auth_configuration` configuration block supports the following arguments: + +* `database_user` - (Optional) Database username for authentication to an Amazon Redshift provisioned data warehouse. +* `type` - (Required) Type of authentication to use. Valid values: `IAM`, `USERNAME_PASSWORD`, ``USERNAME`. +* `username_password_secret_arn` - (Optional) ARN of a Secrets Manager secret for authentication. + +### `serverless_configuration` block + +The `serverless_configuration` configuration block supports the following arguments: + +* `auth_configuration` - (Required) Configurations for authentication to a Redshift Serverless. See [`auth_configuration` block](#serverless-auth_configuration-block) for details. +* `workgroup_arn` - (Required) ARN of the Amazon Redshift workgroup. + +### Serverless `auth_configuration` block + +The `auth_configuration` configuration block supports the following arguments: + +* `type` - (Required) Type of authentication to use. Valid values: `IAM`, `USERNAME_PASSWORD`. +* `username_password_secret_arn` - (Optional) ARN of a Secrets Manager secret for authentication. + +### `query_generation_configuration` block + +The `query_generation_configuration` configuration block supports the following arguments: + +* `execution_timeout_seconds` - (Optional) Time after which query generation will time out. +* `generation_context` - (Optional) Configurations for context to use during query generation. See [`generation_context` block](#generation_context-block) for details. + +### `generation_context` block + +The `generation_context` configuration block supports the following arguments: + +* `curated_query` - (Optional) Information about example queries to help the query engine generate appropriate SQL queries. See [`curated_query` block](#curated_query-block) for details. +* `table` - (Optional) Information about a table in the database. See [`table` block](#table-block) for details. + +### `curated_query` block + +The `curated_query` configuration block supports the following arguments: + +* `natural_language` - (Required) Example natural language query. +* `sql` - (Required) SQL equivalent of `natural_language`. + +### `table` block + +The `table` configuration block supports the following arguments: + +* `column` - (Optional) Information about a column in the table. See [`column` block](#column-block) for details. +* `description` - (Optional) Description of the table that helps the query engine understand the contents of the table. +* `inclusion` - (Optional) Whether to include or exclude the table during query generation. Valid values `INCLUDE`, `EXCLUDE`. +* `name` - (Required) Name of the table for which the other fields in this object apply. + +### `column` block + +The `column` configuration block supports the following arguments: + +* `description` - (Optional) Description of the column that helps the query engine understand the contents of the column. +* `inclusion` - (Optional) Whether to include or exclude the column during query generation. Valid values `INCLUDE`, `EXCLUDE`. +* `name` - (Required) Name of the column for which the other fields in this object apply. + +### `storage_configuration` block + +The `storage_configuration` configuration block supports the following arguments: + +* `aws_data_catalog_configuration` - (Optional) Configurations for storage in AWS Glue Data Catalog. See [`aws_data_catalog_configuration` block](#aws_data_catalog_configuration-block) for details. +* `redshift_configuration` - (Optional) Configurations for storage in Amazon Redshift. See [`redshift_configuration` block](#storage-redshift_configuration-block) for details. +* `type` - (Required) Data storage service to use. Valid values: `REDSHIFT`, `AWS_DATA_CATALOG`. + +### `aws_data_catalog_configuration` block + +The `aws_data_catalog_configuration` configuration block supports the following arguments: + +* `table_names` - (Required) List of names of the tables to use. + +### Storage `redshift_configuration` block + +The `redshift_configuration` configuration block supports the following arguments: + +* `database_name` - (Required) Name of the Amazon Redshift database. + ### `vector_knowledge_base_configuration` block The `vector_knowledge_base_configuration` configuration block supports the following arguments: From 542db60774faed51b9f93f00ed4a53c6ba002903 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Wed, 10 Dec 2025 13:55:08 -0500 Subject: [PATCH 52/65] Add 'testAccKnowledgeBase_StructuredDataStore_redshiftProvisioned'. --- .../service/bedrockagent/bedrockagent_test.go | 7 +- .../bedrockagent/knowledge_base_test.go | 197 ++++++++++++++++++ 2 files changed, 201 insertions(+), 3 deletions(-) diff --git a/internal/service/bedrockagent/bedrockagent_test.go b/internal/service/bedrockagent/bedrockagent_test.go index a9d4286c4e11..4a57f7bf8624 100644 --- a/internal/service/bedrockagent/bedrockagent_test.go +++ b/internal/service/bedrockagent/bedrockagent_test.go @@ -20,9 +20,10 @@ func TestAccBedrockAgent_serial(t *testing.T) { "OpenSearchServerlessBasic": testAccKnowledgeBase_OpenSearchServerless_basic, "OpenSearchServerlessUpdate": testAccKnowledgeBase_OpenSearchServerless_update, "OpenSearchServerlessSupplementalDataStorage": testAccKnowledgeBase_OpenSearchServerless_supplementalDataStorage, - "KendraBasic": testAccKnowledgeBase_Kendra_basic, - "OpenSearchManagedClusterBasic": testAccKnowledgeBase_OpenSearchManagedCluster_basic, - "S3Vectors": testAccKnowledgeBase_S3Vectors_update, + "KendraBasic": testAccKnowledgeBase_Kendra_basic, + "OpenSearchManagedClusterBasic": testAccKnowledgeBase_OpenSearchManagedCluster_basic, + "S3Vectors": testAccKnowledgeBase_S3Vectors_update, + "StructuredDataStoreRedshiftProvisioned": testAccKnowledgeBase_StructuredDataStore_redshiftProvisioned, }, "DataSource": { acctest.CtBasic: testAccDataSource_basic, diff --git a/internal/service/bedrockagent/knowledge_base_test.go b/internal/service/bedrockagent/knowledge_base_test.go index a175b52c045a..fb6fc8b2a8d8 100644 --- a/internal/service/bedrockagent/knowledge_base_test.go +++ b/internal/service/bedrockagent/knowledge_base_test.go @@ -558,6 +558,66 @@ func testAccKnowledgeBase_S3Vectors_update(t *testing.T) { }) } +func testAccKnowledgeBase_StructuredDataStore_redshiftProvisioned(t *testing.T) { + ctx := acctest.Context(t) + var knowledgebase awstypes.KnowledgeBase + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + resourceName := "aws_bedrockagent_knowledge_base.test" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.BedrockAgentServiceID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckKnowledgeBaseDestroy(ctx), + Steps: []resource.TestStep{ + { + Config: testAccKnowledgeBaseConfig_StructuredDataStore_redshiftProvisioned(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckKnowledgeBaseExists(ctx, resourceName, &knowledgebase), + ), + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + }, + }, + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("knowledge_base_configuration"), knownvalue.ListExact([]knownvalue.Check{ + knownvalue.MapExact(map[string]knownvalue.Check{ + "kendra_knowledge_base_configuration": knownvalue.ListSizeExact(0), + "sql_knowledge_base_configuration": knownvalue.ListExact([]knownvalue.Check{ + knownvalue.ObjectExact(map[string]knownvalue.Check{ + names.AttrType: tfknownvalue.StringExact(awstypes.QueryEngineTypeRedshift), + "redshift_configuration": knownvalue.ListExact([]knownvalue.Check{ + knownvalue.ObjectExact(map[string]knownvalue.Check{ + "query_engine_configuration": knownvalue.ListExact([]knownvalue.Check{ + knownvalue.ObjectExact(map[string]knownvalue.Check{ + names.AttrType: tfknownvalue.StringExact(awstypes.RedshiftQueryEngineTypeProvisioned), + "provisioned_configuration": knownvalue.ListSizeExact(1), + "serverless_configuration": knownvalue.ListSizeExact(0), + }), + }), + "query_generation_configuration": knownvalue.ListSizeExact(0), + "storage_configuration": knownvalue.ListExact([]knownvalue.Check{ + knownvalue.ObjectExact(map[string]knownvalue.Check{ + names.AttrType: tfknownvalue.StringExact(awstypes.RedshiftQueryEngineStorageTypeRedshift), + "aws_data_catalog_configuration": knownvalue.ListSizeExact(0), + "redshift_configuration": knownvalue.ListSizeExact(1), + }), + }), + }), + }), + }), + }), + names.AttrType: tfknownvalue.StringExact(awstypes.KnowledgeBaseTypeSql), + "vector_knowledge_base_configuration": knownvalue.ListSizeExact(0), + }), + })), + }, + }, + }, + }) +} + func testAccCheckKnowledgeBaseDestroy(ctx context.Context) resource.TestCheckFunc { return func(s *terraform.State) error { conn := acctest.Provider.Meta().(*conns.AWSClient).BedrockAgentClient(ctx) @@ -1777,3 +1837,140 @@ resource "aws_bedrockagent_knowledge_base" "test" { } `, rName, model)) } + +func testAccKnowledgeBaseConfig_StructuredDataStore_redshiftProvisioned(rName string) string { + return fmt.Sprintf(` +data "aws_caller_identity" "current" {} +data "aws_region" "current" {} +data "aws_partition" "current" {} + +resource "aws_iam_role" "test" { + name = %[1]q + + assume_role_policy = jsonencode({ + Version = "2012-10-17" + Statement = [ + { + Action = "sts:AssumeRole" + Effect = "Allow" + Principal = { + Service = "bedrock.amazonaws.com" + } + Condition = { + StringEquals = { + "aws:SourceAccount" = data.aws_caller_identity.current.account_id + } + ArnLike = { + "aws:SourceArn" = "arn:${data.aws_partition.current.partition}:bedrock:${data.aws_region.current.region}:${data.aws_caller_identity.current.account_id}:knowledge-base/*" + } + } + } + ] + }) +} + +resource "aws_iam_role_policy" "test" { + name = "%[1]s-bedrock" + role = aws_iam_role.test.id + + policy = jsonencode({ + Version = "2012-10-17" + Statement = [ + { + Sid = "RedshiftDataAPIStatementPermissions" + Effect = "Allow" + Action = [ + "redshift-data:GetStatementResult", + "redshift-data:DescribeStatement", + "redshift-data:CancelStatement" + ] + Resource = ["*"] + }, + { + Sid = "RedshiftDataAPIExecutePermissions" + Effect = "Allow" + Action = [ + "redshift-data:ExecuteStatement" + ] + Resource = ["*"] + }, + { + Sid = "SqlWorkbenchAccess" + Effect = "Allow" + Action = [ + "sqlworkbench:GetSqlRecommendations", + "sqlworkbench:PutSqlGenerationContext", + "sqlworkbench:GetSqlGenerationContext", + "sqlworkbench:DeleteSqlGenerationContext" + ] + Resource = ["*"] + }, + { + Sid = "GenerateQueryAccess" + Effect = "Allow" + Action = [ + "bedrock:GenerateQuery" + ] + Resource = ["*"] + }, + { + Sid = "GetCredentialsWithClusterCredentials" + Effect = "Allow" + Action = [ + "redshift:GetClusterCredentials" + ] + Resource = ["*"] + } + ] + }) +} + +resource "aws_redshift_cluster" "test" { + cluster_identifier = %[1]q + database_name = "mydb" + master_username = "foo_test" + master_password = "Mustbe8characters" + node_type = "ra3.large" + allow_version_upgrade = false + skip_final_snapshot = true +} + +resource "aws_bedrockagent_knowledge_base" "test" { + name = %[1]q + role_arn = aws_iam_role.test.arn + + knowledge_base_configuration { + type = "SQL" + + sql_knowledge_base_configuration { + type = "REDSHIFT" + + redshift_configuration { + query_engine_configuration { + type = "PROVISIONED" + + provisioned_configuration { + cluster_identifier = aws_redshift_cluster.test.cluster_identifier + + auth_configuration { + type = "USERNAME" + database_user = aws_redshift_cluster.test.master_username + } + } + } + + storage_configuration { + type = "REDSHIFT" + + redshift_configuration { + database_name = aws_redshift_cluster.test.database_name + } + } + } + } + } + + depends_on = [aws_iam_role_policy.test] +} +`, rName) +} From 6f18ff54ee10d6fafaec4bc4b5f339b8225d7fcd Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Wed, 10 Dec 2025 14:02:59 -0500 Subject: [PATCH 53/65] Acceptance test output: MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit % make testacc TESTARGS='-run=TestAccBedrockAgent_serial/KnowledgeBase/StructuredDataStoreRedshiftProvisioned' PKG=bedrockagent make: Verifying source code with gofmt... ==> Checking that code complies with gofmt requirements... make: Running acceptance tests on branch: 🌿 f-aws_bedrockagent_knowledge_base-enhancements 🌿... TF_ACC=1 go1.24.11 test ./internal/service/bedrockagent/... -v -count 1 -parallel 20 -run=TestAccBedrockAgent_serial/KnowledgeBase/StructuredDataStoreRedshiftProvisioned -timeout 360m -vet=off 2025/12/10 13:56:08 Creating Terraform AWS Provider (SDKv2-style)... 2025/12/10 13:56:08 Initializing Terraform AWS Provider (SDKv2-style)... === RUN TestAccBedrockAgent_serial === PAUSE TestAccBedrockAgent_serial === CONT TestAccBedrockAgent_serial === RUN TestAccBedrockAgent_serial/KnowledgeBase === RUN TestAccBedrockAgent_serial/KnowledgeBase/StructuredDataStoreRedshiftProvisioned --- PASS: TestAccBedrockAgent_serial (300.23s) --- PASS: TestAccBedrockAgent_serial/KnowledgeBase (300.23s) --- PASS: TestAccBedrockAgent_serial/KnowledgeBase/StructuredDataStoreRedshiftProvisioned (300.23s) PASS ok github.com/hashicorp/terraform-provider-aws/internal/service/bedrockagent 305.618s From dcf8782d6fb8c513737e050504c000bfba117042 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Wed, 10 Dec 2025 14:40:55 -0500 Subject: [PATCH 54/65] Example aws_bedrockagent_knowledge_base structured data store. --- .../bedrockagent_knowledge_base.html.markdown | 40 +++++++++++++++++++ 1 file changed, 40 insertions(+) diff --git a/website/docs/r/bedrockagent_knowledge_base.html.markdown b/website/docs/r/bedrockagent_knowledge_base.html.markdown index badd104cc49c..2e4c53077c6d 100644 --- a/website/docs/r/bedrockagent_knowledge_base.html.markdown +++ b/website/docs/r/bedrockagent_knowledge_base.html.markdown @@ -55,6 +55,46 @@ resource "aws_bedrockagent_knowledge_base" "kendra_example" { } ``` +### Structured Data Store + +```hcl +resource "aws_bedrockagent_knowledge_base" "example" { + name = "example-kb" + role_arn = aws_iam_role.example.arn + + knowledge_base_configuration { + type = "SQL" + + sql_knowledge_base_configuration { + type = "REDSHIFT" + + redshift_configuration { + query_engine_configuration { + type = "PROVISIONED" + + provisioned_configuration { + cluster_identifier = aws_redshift_cluster.example.cluster_identifier + + auth_configuration { + type = "USERNAME" + database_user = aws_redshift_cluster.example.master_username + } + } + } + + storage_configuration { + type = "REDSHIFT" + + redshift_configuration { + database_name = aws_redshift_cluster.example.database_name + } + } + } + } + } +} +``` + ### OpenSearch Managed Cluster Configuration ```terraform From e3e31cd09543dc3b66e54033794aeb70676bca5c Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Wed, 10 Dec 2025 14:41:13 -0500 Subject: [PATCH 55/65] Add 'testAccKnowledgeBase_StructuredDataStore_redshiftServerless'. --- .../service/bedrockagent/bedrockagent_test.go | 1 + .../bedrockagent/knowledge_base_test.go | 181 ++++++++++++++++++ 2 files changed, 182 insertions(+) diff --git a/internal/service/bedrockagent/bedrockagent_test.go b/internal/service/bedrockagent/bedrockagent_test.go index 4a57f7bf8624..0a2e42041505 100644 --- a/internal/service/bedrockagent/bedrockagent_test.go +++ b/internal/service/bedrockagent/bedrockagent_test.go @@ -24,6 +24,7 @@ func TestAccBedrockAgent_serial(t *testing.T) { "OpenSearchManagedClusterBasic": testAccKnowledgeBase_OpenSearchManagedCluster_basic, "S3Vectors": testAccKnowledgeBase_S3Vectors_update, "StructuredDataStoreRedshiftProvisioned": testAccKnowledgeBase_StructuredDataStore_redshiftProvisioned, + "StructuredDataStoreRedshiftServerless": testAccKnowledgeBase_StructuredDataStore_redshiftServerless, }, "DataSource": { acctest.CtBasic: testAccDataSource_basic, diff --git a/internal/service/bedrockagent/knowledge_base_test.go b/internal/service/bedrockagent/knowledge_base_test.go index fb6fc8b2a8d8..3a128ce175f6 100644 --- a/internal/service/bedrockagent/knowledge_base_test.go +++ b/internal/service/bedrockagent/knowledge_base_test.go @@ -618,6 +618,66 @@ func testAccKnowledgeBase_StructuredDataStore_redshiftProvisioned(t *testing.T) }) } +func testAccKnowledgeBase_StructuredDataStore_redshiftServerless(t *testing.T) { + ctx := acctest.Context(t) + var knowledgebase awstypes.KnowledgeBase + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + resourceName := "aws_bedrockagent_knowledge_base.test" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.BedrockAgentServiceID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckKnowledgeBaseDestroy(ctx), + Steps: []resource.TestStep{ + { + Config: testAccKnowledgeBaseConfig_StructuredDataStore_redshiftServerless(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckKnowledgeBaseExists(ctx, resourceName, &knowledgebase), + ), + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + }, + }, + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("knowledge_base_configuration"), knownvalue.ListExact([]knownvalue.Check{ + knownvalue.MapExact(map[string]knownvalue.Check{ + "kendra_knowledge_base_configuration": knownvalue.ListSizeExact(0), + "sql_knowledge_base_configuration": knownvalue.ListExact([]knownvalue.Check{ + knownvalue.ObjectExact(map[string]knownvalue.Check{ + names.AttrType: tfknownvalue.StringExact(awstypes.QueryEngineTypeRedshift), + "redshift_configuration": knownvalue.ListExact([]knownvalue.Check{ + knownvalue.ObjectExact(map[string]knownvalue.Check{ + "query_engine_configuration": knownvalue.ListExact([]knownvalue.Check{ + knownvalue.ObjectExact(map[string]knownvalue.Check{ + names.AttrType: tfknownvalue.StringExact(awstypes.RedshiftQueryEngineTypeServerless), + "provisioned_configuration": knownvalue.ListSizeExact(0), + "serverless_configuration": knownvalue.ListSizeExact(1), + }), + }), + "query_generation_configuration": knownvalue.ListSizeExact(1), + "storage_configuration": knownvalue.ListExact([]knownvalue.Check{ + knownvalue.ObjectExact(map[string]knownvalue.Check{ + names.AttrType: tfknownvalue.StringExact(awstypes.RedshiftQueryEngineStorageTypeRedshift), + "aws_data_catalog_configuration": knownvalue.ListSizeExact(0), + "redshift_configuration": knownvalue.ListSizeExact(1), + }), + }), + }), + }), + }), + }), + names.AttrType: tfknownvalue.StringExact(awstypes.KnowledgeBaseTypeSql), + "vector_knowledge_base_configuration": knownvalue.ListSizeExact(0), + }), + })), + }, + }, + }, + }) +} + func testAccCheckKnowledgeBaseDestroy(ctx context.Context) resource.TestCheckFunc { return func(s *terraform.State) error { conn := acctest.Provider.Meta().(*conns.AWSClient).BedrockAgentClient(ctx) @@ -1974,3 +2034,124 @@ resource "aws_bedrockagent_knowledge_base" "test" { } `, rName) } + +func testAccKnowledgeBaseConfig_StructuredDataStore_redshiftServerless(rName string) string { + return fmt.Sprintf(` +data "aws_caller_identity" "current" {} +data "aws_region" "current" {} +data "aws_partition" "current" {} + +resource "aws_iam_role" "test" { + name = %[1]q + + assume_role_policy = jsonencode({ + Version = "2012-10-17" + Statement = [ + { + Action = "sts:AssumeRole" + Effect = "Allow" + Principal = { + Service = "bedrock.amazonaws.com" + } + Condition = { + StringEquals = { + "aws:SourceAccount" = data.aws_caller_identity.current.account_id + } + ArnLike = { + "aws:SourceArn" = "arn:${data.aws_partition.current.partition}:bedrock:${data.aws_region.current.region}:${data.aws_caller_identity.current.account_id}:knowledge-base/*" + } + } + } + ] + }) +} + +# Redshift Serverless +resource "aws_iam_role_policy" "test" { + name = "%[1]s-bedrock" + role = aws_iam_role.test.id + + policy = jsonencode({ + Version = "2012-10-17" + Statement = [ + { + Sid = "SqlWorkbenchAccess" + Effect = "Allow" + Action = [ + "sqlworkbench:GetSqlRecommendations", + "sqlworkbench:PutSqlGenerationContext", + "sqlworkbench:GetSqlGenerationContext", + "sqlworkbench:DeleteSqlGenerationContext" + ] + Resource = ["*"] + }, + { + Sid = "RedshiftServerlessGetCredentials" + Effect = "Allow" + Action = [ + "redshift-serverless:GetClusterCredentials" + ] + Resource = ["*"] + } + ] + }) +} + +resource "aws_redshiftserverless_namespace" "test" { + namespace_name = %[1]q + manage_admin_password = true +} + +resource "aws_redshiftserverless_workgroup" "test" { + namespace_name = aws_redshiftserverless_namespace.test.namespace_name + workgroup_name = %[1]q +} + +resource "aws_bedrockagent_knowledge_base" "test" { + name = %[1]q + role_arn = aws_iam_role.test.arn + + knowledge_base_configuration { + type = "SQL" + + sql_knowledge_base_configuration { + type = "REDSHIFT" + + redshift_configuration { + query_engine_configuration { + type = "SERVERLESS" + + serverless_configuration { + workgroup_arn = aws_redshiftserverless_workgroup.test.arn + + auth_configuration { + type = "USERNAME_PASSWORD" + username_password_secret_arn = aws_redshiftserverless_namespace.test.admin_password_secret_arn + } + } + } + + storage_configuration { + type = "REDSHIFT" + + redshift_configuration { + database_name = aws_redshiftserverless_namespace.test.db_name + } + } + + query_generation_configuration { + generation_context { + curated_query { + natural_language = "Find all the things" + sql = "SELECT * FROM things;" + } + } + } + } + } + } + + depends_on = [aws_iam_role_policy.test] +} +`, rName) +} From d5f272aeef98b8da51d54fd3cc1f76d14f620672 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Wed, 10 Dec 2025 14:58:39 -0500 Subject: [PATCH 56/65] Acceptance test output: MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit % make testacc TESTARGS='-run=TestAccBedrockAgent_serial/KnowledgeBase/StructuredDataStoreRedshiftServerless' PKG=bedrockagent make: Verifying source code with gofmt... ==> Checking that code complies with gofmt requirements... make: Running acceptance tests on branch: 🌿 f-aws_bedrockagent_knowledge_base-enhancements 🌿... TF_ACC=1 go1.24.11 test ./internal/service/bedrockagent/... -v -count 1 -parallel 20 -run=TestAccBedrockAgent_serial/KnowledgeBase/StructuredDataStoreRedshiftServerless -timeout 360m -vet=off 2025/12/10 14:42:05 Creating Terraform AWS Provider (SDKv2-style)... 2025/12/10 14:42:05 Initializing Terraform AWS Provider (SDKv2-style)... === RUN TestAccBedrockAgent_serial === PAUSE TestAccBedrockAgent_serial === CONT TestAccBedrockAgent_serial === RUN TestAccBedrockAgent_serial/KnowledgeBase === RUN TestAccBedrockAgent_serial/KnowledgeBase/StructuredDataStoreRedshiftServerless --- PASS: TestAccBedrockAgent_serial (378.33s) --- PASS: TestAccBedrockAgent_serial/KnowledgeBase (378.33s) --- PASS: TestAccBedrockAgent_serial/KnowledgeBase/StructuredDataStoreRedshiftServerless (378.33s) PASS ok github.com/hashicorp/terraform-provider-aws/internal/service/bedrockagent 383.801s From 83c1e4a73f5329cf262b73b84343933ba1b733ef Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Wed, 10 Dec 2025 16:35:04 -0500 Subject: [PATCH 57/65] r/aws_bedrockagent_knowledge_base: Add `storage_configuration.neptune_analytics_configuration` argument. --- .changelog/45465.txt | 2 +- .../service/bedrockagent/knowledge_base.go | 61 +++++++++++++++++++ .../bedrockagent/knowledge_base_test.go | 3 + .../bedrockagent_knowledge_base.html.markdown | 18 ++++-- 4 files changed, 79 insertions(+), 5 deletions(-) diff --git a/.changelog/45465.txt b/.changelog/45465.txt index 72ab5ff316c5..df85be9f6843 100644 --- a/.changelog/45465.txt +++ b/.changelog/45465.txt @@ -1,5 +1,5 @@ ```release-note:enhancement -resource/aws_bedrockagent_knowledge_base: Add `knowledge_base_configuration.sql_knowledge_base_configuration` argument +resource/aws_bedrockagent_knowledge_base: Add `knowledge_base_configuration.sql_knowledge_base_configuration` and `storage_configuration.neptune_analytics_configuration` arguments ``` ```release-note:bug diff --git a/internal/service/bedrockagent/knowledge_base.go b/internal/service/bedrockagent/knowledge_base.go index 054acd2f0e0b..0b46663458e1 100644 --- a/internal/service/bedrockagent/knowledge_base.go +++ b/internal/service/bedrockagent/knowledge_base.go @@ -668,6 +668,7 @@ func (r *knowledgeBaseResource) Schema(ctx context.Context, request resource.Sch listvalidator.SizeAtMost(1), listvalidator.ExactlyOneOf( path.MatchRelative().AtParent().AtName("mongo_db_atlas_configuration"), + path.MatchRelative().AtParent().AtName("neptune_analytics_configuration"), path.MatchRelative().AtParent().AtName("opensearch_managed_cluster_configuration"), path.MatchRelative().AtParent().AtName("opensearch_serverless_configuration"), path.MatchRelative().AtParent().AtName("pinecone_configuration"), @@ -762,6 +763,55 @@ func (r *knowledgeBaseResource) Schema(ctx context.Context, request resource.Sch }, }, }, + "neptune_analytics_configuration": schema.ListNestedBlock{ + CustomType: fwtypes.NewListNestedObjectTypeOf[neptuneAnalyticsConfigurationModel](ctx), + Validators: []validator.List{ + listvalidator.SizeAtMost(1), + }, + PlanModifiers: []planmodifier.List{ + listplanmodifier.RequiresReplace(), + }, + NestedObject: schema.NestedBlockObject{ + Attributes: map[string]schema.Attribute{ + "graph_arn": schema.StringAttribute{ + CustomType: fwtypes.ARNType, + Required: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.RequiresReplace(), + }, + }, + }, + Blocks: map[string]schema.Block{ + "field_mapping": schema.ListNestedBlock{ + CustomType: fwtypes.NewListNestedObjectTypeOf[neptuneAnalyticsFieldMappingModel](ctx), + Validators: []validator.List{ + listvalidator.IsRequired(), + listvalidator.SizeAtLeast(1), + listvalidator.SizeAtMost(1), + }, + PlanModifiers: []planmodifier.List{ + listplanmodifier.RequiresReplace(), + }, + NestedObject: schema.NestedBlockObject{ + Attributes: map[string]schema.Attribute{ + "metadata_field": schema.StringAttribute{ + Required: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.RequiresReplace(), + }, + }, + "text_field": schema.StringAttribute{ + Required: true, + PlanModifiers: []planmodifier.String{ + stringplanmodifier.RequiresReplace(), + }, + }, + }, + }, + }, + }, + }, + }, "opensearch_managed_cluster_configuration": schema.ListNestedBlock{ CustomType: fwtypes.NewListNestedObjectTypeOf[openSearchManagedClusterConfigurationModel](ctx), Validators: []validator.List{ @@ -1595,6 +1645,7 @@ type storageLocationModel struct { type storageConfigurationModel struct { MongoDBAtlasConfiguration fwtypes.ListNestedObjectValueOf[mongoDBAtlasConfigurationModel] `tfsdk:"mongo_db_atlas_configuration"` + NeptuneAnalyticsConfiguration fwtypes.ListNestedObjectValueOf[neptuneAnalyticsConfigurationModel] `tfsdk:"neptune_analytics_configuration"` OpenSearchManagedClusterConfiguration fwtypes.ListNestedObjectValueOf[openSearchManagedClusterConfigurationModel] `tfsdk:"opensearch_managed_cluster_configuration"` OpenSearchServerlessConfiguration fwtypes.ListNestedObjectValueOf[openSearchServerlessConfigurationModel] `tfsdk:"opensearch_serverless_configuration"` PineconeConfiguration fwtypes.ListNestedObjectValueOf[pineconeConfigurationModel] `tfsdk:"pinecone_configuration"` @@ -1621,6 +1672,16 @@ type mongoDBAtlasFieldMappingModel struct { VectorField types.String `tfsdk:"vector_field"` } +type neptuneAnalyticsConfigurationModel struct { + FieldMapping fwtypes.ListNestedObjectValueOf[neptuneAnalyticsFieldMappingModel] `tfsdk:"field_mapping"` + GraphARN fwtypes.ARN `tfsdk:"graph_arn"` +} + +type neptuneAnalyticsFieldMappingModel struct { + MetadataField types.String `tfsdk:"metadata_field"` + TextField types.String `tfsdk:"text_field"` +} + type openSearchManagedClusterConfigurationModel struct { DomainARN fwtypes.ARN `tfsdk:"domain_arn"` DomainEndpoint types.String `tfsdk:"domain_endpoint"` diff --git a/internal/service/bedrockagent/knowledge_base_test.go b/internal/service/bedrockagent/knowledge_base_test.go index 3a128ce175f6..eda19c8a2346 100644 --- a/internal/service/bedrockagent/knowledge_base_test.go +++ b/internal/service/bedrockagent/knowledge_base_test.go @@ -463,6 +463,7 @@ func testAccKnowledgeBase_OpenSearchManagedCluster_basic(t *testing.T) { statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("storage_configuration"), knownvalue.ListExact([]knownvalue.Check{ knownvalue.MapExact(map[string]knownvalue.Check{ "mongo_db_atlas_configuration": knownvalue.ListSizeExact(0), + "neptune_analytics_configuration": knownvalue.ListSizeExact(0), "opensearch_managed_cluster_configuration": knownvalue.ListSizeExact(1), "opensearch_serverless_configuration": knownvalue.ListSizeExact(0), names.AttrType: tfknownvalue.StringExact(awstypes.KnowledgeBaseStorageTypeOpensearchManagedCluster), @@ -513,6 +514,7 @@ func testAccKnowledgeBase_S3Vectors_update(t *testing.T) { statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("storage_configuration"), knownvalue.ListExact([]knownvalue.Check{ knownvalue.MapExact(map[string]knownvalue.Check{ "mongo_db_atlas_configuration": knownvalue.ListSizeExact(0), + "neptune_analytics_configuration": knownvalue.ListSizeExact(0), "opensearch_managed_cluster_configuration": knownvalue.ListSizeExact(0), "opensearch_serverless_configuration": knownvalue.ListSizeExact(0), names.AttrType: tfknownvalue.StringExact(awstypes.KnowledgeBaseStorageTypeS3Vectors), @@ -543,6 +545,7 @@ func testAccKnowledgeBase_S3Vectors_update(t *testing.T) { statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("storage_configuration"), knownvalue.ListExact([]knownvalue.Check{ knownvalue.MapExact(map[string]knownvalue.Check{ "mongo_db_atlas_configuration": knownvalue.ListSizeExact(0), + "neptune_analytics_configuration": knownvalue.ListSizeExact(0), "opensearch_managed_cluster_configuration": knownvalue.ListSizeExact(0), "opensearch_serverless_configuration": knownvalue.ListSizeExact(0), names.AttrType: tfknownvalue.StringExact(awstypes.KnowledgeBaseStorageTypeS3Vectors), diff --git a/website/docs/r/bedrockagent_knowledge_base.html.markdown b/website/docs/r/bedrockagent_knowledge_base.html.markdown index 2e4c53077c6d..4bdc408616cc 100644 --- a/website/docs/r/bedrockagent_knowledge_base.html.markdown +++ b/website/docs/r/bedrockagent_knowledge_base.html.markdown @@ -256,7 +256,7 @@ The `redshift_configuration` configuration block supports the following argument * `query_engine_configuration` - (Required) Configurations for an Amazon Redshift query engine. See [`query_engine_configuration` block](#query_engine_configuration-block) for details. * `query_generation_configuration` - (Optional) Configurations for generating queries. See [`query_generation_configuration` block](#query_generation_configuration-block) for details. -* `storage_configuration` - (Required) Configurations for Amazon Redshift database storage. See [`storage_configuration` block](#storage_configuration-block) for details. +* `storage_configuration` - (Required) Configurations for Amazon Redshift database storage. See [`storage_configuration` block](#redshift-storage_configuration-block) for details. ### `query_engine_configuration` block @@ -333,7 +333,7 @@ The `column` configuration block supports the following arguments: * `inclusion` - (Optional) Whether to include or exclude the column during query generation. Valid values `INCLUDE`, `EXCLUDE`. * `name` - (Required) Name of the column for which the other fields in this object apply. -### `storage_configuration` block +### Redshift `storage_configuration` block The `storage_configuration` configuration block supports the following arguments: @@ -397,8 +397,9 @@ The `s3_location` configuration block supports the following arguments: The `storage_configuration` configuration block supports the following arguments: -* `type` - (Required) Vector store service in which the knowledge base is stored. Valid Values: `MONGO_DB_ATLAS`, `OPENSEARCH_SERVERLESS`, `OPENSEARCH_MANAGED_CLUSTER`, `PINECONE`, `REDIS_ENTERPRISE_CLOUD`, `RDS`, `S3_VECTORS`. -* `mongo_db_atlas_configuration` – (Optional) The storage configuration of the knowledge base in MongoDB Atlas. See [`opensearch_managed_cluster_comongo_db_atlas_configurationnfiguration` block](#mongo_db_atlas_configuration-block) for details. +* `type` - (Required) Vector store service in which the knowledge base is stored. Valid Values: `MONGO_DB_ATLAS`, `OPENSEARCH_SERVERLESS`, `OPENSEARCH_MANAGED_CLUSTER`, `PINECONE`, `REDIS_ENTERPRISE_CLOUD`, `RDS`, `S3_VECTORS`, `NEPTUNE_ANALYTICS`. +* `mongo_db_atlas_configuration` – (Optional) The storage configuration of the knowledge base in MongoDB Atlas. See [`mongo_db_atlas_configuration` block](#mongo_db_atlas_configuration-block) for details. +* `neptune_analytics_configuration` – (Optional) The storage configuration of the knowledge base in Amazon Neptune Analytics. See [`neptune_analytics_configuration` block](#neptune_analytics_configuration-block) for details. * `opensearch_managed_cluster_configuration` - (Optional) The storage configuration of the knowledge base in Amazon OpenSearch Service Managed Cluster. See [`opensearch_managed_cluster_configuration` block](#opensearch_managed_cluster_configuration-block) for details. * `opensearch_serverless_configuration` - (Optional) The storage configuration of the knowledge base in Amazon OpenSearch Service Serverless. See [`opensearch_serverless_configuration` block](#opensearch_serverless_configuration-block) for details. * `pinecone_configuration` - (Optional) The storage configuration of the knowledge base in Pinecone. See [`pinecone_configuration` block](#pinecone_configuration-block) for details. @@ -422,6 +423,15 @@ The `mongo_db_atlas_configuration` configuration block supports the following ar * `endpoint_service_name` – (Optional) The name of the service that hosts the MongoDB Atlas database. * `text_index_name` – (Optional) The name of the vector index. +### `neptune_analytics_configuration` block + +The `neptune_analytics_configuration` configuration block supports the following arguments: + +* `field_mapping` - (Required) The names of the fields to which to map information about the vector store. This block supports the following arguments: + * `metadata_field` - (Required) Name of the field in which Amazon Bedrock stores metadata about the vector store. + * `text_field` - (Required) Name of the field in which Amazon Bedrock stores the raw text from your data. The text is split according to the chunking strategy you choose. +* `graph_arn` - (Required) ARN of the Neptune Analytics vector store. + ### `opensearch_managed_cluster_configuration` block The `opensearch_managed_cluster_configuration` configuration block supports the following arguments: From 62a51068572487e4348d30bc27f6c10649ec4142 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Thu, 11 Dec 2025 08:36:58 -0500 Subject: [PATCH 58/65] Add 'testAccKnowledgeBase_NeptuneAnalytics_basic'. --- .../service/bedrockagent/bedrockagent_test.go | 1 + .../bedrockagent/knowledge_base_test.go | 161 +++++++++++++++++- 2 files changed, 160 insertions(+), 2 deletions(-) diff --git a/internal/service/bedrockagent/bedrockagent_test.go b/internal/service/bedrockagent/bedrockagent_test.go index 0a2e42041505..4c334a3cd885 100644 --- a/internal/service/bedrockagent/bedrockagent_test.go +++ b/internal/service/bedrockagent/bedrockagent_test.go @@ -25,6 +25,7 @@ func TestAccBedrockAgent_serial(t *testing.T) { "S3Vectors": testAccKnowledgeBase_S3Vectors_update, "StructuredDataStoreRedshiftProvisioned": testAccKnowledgeBase_StructuredDataStore_redshiftProvisioned, "StructuredDataStoreRedshiftServerless": testAccKnowledgeBase_StructuredDataStore_redshiftServerless, + "NeptuneAnalytics": testAccKnowledgeBase_NeptuneAnalytics_basic, }, "DataSource": { acctest.CtBasic: testAccDataSource_basic, diff --git a/internal/service/bedrockagent/knowledge_base_test.go b/internal/service/bedrockagent/knowledge_base_test.go index eda19c8a2346..7da092a44720 100644 --- a/internal/service/bedrockagent/knowledge_base_test.go +++ b/internal/service/bedrockagent/knowledge_base_test.go @@ -470,7 +470,7 @@ func testAccKnowledgeBase_OpenSearchManagedCluster_basic(t *testing.T) { "pinecone_configuration": knownvalue.ListSizeExact(0), "rds_configuration": knownvalue.ListSizeExact(0), "redis_enterprise_cloud_configuration": knownvalue.ListSizeExact(0), - "s3_vectors": knownvalue.ListSizeExact(0), + "s3_vectors_configuration": knownvalue.ListSizeExact(0), }), })), }, @@ -681,6 +681,56 @@ func testAccKnowledgeBase_StructuredDataStore_redshiftServerless(t *testing.T) { }) } +func testAccKnowledgeBase_NeptuneAnalytics_basic(t *testing.T) { + ctx := acctest.Context(t) + var knowledgebase awstypes.KnowledgeBase + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + resourceName := "aws_bedrockagent_knowledge_base.test" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, names.BedrockAgentServiceID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckKnowledgeBaseDestroy(ctx), + Steps: []resource.TestStep{ + { + Config: testAccKnowledgeBaseConfig_NeptuneAnalytics_basic(rName), + Check: resource.ComposeTestCheckFunc( + testAccCheckKnowledgeBaseExists(ctx, resourceName, &knowledgebase), + ), + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + }, + }, + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("knowledge_base_configuration"), knownvalue.ListExact([]knownvalue.Check{ + knownvalue.MapExact(map[string]knownvalue.Check{ + "kendra_knowledge_base_configuration": knownvalue.ListSizeExact(0), + "sql_knowledge_base_configuration": knownvalue.ListSizeExact(0), + names.AttrType: tfknownvalue.StringExact(awstypes.KnowledgeBaseTypeVector), + "vector_knowledge_base_configuration": knownvalue.ListSizeExact(1), + }), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("storage_configuration"), knownvalue.ListExact([]knownvalue.Check{ + knownvalue.MapExact(map[string]knownvalue.Check{ + "mongo_db_atlas_configuration": knownvalue.ListSizeExact(0), + "neptune_analytics_configuration": knownvalue.ListSizeExact(1), + "opensearch_managed_cluster_configuration": knownvalue.ListSizeExact(0), + "opensearch_serverless_configuration": knownvalue.ListSizeExact(0), + names.AttrType: tfknownvalue.StringExact(awstypes.KnowledgeBaseStorageTypeNeptuneAnalytics), + "pinecone_configuration": knownvalue.ListSizeExact(0), + "rds_configuration": knownvalue.ListSizeExact(0), + "redis_enterprise_cloud_configuration": knownvalue.ListSizeExact(0), + "s3_vectors_configuration": knownvalue.ListSizeExact(0), + }), + })), + }, + }, + }, + }) +} + func testAccCheckKnowledgeBaseDestroy(ctx context.Context) resource.TestCheckFunc { return func(s *terraform.State) error { conn := acctest.Provider.Meta().(*conns.AWSClient).BedrockAgentClient(ctx) @@ -2069,7 +2119,6 @@ resource "aws_iam_role" "test" { }) } -# Redshift Serverless resource "aws_iam_role_policy" "test" { name = "%[1]s-bedrock" role = aws_iam_role.test.id @@ -2158,3 +2207,111 @@ resource "aws_bedrockagent_knowledge_base" "test" { } `, rName) } + +func testAccKnowledgeBaseConfig_NeptuneAnalytics_basic(rName string) string { + return fmt.Sprintf(` +data "aws_caller_identity" "current" {} +data "aws_region" "current" {} +data "aws_partition" "current" {} + +resource "aws_iam_role" "test" { + name = %[1]q + + assume_role_policy = jsonencode({ + Version = "2012-10-17" + Statement = [ + { + Action = "sts:AssumeRole" + Effect = "Allow" + Principal = { + Service = "bedrock.amazonaws.com" + } + Condition = { + StringEquals = { + "aws:SourceAccount" = data.aws_caller_identity.current.account_id + } + ArnLike = { + "aws:SourceArn" = "arn:${data.aws_partition.current.partition}:bedrock:${data.aws_region.current.region}:${data.aws_caller_identity.current.account_id}:knowledge-base/*" + } + } + } + ] + }) +} + +resource "aws_iam_role_policy" "test" { + name = "%[1]s-bedrock" + role = aws_iam_role.test.id + + policy = jsonencode({ + Version = "2012-10-17" + Statement = [ + { + Sid = "AllowAllPermissionsForRDS" + Effect = "Allow" + Action = [ + "rds:*" + ] + Resource = ["*"] + }, + { + Sid = "AllowDataAccessForNeptune" + Effect = "Allow" + Action = [ + "neptune-db:*" + ] + Resource = ["*"] + }, + { + Sid = "AllowAllPermissionsForNeptuneGraph" + Effect = "Allow" + Action = [ + "neptune-graph:*" + ] + Resource = ["*"] + } + ] + }) +} + +resource "aws_neptunegraph_graph" "test" { + graph_name = %[1]q + provisioned_memory = 16 + public_connectivity = false + replica_count = 0 + deletion_protection = false + + vector_search_configuration { + vector_search_dimension = 1024 + } +} + +resource "aws_bedrockagent_knowledge_base" "test" { + name = %[1]q + role_arn = aws_iam_role.test.arn + + knowledge_base_configuration { + type = "VECTOR" + + vector_knowledge_base_configuration { + embedding_model_arn = "arn:${data.aws_partition.current.partition}:bedrock:${data.aws_region.current.region}::foundation-model/cohere.embed-english-v3" + } + } + + storage_configuration { + type = "NEPTUNE_ANALYTICS" + + neptune_analytics_configuration { + graph_arn = aws_neptunegraph_graph.test.arn + + field_mapping { + metadata_field = "metadata" + text_field = "text" + } + } + } + + depends_on = [aws_iam_role_policy.test] +} +`, rName) +} From 36946b862eddfa01e07f3b6268da134dbb369954 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Thu, 11 Dec 2025 08:57:44 -0500 Subject: [PATCH 59/65] Acceptance test output: MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit % make testacc TESTARGS='-run=TestAccBedrockAgent_serial/KnowledgeBase/NeptuneAnalytics' PKG=bedrockagent make: Verifying source code with gofmt... ==> Checking that code complies with gofmt requirements... make: Running acceptance tests on branch: 🌿 f-aws_bedrockagent_knowledge_base-enhancements 🌿... TF_ACC=1 go1.24.11 test ./internal/service/bedrockagent/... -v -count 1 -parallel 20 -run=TestAccBedrockAgent_serial/KnowledgeBase/NeptuneAnalytics -timeout 360m -vet=off 2025/12/11 08:48:37 Creating Terraform AWS Provider (SDKv2-style)... 2025/12/11 08:48:37 Initializing Terraform AWS Provider (SDKv2-style)... === RUN TestAccBedrockAgent_serial === PAUSE TestAccBedrockAgent_serial === CONT TestAccBedrockAgent_serial === RUN TestAccBedrockAgent_serial/KnowledgeBase === RUN TestAccBedrockAgent_serial/KnowledgeBase/NeptuneAnalytics --- PASS: TestAccBedrockAgent_serial (426.11s) --- PASS: TestAccBedrockAgent_serial/KnowledgeBase (426.11s) --- PASS: TestAccBedrockAgent_serial/KnowledgeBase/NeptuneAnalytics (426.11s) PASS ok github.com/hashicorp/terraform-provider-aws/internal/service/bedrockagent 431.463s From 6af99df988ae6dc539ebde5fa23f931395a4bae1 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Thu, 11 Dec 2025 09:11:33 -0500 Subject: [PATCH 60/65] r/aws_bedrockagent_knowledge_base: Simplify update acceptance test. --- .../service/bedrockagent/bedrockagent_test.go | 12 +- .../bedrockagent/knowledge_base_test.go | 310 +++++++++--------- 2 files changed, 154 insertions(+), 168 deletions(-) diff --git a/internal/service/bedrockagent/bedrockagent_test.go b/internal/service/bedrockagent/bedrockagent_test.go index 4c334a3cd885..2605e4b9adf5 100644 --- a/internal/service/bedrockagent/bedrockagent_test.go +++ b/internal/service/bedrockagent/bedrockagent_test.go @@ -14,12 +14,12 @@ func TestAccBedrockAgent_serial(t *testing.T) { testCases := map[string]map[string]func(t *testing.T){ "KnowledgeBase": { - "RDS": testAccKnowledgeBase_RDS_update, - acctest.CtDisappears: testAccKnowledgeBase_disappears, - "tags": testAccKnowledgeBase_tags, - "OpenSearchServerlessBasic": testAccKnowledgeBase_OpenSearchServerless_basic, - "OpenSearchServerlessUpdate": testAccKnowledgeBase_OpenSearchServerless_update, - "OpenSearchServerlessSupplementalDataStorage": testAccKnowledgeBase_OpenSearchServerless_supplementalDataStorage, + "RDS": testAccKnowledgeBase_RDS_update, + acctest.CtDisappears: testAccKnowledgeBase_disappears, + "tags": testAccKnowledgeBase_tags, + "update": testAccKnowledgeBase_update, + "SupplementalDataStorage": testAccKnowledgeBase_supplementalDataStorage, + "OpenSearchServerlessBasic": testAccKnowledgeBase_OpenSearchServerless_basic, "KendraBasic": testAccKnowledgeBase_Kendra_basic, "OpenSearchManagedClusterBasic": testAccKnowledgeBase_OpenSearchManagedCluster_basic, "S3Vectors": testAccKnowledgeBase_S3Vectors_update, diff --git a/internal/service/bedrockagent/knowledge_base_test.go b/internal/service/bedrockagent/knowledge_base_test.go index 7da092a44720..5f012ca7b425 100644 --- a/internal/service/bedrockagent/knowledge_base_test.go +++ b/internal/service/bedrockagent/knowledge_base_test.go @@ -264,40 +264,34 @@ func testAccKnowledgeBase_OpenSearchServerless_basic(t *testing.T) { }) } -func testAccKnowledgeBase_OpenSearchServerless_update(t *testing.T) { +func testAccKnowledgeBase_update(t *testing.T) { ctx := acctest.Context(t) - collectionName := skipIfOSSCollectionNameEnvVarNotSet(t) var knowledgebase awstypes.KnowledgeBase rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) resourceName := "aws_bedrockagent_knowledge_base.test" foundationModel := "amazon.titan-embed-text-v2:0" resource.Test(t, resource.TestCase{ - PreCheck: func() { - acctest.PreCheck(ctx, t) - }, + PreCheck: func() { acctest.PreCheck(ctx, t) }, ErrorCheck: acctest.ErrorCheck(t, names.BedrockAgentServiceID), ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, CheckDestroy: testAccCheckKnowledgeBaseDestroy(ctx), Steps: []resource.TestStep{ { - Config: testAccKnowledgeBaseConfig_OpenSearchServerless_basic(rName, collectionName, foundationModel), + Config: testAccKnowledgeBaseConfig_description(rName, foundationModel, "desc1"), Check: resource.ComposeTestCheckFunc( testAccCheckKnowledgeBaseExists(ctx, resourceName, &knowledgebase), - resource.TestCheckResourceAttr(resourceName, names.AttrName, rName), - resource.TestCheckResourceAttrPair(resourceName, names.AttrRoleARN, "aws_iam_role.test", names.AttrARN), - resource.TestCheckResourceAttr(resourceName, "knowledge_base_configuration.#", "1"), - resource.TestCheckResourceAttr(resourceName, "knowledge_base_configuration.0.vector_knowledge_base_configuration.#", "1"), - resource.TestCheckResourceAttr(resourceName, "knowledge_base_configuration.0.type", "VECTOR"), - resource.TestCheckResourceAttr(resourceName, "storage_configuration.#", "1"), - resource.TestCheckResourceAttr(resourceName, "storage_configuration.0.type", "OPENSEARCH_SERVERLESS"), - resource.TestCheckResourceAttr(resourceName, "storage_configuration.0.opensearch_serverless_configuration.#", "1"), - resource.TestCheckResourceAttr(resourceName, "storage_configuration.0.opensearch_serverless_configuration.0.vector_index_name", "bedrock-knowledge-base-default-index"), - resource.TestCheckResourceAttr(resourceName, "storage_configuration.0.opensearch_serverless_configuration.0.field_mapping.#", "1"), - resource.TestCheckResourceAttr(resourceName, "storage_configuration.0.opensearch_serverless_configuration.0.field_mapping.0.vector_field", "bedrock-knowledge-base-default-vector"), - resource.TestCheckResourceAttr(resourceName, "storage_configuration.0.opensearch_serverless_configuration.0.field_mapping.0.text_field", "AMAZON_BEDROCK_TEXT_CHUNK"), - resource.TestCheckResourceAttr(resourceName, "storage_configuration.0.opensearch_serverless_configuration.0.field_mapping.0.metadata_field", "AMAZON_BEDROCK_METADATA"), ), + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + }, + }, + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrDescription), knownvalue.StringExact("desc1")), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrName), knownvalue.StringExact(rName)), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + }, }, { ResourceName: resourceName, @@ -305,35 +299,26 @@ func testAccKnowledgeBase_OpenSearchServerless_update(t *testing.T) { ImportStateVerify: true, }, { - Config: testAccKnowledgeBaseConfig_OpenSearchServerless_update(rName, collectionName, foundationModel), + Config: testAccKnowledgeBaseConfig_description(rName, foundationModel, "desc2"), Check: resource.ComposeTestCheckFunc( testAccCheckKnowledgeBaseExists(ctx, resourceName, &knowledgebase), - resource.TestCheckResourceAttr(resourceName, names.AttrName, rName+"-updated"), - resource.TestCheckResourceAttr(resourceName, names.AttrDescription, rName), - resource.TestCheckResourceAttrPair(resourceName, names.AttrRoleARN, "aws_iam_role.test", names.AttrARN), - resource.TestCheckResourceAttr(resourceName, "knowledge_base_configuration.#", "1"), - resource.TestCheckResourceAttr(resourceName, "knowledge_base_configuration.0.vector_knowledge_base_configuration.#", "1"), - resource.TestCheckResourceAttr(resourceName, "knowledge_base_configuration.0.type", "VECTOR"), - resource.TestCheckResourceAttr(resourceName, "storage_configuration.#", "1"), - resource.TestCheckResourceAttr(resourceName, "storage_configuration.0.type", "OPENSEARCH_SERVERLESS"), - resource.TestCheckResourceAttr(resourceName, "storage_configuration.0.opensearch_serverless_configuration.#", "1"), - resource.TestCheckResourceAttr(resourceName, "storage_configuration.0.opensearch_serverless_configuration.0.vector_index_name", "bedrock-knowledge-base-default-index"), - resource.TestCheckResourceAttr(resourceName, "storage_configuration.0.opensearch_serverless_configuration.0.field_mapping.#", "1"), - resource.TestCheckResourceAttr(resourceName, "storage_configuration.0.opensearch_serverless_configuration.0.field_mapping.0.vector_field", "bedrock-knowledge-base-default-vector"), - resource.TestCheckResourceAttr(resourceName, "storage_configuration.0.opensearch_serverless_configuration.0.field_mapping.0.text_field", "AMAZON_BEDROCK_TEXT_CHUNK"), - resource.TestCheckResourceAttr(resourceName, "storage_configuration.0.opensearch_serverless_configuration.0.field_mapping.0.metadata_field", "AMAZON_BEDROCK_METADATA"), ), - }, - { - ResourceName: resourceName, - ImportState: true, - ImportStateVerify: true, + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), + }, + }, + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrDescription), knownvalue.StringExact("desc2")), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrName), knownvalue.StringExact(rName)), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + }, }, }, }) } -func testAccKnowledgeBase_OpenSearchServerless_supplementalDataStorage(t *testing.T) { +func testAccKnowledgeBase_supplementalDataStorage(t *testing.T) { ctx := acctest.Context(t) collectionName := skipIfOSSCollectionNameEnvVarNotSet(t) var knowledgebase awstypes.KnowledgeBase @@ -1202,6 +1187,129 @@ resource "aws_bedrockagent_knowledge_base" "test" { `, rName, model, tag1Key, tag1Value, tag2Key, tag2Value)) } +func testAccKnowledgeBaseConfig_description(rName, model, description string) string { + return acctest.ConfigCompose(acctest.ConfigBedrockAgentKnowledgeBaseS3VectorsBase(rName), fmt.Sprintf(` +resource "aws_bedrockagent_knowledge_base" "test" { + depends_on = [ + aws_iam_role_policy.test, + ] + + name = %[1]q + role_arn = aws_iam_role.test.arn + description = %[3]q + + knowledge_base_configuration { + type = "VECTOR" + + vector_knowledge_base_configuration { + embedding_model_arn = "arn:${data.aws_partition.current.partition}:bedrock:${data.aws_region.current.region}::foundation-model/%[2]s" + embedding_model_configuration { + bedrock_embedding_model_configuration { + dimensions = 256 + embedding_data_type = "FLOAT32" + } + } + } + } + + storage_configuration { + type = "S3_VECTORS" + + s3_vectors_configuration { + index_arn = aws_s3vectors_index.test.index_arn + } + } +} +`, rName, model, description)) +} + +func testAccKnowledgeBaseConfig_OpenSearchServerless_supplementalDataStorage(rName, collectionName, model string) string { + return acctest.ConfigCompose(testAccKnowledgeBaseConfig_baseOpenSearchServerless(rName, collectionName, model), fmt.Sprintf(` +resource "aws_s3_bucket" "test" { + bucket = %[1]q + force_destroy = true +} + +data "aws_iam_policy_document" "test_s3" { + statement { + effect = "Allow" + actions = [ + "s3:DeleteObject", + "s3:GetObject", + "s3:ListBucket", + "s3:PutObject", + ] + resources = [ + "arn:${data.aws_partition.current.partition}:s3:::${aws_s3_bucket.test.bucket}", + "arn:${data.aws_partition.current.partition}:s3:::${aws_s3_bucket.test.bucket}/*", + ] + condition { + test = "StringEquals" + variable = "aws:PrincipalAccount" + values = [ + data.aws_caller_identity.current.account_id, + ] + } + } +} + +resource "aws_iam_policy" "test_s3" { + name = "%[1]s-s3" + policy = data.aws_iam_policy_document.test_s3.json +} + +resource "aws_iam_role_policy_attachment" "test_s3" { + role = aws_iam_role.test.name + policy_arn = aws_iam_policy.test_s3.arn +} + +resource "aws_bedrockagent_knowledge_base" "test" { + depends_on = [ + aws_iam_role_policy_attachment.test, + aws_iam_role_policy_attachment.test_s3, + aws_opensearchserverless_access_policy.test, + ] + + name = %[1]q + role_arn = aws_iam_role.test.arn + + knowledge_base_configuration { + type = "VECTOR" + vector_knowledge_base_configuration { + embedding_model_arn = "arn:${data.aws_partition.current.partition}:bedrock:${data.aws_region.current.region}::foundation-model/%[2]s" + embedding_model_configuration { + bedrock_embedding_model_configuration { + dimensions = 1024 + embedding_data_type = "FLOAT32" + } + } + supplemental_data_storage_configuration { + storage_location { + type = "S3" + s3_location { + uri = "s3://${aws_s3_bucket.test.bucket}" + } + } + } + } + } + + storage_configuration { + type = "OPENSEARCH_SERVERLESS" + opensearch_serverless_configuration { + collection_arn = data.aws_opensearchserverless_collection.test.arn + vector_index_name = "bedrock-knowledge-base-default-index" + field_mapping { + vector_field = "bedrock-knowledge-base-default-vector" + text_field = "AMAZON_BEDROCK_TEXT_CHUNK" + metadata_field = "AMAZON_BEDROCK_METADATA" + } + } + } +} +`, rName, model)) +} + func testAccKnowledgeBaseConfig_baseOpenSearchServerless(rName, collectionName, model string) string { return fmt.Sprintf(` data "aws_caller_identity" "current" {} @@ -1374,128 +1482,6 @@ resource "aws_bedrockagent_knowledge_base" "test" { `, rName, model)) } -func testAccKnowledgeBaseConfig_OpenSearchServerless_update(rName, collectionName, model string) string { - return acctest.ConfigCompose(testAccKnowledgeBaseConfig_baseOpenSearchServerless(rName, collectionName, model), fmt.Sprintf(` -resource "aws_bedrockagent_knowledge_base" "test" { - depends_on = [ - aws_iam_role_policy_attachment.test, - aws_opensearchserverless_access_policy.test, - ] - - name = "%[1]s-updated" - description = %[1]q - role_arn = aws_iam_role.test.arn - - knowledge_base_configuration { - vector_knowledge_base_configuration { - embedding_model_arn = "arn:${data.aws_partition.current.partition}:bedrock:${data.aws_region.current.region}::foundation-model/%[2]s" - } - type = "VECTOR" - } - - storage_configuration { - type = "OPENSEARCH_SERVERLESS" - opensearch_serverless_configuration { - collection_arn = data.aws_opensearchserverless_collection.test.arn - vector_index_name = "bedrock-knowledge-base-default-index" - field_mapping { - vector_field = "bedrock-knowledge-base-default-vector" - text_field = "AMAZON_BEDROCK_TEXT_CHUNK" - metadata_field = "AMAZON_BEDROCK_METADATA" - } - } - } -} -`, rName, model)) -} - -func testAccKnowledgeBaseConfig_OpenSearchServerless_supplementalDataStorage(rName, collectionName, model string) string { - return acctest.ConfigCompose(testAccKnowledgeBaseConfig_baseOpenSearchServerless(rName, collectionName, model), fmt.Sprintf(` -resource "aws_s3_bucket" "test" { - bucket = %[1]q - force_destroy = true -} - -data "aws_iam_policy_document" "test_s3" { - statement { - effect = "Allow" - actions = [ - "s3:DeleteObject", - "s3:GetObject", - "s3:ListBucket", - "s3:PutObject", - ] - resources = [ - "arn:${data.aws_partition.current.partition}:s3:::${aws_s3_bucket.test.bucket}", - "arn:${data.aws_partition.current.partition}:s3:::${aws_s3_bucket.test.bucket}/*", - ] - condition { - test = "StringEquals" - variable = "aws:PrincipalAccount" - values = [ - data.aws_caller_identity.current.account_id, - ] - } - } -} - -resource "aws_iam_policy" "test_s3" { - name = "%[1]s-s3" - policy = data.aws_iam_policy_document.test_s3.json -} - -resource "aws_iam_role_policy_attachment" "test_s3" { - role = aws_iam_role.test.name - policy_arn = aws_iam_policy.test_s3.arn -} - -resource "aws_bedrockagent_knowledge_base" "test" { - depends_on = [ - aws_iam_role_policy_attachment.test, - aws_iam_role_policy_attachment.test_s3, - aws_opensearchserverless_access_policy.test, - ] - - name = %[1]q - role_arn = aws_iam_role.test.arn - - knowledge_base_configuration { - type = "VECTOR" - vector_knowledge_base_configuration { - embedding_model_arn = "arn:${data.aws_partition.current.partition}:bedrock:${data.aws_region.current.region}::foundation-model/%[2]s" - embedding_model_configuration { - bedrock_embedding_model_configuration { - dimensions = 1024 - embedding_data_type = "FLOAT32" - } - } - supplemental_data_storage_configuration { - storage_location { - type = "S3" - s3_location { - uri = "s3://${aws_s3_bucket.test.bucket}" - } - } - } - } - } - - storage_configuration { - type = "OPENSEARCH_SERVERLESS" - opensearch_serverless_configuration { - collection_arn = data.aws_opensearchserverless_collection.test.arn - vector_index_name = "bedrock-knowledge-base-default-index" - field_mapping { - vector_field = "bedrock-knowledge-base-default-vector" - text_field = "AMAZON_BEDROCK_TEXT_CHUNK" - metadata_field = "AMAZON_BEDROCK_METADATA" - } - } - } -} -`, rName, model)) -} - func testAccKnowledgeBaseConfig_Kendra_basic(rName, kendraIndexArn string) string { return fmt.Sprintf(` data "aws_caller_identity" "current" {} From ddc3704d490899ba0b4cae3a78a365b581fd883a Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Thu, 11 Dec 2025 11:08:40 -0500 Subject: [PATCH 61/65] Tidy up 'testAccKnowledgeBase_OpenSearchServerless_supplementalDataStorage'. --- .../service/bedrockagent/bedrockagent_test.go | 24 +++---- .../bedrockagent/knowledge_base_test.go | 63 ++++++++++++------- 2 files changed, 52 insertions(+), 35 deletions(-) diff --git a/internal/service/bedrockagent/bedrockagent_test.go b/internal/service/bedrockagent/bedrockagent_test.go index 2605e4b9adf5..22ac6c9be7db 100644 --- a/internal/service/bedrockagent/bedrockagent_test.go +++ b/internal/service/bedrockagent/bedrockagent_test.go @@ -14,18 +14,18 @@ func TestAccBedrockAgent_serial(t *testing.T) { testCases := map[string]map[string]func(t *testing.T){ "KnowledgeBase": { - "RDS": testAccKnowledgeBase_RDS_update, - acctest.CtDisappears: testAccKnowledgeBase_disappears, - "tags": testAccKnowledgeBase_tags, - "update": testAccKnowledgeBase_update, - "SupplementalDataStorage": testAccKnowledgeBase_supplementalDataStorage, - "OpenSearchServerlessBasic": testAccKnowledgeBase_OpenSearchServerless_basic, - "KendraBasic": testAccKnowledgeBase_Kendra_basic, - "OpenSearchManagedClusterBasic": testAccKnowledgeBase_OpenSearchManagedCluster_basic, - "S3Vectors": testAccKnowledgeBase_S3Vectors_update, - "StructuredDataStoreRedshiftProvisioned": testAccKnowledgeBase_StructuredDataStore_redshiftProvisioned, - "StructuredDataStoreRedshiftServerless": testAccKnowledgeBase_StructuredDataStore_redshiftServerless, - "NeptuneAnalytics": testAccKnowledgeBase_NeptuneAnalytics_basic, + "RDS": testAccKnowledgeBase_RDS_update, + acctest.CtDisappears: testAccKnowledgeBase_disappears, + "tags": testAccKnowledgeBase_tags, + "update": testAccKnowledgeBase_update, + "OpenSearchServerlessSupplementalDataStorage": testAccKnowledgeBase_OpenSearchServerless_supplementalDataStorage, + "OpenSearchServerlessBasic": testAccKnowledgeBase_OpenSearchServerless_basic, + "KendraBasic": testAccKnowledgeBase_Kendra_basic, + "OpenSearchManagedClusterBasic": testAccKnowledgeBase_OpenSearchManagedCluster_basic, + "S3Vectors": testAccKnowledgeBase_S3Vectors_update, + "StructuredDataStoreRedshiftProvisioned": testAccKnowledgeBase_StructuredDataStore_redshiftProvisioned, + "StructuredDataStoreRedshiftServerless": testAccKnowledgeBase_StructuredDataStore_redshiftServerless, + "NeptuneAnalytics": testAccKnowledgeBase_NeptuneAnalytics_basic, }, "DataSource": { acctest.CtBasic: testAccDataSource_basic, diff --git a/internal/service/bedrockagent/knowledge_base_test.go b/internal/service/bedrockagent/knowledge_base_test.go index 5f012ca7b425..a2e8865f856f 100644 --- a/internal/service/bedrockagent/knowledge_base_test.go +++ b/internal/service/bedrockagent/knowledge_base_test.go @@ -318,7 +318,7 @@ func testAccKnowledgeBase_update(t *testing.T) { }) } -func testAccKnowledgeBase_supplementalDataStorage(t *testing.T) { +func testAccKnowledgeBase_OpenSearchServerless_supplementalDataStorage(t *testing.T) { ctx := acctest.Context(t) collectionName := skipIfOSSCollectionNameEnvVarNotSet(t) var knowledgebase awstypes.KnowledgeBase @@ -327,9 +327,7 @@ func testAccKnowledgeBase_supplementalDataStorage(t *testing.T) { foundationModel := "amazon.titan-embed-text-v2:0" resource.Test(t, resource.TestCase{ - PreCheck: func() { - acctest.PreCheck(ctx, t) - }, + PreCheck: func() { acctest.PreCheck(ctx, t) }, ErrorCheck: acctest.ErrorCheck(t, names.BedrockAgentServiceID), ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, CheckDestroy: testAccCheckKnowledgeBaseDestroy(ctx), @@ -338,28 +336,47 @@ func testAccKnowledgeBase_supplementalDataStorage(t *testing.T) { Config: testAccKnowledgeBaseConfig_OpenSearchServerless_supplementalDataStorage(rName, collectionName, foundationModel), Check: resource.ComposeTestCheckFunc( testAccCheckKnowledgeBaseExists(ctx, resourceName, &knowledgebase), - resource.TestCheckResourceAttr(resourceName, "knowledge_base_configuration.#", "1"), - resource.TestCheckResourceAttr(resourceName, "knowledge_base_configuration.0.vector_knowledge_base_configuration.#", "1"), - resource.TestCheckResourceAttr(resourceName, "knowledge_base_configuration.0.type", "VECTOR"), - resource.TestCheckResourceAttr(resourceName, "knowledge_base_configuration.0.vector_knowledge_base_configuration.0.embedding_model_configuration.0.bedrock_embedding_model_configuration.0.dimensions", "1024"), - resource.TestCheckResourceAttr(resourceName, "knowledge_base_configuration.0.vector_knowledge_base_configuration.0.embedding_model_configuration.0.bedrock_embedding_model_configuration.0.embedding_data_type", "FLOAT32"), - resource.TestCheckResourceAttr(resourceName, "knowledge_base_configuration.0.vector_knowledge_base_configuration.0.supplemental_data_storage_configuration.0.storage_location.0.type", "S3"), - resource.TestCheckResourceAttr(resourceName, "knowledge_base_configuration.0.vector_knowledge_base_configuration.0.supplemental_data_storage_configuration.0.storage_location.0.s3_location.0.uri", fmt.Sprintf("s3://%s", rName)), - resource.TestCheckResourceAttr(resourceName, "storage_configuration.#", "1"), - resource.TestCheckResourceAttr(resourceName, "storage_configuration.0.type", "OPENSEARCH_SERVERLESS"), - resource.TestCheckResourceAttr(resourceName, "storage_configuration.0.opensearch_serverless_configuration.#", "1"), - resource.TestCheckResourceAttr(resourceName, "storage_configuration.0.opensearch_serverless_configuration.0.vector_index_name", "bedrock-knowledge-base-default-index"), - resource.TestCheckResourceAttr(resourceName, "storage_configuration.0.opensearch_serverless_configuration.0.field_mapping.#", "1"), - resource.TestCheckResourceAttr(resourceName, "storage_configuration.0.opensearch_serverless_configuration.0.field_mapping.0.vector_field", "bedrock-knowledge-base-default-vector"), - resource.TestCheckResourceAttr(resourceName, "storage_configuration.0.opensearch_serverless_configuration.0.field_mapping.0.text_field", "AMAZON_BEDROCK_TEXT_CHUNK"), - resource.TestCheckResourceAttr(resourceName, "storage_configuration.0.opensearch_serverless_configuration.0.field_mapping.0.metadata_field", "AMAZON_BEDROCK_METADATA"), ), + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + }, + }, + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrDescription), knownvalue.Null()), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("knowledge_base_configuration"), knownvalue.ListExact([]knownvalue.Check{ + knownvalue.MapExact(map[string]knownvalue.Check{ + "kendra_knowledge_base_configuration": knownvalue.ListSizeExact(0), + "sql_knowledge_base_configuration": knownvalue.ListSizeExact(0), + names.AttrType: tfknownvalue.StringExact(awstypes.KnowledgeBaseTypeVector), + "vector_knowledge_base_configuration": knownvalue.ListExact([]knownvalue.Check{ + knownvalue.ObjectPartial(map[string]knownvalue.Check{ + "supplemental_data_storage_configuration": knownvalue.ListExact([]knownvalue.Check{ + knownvalue.ObjectExact(map[string]knownvalue.Check{ + "storage_location": knownvalue.ListExact([]knownvalue.Check{ + knownvalue.ObjectExact(map[string]knownvalue.Check{ + "s3_location": knownvalue.ListExact([]knownvalue.Check{ + knownvalue.ObjectExact(map[string]knownvalue.Check{ + "s3_location": knownvalue.ListSizeExact(1), + names.AttrType: tfknownvalue.StringExact(awstypes.SupplementalDataStorageLocationTypeS3), + }), + }), + }), + }), + }), + }), + }), + }), + }), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrName), knownvalue.StringExact(rName)), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrTags), knownvalue.Null()), + }, }, { - ResourceName: resourceName, - ImportState: true, - ImportStateVerify: true, - ImportStateVerifyIgnore: []string{}, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, }, }, }) From 9f82d79ec64a0d08f38db00eb0ad95fe71a32db7 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Thu, 11 Dec 2025 13:28:52 -0500 Subject: [PATCH 62/65] Replace 'testAccKnowledgeBase_OpenSearchServerless_supplementalDataStorage' with 'testAccKnowledgeBase_RDS_supplementalDataStorage'. --- .../service/bedrockagent/bedrockagent_test.go | 24 +- .../bedrockagent/knowledge_base_test.go | 482 +++++++----------- 2 files changed, 195 insertions(+), 311 deletions(-) diff --git a/internal/service/bedrockagent/bedrockagent_test.go b/internal/service/bedrockagent/bedrockagent_test.go index 22ac6c9be7db..2db57f4420bf 100644 --- a/internal/service/bedrockagent/bedrockagent_test.go +++ b/internal/service/bedrockagent/bedrockagent_test.go @@ -14,18 +14,18 @@ func TestAccBedrockAgent_serial(t *testing.T) { testCases := map[string]map[string]func(t *testing.T){ "KnowledgeBase": { - "RDS": testAccKnowledgeBase_RDS_update, - acctest.CtDisappears: testAccKnowledgeBase_disappears, - "tags": testAccKnowledgeBase_tags, - "update": testAccKnowledgeBase_update, - "OpenSearchServerlessSupplementalDataStorage": testAccKnowledgeBase_OpenSearchServerless_supplementalDataStorage, - "OpenSearchServerlessBasic": testAccKnowledgeBase_OpenSearchServerless_basic, - "KendraBasic": testAccKnowledgeBase_Kendra_basic, - "OpenSearchManagedClusterBasic": testAccKnowledgeBase_OpenSearchManagedCluster_basic, - "S3Vectors": testAccKnowledgeBase_S3Vectors_update, - "StructuredDataStoreRedshiftProvisioned": testAccKnowledgeBase_StructuredDataStore_redshiftProvisioned, - "StructuredDataStoreRedshiftServerless": testAccKnowledgeBase_StructuredDataStore_redshiftServerless, - "NeptuneAnalytics": testAccKnowledgeBase_NeptuneAnalytics_basic, + acctest.CtDisappears: testAccKnowledgeBase_disappears, + "tags": testAccKnowledgeBase_tags, + "update": testAccKnowledgeBase_update, + "OpenSearchServerlessBasic": testAccKnowledgeBase_OpenSearchServerless_basic, + "Kendra": testAccKnowledgeBase_Kendra_basic, + "NeptuneAnalytics": testAccKnowledgeBase_NeptuneAnalytics_basic, + "OpenSearchManagedClusterBasic": testAccKnowledgeBase_OpenSearchManagedCluster_basic, + "S3Vectors": testAccKnowledgeBase_S3Vectors_update, + "StructuredDataStoreRedshiftProvisioned": testAccKnowledgeBase_StructuredDataStore_redshiftProvisioned, + "StructuredDataStoreRedshiftServerless": testAccKnowledgeBase_StructuredDataStore_redshiftServerless, + "RDS": testAccKnowledgeBase_RDS_basic, + "RDSSupplementalDataStorage": testAccKnowledgeBase_RDS_supplementalDataStorage, }, "DataSource": { acctest.CtBasic: testAccDataSource_basic, diff --git a/internal/service/bedrockagent/knowledge_base_test.go b/internal/service/bedrockagent/knowledge_base_test.go index a2e8865f856f..9efa49b0a87f 100644 --- a/internal/service/bedrockagent/knowledge_base_test.go +++ b/internal/service/bedrockagent/knowledge_base_test.go @@ -7,7 +7,6 @@ import ( "context" "fmt" "os" - "strconv" "testing" awstypes "github.com/aws/aws-sdk-go-v2/service/bedrockagent/types" @@ -133,7 +132,7 @@ func testAccKnowledgeBase_tags(t *testing.T) { // Prerequisites: // * psql run via null_resource/provisioner "local-exec" // * jq for parsing output from aws cli to retrieve postgres password -func testAccKnowledgeBase_RDS_update(t *testing.T) { +func testAccKnowledgeBase_RDS_basic(t *testing.T) { acctest.SkipIfExeNotOnPath(t, "psql") acctest.SkipIfExeNotOnPath(t, "jq") acctest.SkipIfExeNotOnPath(t, "aws") @@ -159,64 +158,44 @@ func testAccKnowledgeBase_RDS_update(t *testing.T) { CheckDestroy: testAccCheckKnowledgeBaseDestroy(ctx), Steps: []resource.TestStep{ { - Config: testAccKnowledgeBaseConfig_basicRDS(rName, foundationModel, ""), + Config: testAccKnowledgeBaseConfig_basicRDS(rName, foundationModel), + Check: resource.ComposeTestCheckFunc( + testAccCheckKnowledgeBaseExists(ctx, resourceName, &knowledgebase), + ), ConfigPlanChecks: resource.ConfigPlanChecks{ PreApply: []plancheck.PlanCheck{ plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), }, }, - Check: resource.ComposeTestCheckFunc( - testAccCheckKnowledgeBaseExists(ctx, resourceName, &knowledgebase), - resource.TestCheckNoResourceAttr(resourceName, names.AttrDescription), - resource.TestCheckResourceAttr(resourceName, "knowledge_base_configuration.#", "1"), - resource.TestCheckResourceAttr(resourceName, "knowledge_base_configuration.0.vector_knowledge_base_configuration.#", "1"), - resource.TestCheckResourceAttr(resourceName, "knowledge_base_configuration.0.type", "VECTOR"), - resource.TestCheckResourceAttr(resourceName, names.AttrName, rName), - resource.TestCheckResourceAttrPair(resourceName, names.AttrRoleARN, "aws_iam_role.test", names.AttrARN), - resource.TestCheckResourceAttr(resourceName, "storage_configuration.#", "1"), - resource.TestCheckResourceAttr(resourceName, "storage_configuration.0.type", "RDS"), - resource.TestCheckResourceAttr(resourceName, "storage_configuration.0.rds_configuration.#", "1"), - resource.TestCheckResourceAttr(resourceName, "storage_configuration.0.rds_configuration.0.table_name", "bedrock_integration.bedrock_kb"), - resource.TestCheckResourceAttr(resourceName, "storage_configuration.0.rds_configuration.0.field_mapping.#", "1"), - resource.TestCheckResourceAttr(resourceName, "storage_configuration.0.rds_configuration.0.field_mapping.0.vector_field", "embedding"), - resource.TestCheckResourceAttr(resourceName, "storage_configuration.0.rds_configuration.0.field_mapping.0.text_field", "chunks"), - resource.TestCheckResourceAttr(resourceName, "storage_configuration.0.rds_configuration.0.field_mapping.0.metadata_field", "metadata"), - resource.TestCheckResourceAttr(resourceName, "storage_configuration.0.rds_configuration.0.field_mapping.0.primary_key_field", names.AttrID), - resource.TestCheckResourceAttr(resourceName, "storage_configuration.0.rds_configuration.0.field_mapping.0.custom_metadata_field", "custom_metadata"), - ), + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("knowledge_base_configuration"), knownvalue.ListExact([]knownvalue.Check{ + knownvalue.MapExact(map[string]knownvalue.Check{ + "kendra_knowledge_base_configuration": knownvalue.ListSizeExact(0), + "sql_knowledge_base_configuration": knownvalue.ListSizeExact(0), + names.AttrType: tfknownvalue.StringExact(awstypes.KnowledgeBaseTypeVector), + "vector_knowledge_base_configuration": knownvalue.ListSizeExact(1), + }), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("storage_configuration"), knownvalue.ListExact([]knownvalue.Check{ + knownvalue.MapExact(map[string]knownvalue.Check{ + "mongo_db_atlas_configuration": knownvalue.ListSizeExact(0), + "neptune_analytics_configuration": knownvalue.ListSizeExact(0), + "opensearch_managed_cluster_configuration": knownvalue.ListSizeExact(0), + "opensearch_serverless_configuration": knownvalue.ListSizeExact(0), + names.AttrType: tfknownvalue.StringExact(awstypes.KnowledgeBaseStorageTypeRds), + "pinecone_configuration": knownvalue.ListSizeExact(0), + "rds_configuration": knownvalue.ListSizeExact(1), + "redis_enterprise_cloud_configuration": knownvalue.ListSizeExact(0), + "s3_vectors_configuration": knownvalue.ListSizeExact(0), + }), + })), + }, }, { ResourceName: resourceName, ImportState: true, ImportStateVerify: true, }, - { - Config: testAccKnowledgeBaseConfig_updateRDS(rName, foundationModel, "test description"), - ConfigPlanChecks: resource.ConfigPlanChecks{ - PreApply: []plancheck.PlanCheck{ - plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionUpdate), - }, - }, - Check: resource.ComposeTestCheckFunc( - testAccCheckKnowledgeBaseExists(ctx, resourceName, &knowledgebase), - resource.TestCheckResourceAttr(resourceName, names.AttrDescription, "test description"), - resource.TestCheckResourceAttr(resourceName, "knowledge_base_configuration.#", "1"), - resource.TestCheckResourceAttr(resourceName, "knowledge_base_configuration.0.vector_knowledge_base_configuration.#", "1"), - resource.TestCheckResourceAttr(resourceName, "knowledge_base_configuration.0.type", "VECTOR"), - resource.TestCheckResourceAttr(resourceName, names.AttrName, rName+"-update"), - resource.TestCheckResourceAttrPair(resourceName, names.AttrRoleARN, "aws_iam_role.test_update", names.AttrARN), - resource.TestCheckResourceAttr(resourceName, "storage_configuration.#", "1"), - resource.TestCheckResourceAttr(resourceName, "storage_configuration.0.type", "RDS"), - resource.TestCheckResourceAttr(resourceName, "storage_configuration.0.rds_configuration.#", "1"), - resource.TestCheckResourceAttr(resourceName, "storage_configuration.0.rds_configuration.0.table_name", "bedrock_integration.bedrock_kb"), - resource.TestCheckResourceAttr(resourceName, "storage_configuration.0.rds_configuration.0.field_mapping.#", "1"), - resource.TestCheckResourceAttr(resourceName, "storage_configuration.0.rds_configuration.0.field_mapping.0.vector_field", "embedding"), - resource.TestCheckResourceAttr(resourceName, "storage_configuration.0.rds_configuration.0.field_mapping.0.text_field", "chunks"), - resource.TestCheckResourceAttr(resourceName, "storage_configuration.0.rds_configuration.0.field_mapping.0.metadata_field", "metadata"), - resource.TestCheckResourceAttr(resourceName, "storage_configuration.0.rds_configuration.0.field_mapping.0.primary_key_field", names.AttrID), - resource.TestCheckResourceAttr(resourceName, "storage_configuration.0.rds_configuration.0.field_mapping.0.custom_metadata_field", "custom_metadata"), - ), - }, }, }) } @@ -318,22 +297,31 @@ func testAccKnowledgeBase_update(t *testing.T) { }) } -func testAccKnowledgeBase_OpenSearchServerless_supplementalDataStorage(t *testing.T) { +func testAccKnowledgeBase_RDS_supplementalDataStorage(t *testing.T) { + acctest.SkipIfExeNotOnPath(t, "psql") + acctest.SkipIfExeNotOnPath(t, "jq") + acctest.SkipIfExeNotOnPath(t, "aws") + ctx := acctest.Context(t) - collectionName := skipIfOSSCollectionNameEnvVarNotSet(t) var knowledgebase awstypes.KnowledgeBase rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) resourceName := "aws_bedrockagent_knowledge_base.test" - foundationModel := "amazon.titan-embed-text-v2:0" + foundationModel := "amazon.titan-embed-text-v1" resource.Test(t, resource.TestCase{ PreCheck: func() { acctest.PreCheck(ctx, t) }, ErrorCheck: acctest.ErrorCheck(t, names.BedrockAgentServiceID), ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, - CheckDestroy: testAccCheckKnowledgeBaseDestroy(ctx), + ExternalProviders: map[string]resource.ExternalProvider{ + "null": { + Source: "hashicorp/null", + VersionConstraint: "3.2.2", + }, + }, + CheckDestroy: testAccCheckKnowledgeBaseDestroy(ctx), Steps: []resource.TestStep{ { - Config: testAccKnowledgeBaseConfig_OpenSearchServerless_supplementalDataStorage(rName, collectionName, foundationModel), + Config: testAccKnowledgeBaseConfig_RDS_supplementalDataStorage(rName, foundationModel), Check: resource.ComposeTestCheckFunc( testAccCheckKnowledgeBaseExists(ctx, resourceName, &knowledgebase), ), @@ -355,12 +343,8 @@ func testAccKnowledgeBase_OpenSearchServerless_supplementalDataStorage(t *testin knownvalue.ObjectExact(map[string]knownvalue.Check{ "storage_location": knownvalue.ListExact([]knownvalue.Check{ knownvalue.ObjectExact(map[string]knownvalue.Check{ - "s3_location": knownvalue.ListExact([]knownvalue.Check{ - knownvalue.ObjectExact(map[string]knownvalue.Check{ - "s3_location": knownvalue.ListSizeExact(1), - names.AttrType: tfknownvalue.StringExact(awstypes.SupplementalDataStorageLocationTypeS3), - }), - }), + "s3_location": knownvalue.ListSizeExact(1), + names.AttrType: tfknownvalue.StringExact(awstypes.SupplementalDataStorageLocationTypeS3), }), }), }), @@ -817,6 +801,121 @@ func skipIfOSSCollectionNameEnvVarNotSet(t *testing.T) string { return v } +func testAccKnowledgeBaseConfig_tags1(rName, model, tag1Key, tag1Value string) string { + return acctest.ConfigCompose(acctest.ConfigBedrockAgentKnowledgeBaseS3VectorsBase(rName), fmt.Sprintf(` +resource "aws_bedrockagent_knowledge_base" "test" { + depends_on = [ + aws_iam_role_policy.test, + ] + + name = %[1]q + role_arn = aws_iam_role.test.arn + + knowledge_base_configuration { + type = "VECTOR" + + vector_knowledge_base_configuration { + embedding_model_arn = "arn:${data.aws_partition.current.partition}:bedrock:${data.aws_region.current.region}::foundation-model/%[2]s" + embedding_model_configuration { + bedrock_embedding_model_configuration { + dimensions = 256 + embedding_data_type = "FLOAT32" + } + } + } + } + + storage_configuration { + type = "S3_VECTORS" + + s3_vectors_configuration { + index_arn = aws_s3vectors_index.test.index_arn + } + } + + tags = { + %[3]q = %[4]q + } +} +`, rName, model, tag1Key, tag1Value)) +} + +func testAccKnowledgeBaseConfig_tags2(rName, model, tag1Key, tag1Value, tag2Key, tag2Value string) string { + return acctest.ConfigCompose(acctest.ConfigBedrockAgentKnowledgeBaseS3VectorsBase(rName), fmt.Sprintf(` +resource "aws_bedrockagent_knowledge_base" "test" { + depends_on = [ + aws_iam_role_policy.test, + ] + + name = %[1]q + role_arn = aws_iam_role.test.arn + + knowledge_base_configuration { + type = "VECTOR" + + vector_knowledge_base_configuration { + embedding_model_arn = "arn:${data.aws_partition.current.partition}:bedrock:${data.aws_region.current.region}::foundation-model/%[2]s" + embedding_model_configuration { + bedrock_embedding_model_configuration { + dimensions = 256 + embedding_data_type = "FLOAT32" + } + } + } + } + + storage_configuration { + type = "S3_VECTORS" + + s3_vectors_configuration { + index_arn = aws_s3vectors_index.test.index_arn + } + } + + tags = { + %[3]q = %[4]q + %[5]q = %[6]q + } +} +`, rName, model, tag1Key, tag1Value, tag2Key, tag2Value)) +} + +func testAccKnowledgeBaseConfig_description(rName, model, description string) string { + return acctest.ConfigCompose(acctest.ConfigBedrockAgentKnowledgeBaseS3VectorsBase(rName), fmt.Sprintf(` +resource "aws_bedrockagent_knowledge_base" "test" { + depends_on = [ + aws_iam_role_policy.test, + ] + + name = %[1]q + role_arn = aws_iam_role.test.arn + description = %[3]q + + knowledge_base_configuration { + type = "VECTOR" + + vector_knowledge_base_configuration { + embedding_model_arn = "arn:${data.aws_partition.current.partition}:bedrock:${data.aws_region.current.region}::foundation-model/%[2]s" + embedding_model_configuration { + bedrock_embedding_model_configuration { + dimensions = 256 + embedding_data_type = "FLOAT32" + } + } + } + } + + storage_configuration { + type = "S3_VECTORS" + + s3_vectors_configuration { + index_arn = aws_s3vectors_index.test.index_arn + } + } +} +`, rName, model, description)) +} + func testAccKnowledgeBaseConfig_baseRDS(rName, model string) string { return acctest.ConfigCompose(acctest.ConfigVPCWithSubnetsEnableDNSHostnames(rName, 2), fmt.Sprintf(` data "aws_partition" "current" {} @@ -988,20 +1087,12 @@ resource "null_resource" "db_setup" { `, rName, model)) } -func testAccKnowledgeBaseConfig_basicRDS(rName, model, description string) string { - if description == "" { - description = "null" - } else { - description = strconv.Quote(description) - } - +func testAccKnowledgeBaseConfig_basicRDS(rName, model string) string { return acctest.ConfigCompose(testAccKnowledgeBaseConfig_baseRDS(rName, model), fmt.Sprintf(` resource "aws_bedrockagent_knowledge_base" "test" { name = %[1]q role_arn = aws_iam_role.test.arn - description = %[3]s - knowledge_base_configuration { vector_knowledge_base_configuration { embedding_model_arn = "arn:${data.aws_partition.current.partition}:bedrock:${data.aws_region.current.region}::foundation-model/%[2]s" @@ -1028,220 +1119,13 @@ resource "aws_bedrockagent_knowledge_base" "test" { depends_on = [aws_iam_role_policy.test, null_resource.db_setup] } -`, rName, model, description)) +`, rName, model)) } -func testAccKnowledgeBaseConfig_updateRDS(rName, model, description string) string { +func testAccKnowledgeBaseConfig_RDS_supplementalDataStorage(rName, model string) string { return acctest.ConfigCompose(testAccKnowledgeBaseConfig_baseRDS(rName, model), fmt.Sprintf(` -resource "aws_iam_role" "test_update" { - name = "%[1]s-update" - path = "/service-role/" - assume_role_policy = < Date: Thu, 11 Dec 2025 13:46:19 -0500 Subject: [PATCH 63/65] r/aws_bedrockagent_agent_knowledge_base_association.test: Simplify acceptance tests by using S3 Vectors. --- .../agent_knowledge_base_association_test.go | 77 +++---------------- 1 file changed, 10 insertions(+), 67 deletions(-) diff --git a/internal/service/bedrockagent/agent_knowledge_base_association_test.go b/internal/service/bedrockagent/agent_knowledge_base_association_test.go index 7aa1b457fa34..51b329c6005c 100644 --- a/internal/service/bedrockagent/agent_knowledge_base_association_test.go +++ b/internal/service/bedrockagent/agent_knowledge_base_association_test.go @@ -19,38 +19,19 @@ import ( "github.com/hashicorp/terraform-provider-aws/names" ) -// Prerequisites: -// * psql run via null_resource/provisioner "local-exec" -// * jq for parsing output from aws cli to retrieve postgres password func TestAccBedrockAgentAgentKnowledgeBaseAssociation_basic(t *testing.T) { - acctest.SkipIfExeNotOnPath(t, "psql") - acctest.SkipIfExeNotOnPath(t, "jq") - acctest.SkipIfExeNotOnPath(t, "aws") - ctx := acctest.Context(t) - if testing.Short() { - t.Skip("skipping long-running test in short mode") - } - var agentknowledgebaseassociation types.AgentKnowledgeBase rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) resourceName := "aws_bedrockagent_agent_knowledge_base_association.test" agentModel := "anthropic.claude-v2" - foundationModel := "amazon.titan-embed-text-v1" + foundationModel := "amazon.titan-embed-text-v2:0" resource.ParallelTest(t, resource.TestCase{ - PreCheck: func() { - acctest.PreCheck(ctx, t) - }, + PreCheck: func() { acctest.PreCheck(ctx, t) }, ErrorCheck: acctest.ErrorCheck(t, names.BedrockAgentServiceID), ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, - ExternalProviders: map[string]resource.ExternalProvider{ - "null": { - Source: "hashicorp/null", - VersionConstraint: "3.2.2", - }, - }, - CheckDestroy: testAccCheckAgentKnowledgeBaseAssociationDestroy(ctx), + CheckDestroy: testAccCheckAgentKnowledgeBaseAssociationDestroy(ctx), Steps: []resource.TestStep{ { Config: testAccAgentKnowledgeBaseAssociationConfig_basic(rName, agentModel, foundationModel, "test desc", "ENABLED"), @@ -69,38 +50,19 @@ func TestAccBedrockAgentAgentKnowledgeBaseAssociation_basic(t *testing.T) { }) } -// Prerequisites: -// * psql run via null_resource/provisioner "local-exec" -// * jq for parsing output from aws cli to retrieve postgres password func TestAccBedrockAgentAgentKnowledgeBaseAssociation_update(t *testing.T) { - acctest.SkipIfExeNotOnPath(t, "psql") - acctest.SkipIfExeNotOnPath(t, "jq") - acctest.SkipIfExeNotOnPath(t, "aws") - ctx := acctest.Context(t) - if testing.Short() { - t.Skip("skipping long-running test in short mode") - } - var agentknowledgebaseassociation types.AgentKnowledgeBase rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) resourceName := "aws_bedrockagent_agent_knowledge_base_association.test" agentModel := "anthropic.claude-v2" - foundationModel := "amazon.titan-embed-text-v1" + foundationModel := "amazon.titan-embed-text-v2:0" resource.ParallelTest(t, resource.TestCase{ - PreCheck: func() { - acctest.PreCheck(ctx, t) - }, + PreCheck: func() { acctest.PreCheck(ctx, t) }, ErrorCheck: acctest.ErrorCheck(t, names.BedrockAgentServiceID), ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, - ExternalProviders: map[string]resource.ExternalProvider{ - "null": { - Source: "hashicorp/null", - VersionConstraint: "3.2.2", - }, - }, - CheckDestroy: testAccCheckAgentKnowledgeBaseAssociationDestroy(ctx), + CheckDestroy: testAccCheckAgentKnowledgeBaseAssociationDestroy(ctx), Steps: []resource.TestStep{ { Config: testAccAgentKnowledgeBaseAssociationConfig_basic(rName, agentModel, foundationModel, "test desc", "ENABLED"), @@ -127,38 +89,19 @@ func TestAccBedrockAgentAgentKnowledgeBaseAssociation_update(t *testing.T) { }) } -// Prerequisites: -// * psql run via null_resource/provisioner "local-exec" -// * jq for parsing output from aws cli to retrieve postgres password func TestAccBedrockAgentAgentKnowledgeBaseAssociation_disappears(t *testing.T) { - acctest.SkipIfExeNotOnPath(t, "psql") - acctest.SkipIfExeNotOnPath(t, "jq") - acctest.SkipIfExeNotOnPath(t, "aws") - ctx := acctest.Context(t) - if testing.Short() { - t.Skip("skipping long-running test in short mode") - } - var agentknowledgebaseassociation types.AgentKnowledgeBase rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) resourceName := "aws_bedrockagent_agent_knowledge_base_association.test" agentModel := "anthropic.claude-v2" - foundationModel := "amazon.titan-embed-text-v1" + foundationModel := "amazon.titan-embed-text-v2:0" resource.ParallelTest(t, resource.TestCase{ - PreCheck: func() { - acctest.PreCheck(ctx, t) - }, + PreCheck: func() { acctest.PreCheck(ctx, t) }, ErrorCheck: acctest.ErrorCheck(t, names.BedrockAgentServiceID), ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, - ExternalProviders: map[string]resource.ExternalProvider{ - "null": { - Source: "hashicorp/null", - VersionConstraint: "3.2.2", - }, - }, - CheckDestroy: testAccCheckAgentKnowledgeBaseAssociationDestroy(ctx), + CheckDestroy: testAccCheckAgentKnowledgeBaseAssociationDestroy(ctx), Steps: []resource.TestStep{ { Config: testAccAgentKnowledgeBaseAssociationConfig_basic(rName, agentModel, foundationModel, "test desc", "ENABLED"), @@ -222,7 +165,7 @@ func testAccCheckAgentKnowledgeBaseAssociationExists(ctx context.Context, n stri func testAccAgentKnowledgeBaseAssociationConfig_basic(rName, agentModel, embeddingModel, description, state string) string { return acctest.ConfigCompose( testAccAgentConfig_basic(rName, agentModel, description), - testAccKnowledgeBaseConfig_basicRDS(rName, embeddingModel, ""), + testAccKnowledgeBaseConfig_S3VectorsByIndexARN(rName, embeddingModel), fmt.Sprintf(` resource "aws_bedrockagent_agent_knowledge_base_association" "test" { agent_id = aws_bedrockagent_agent.test.id From ebeffc707c246d50dfd828a65a9646edbd1f68e7 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Thu, 11 Dec 2025 13:55:55 -0500 Subject: [PATCH 64/65] r/aws_bedrockagent_data_source: Simplify acceptance tests by using S3 Vectors. --- .../service/bedrockagent/data_source_test.go | 196 +++--------------- 1 file changed, 25 insertions(+), 171 deletions(-) diff --git a/internal/service/bedrockagent/data_source_test.go b/internal/service/bedrockagent/data_source_test.go index c9a64a0e0754..2d8327cee649 100644 --- a/internal/service/bedrockagent/data_source_test.go +++ b/internal/service/bedrockagent/data_source_test.go @@ -19,37 +19,18 @@ import ( "github.com/hashicorp/terraform-provider-aws/names" ) -// Prerequisites: -// * psql run via null_resource/provisioner "local-exec" -// * jq for parsing output from aws cli to retrieve postgres password func testAccDataSource_basic(t *testing.T) { - acctest.SkipIfExeNotOnPath(t, "psql") - acctest.SkipIfExeNotOnPath(t, "jq") - acctest.SkipIfExeNotOnPath(t, "aws") - ctx := acctest.Context(t) - if testing.Short() { - t.Skip("skipping long-running test in short mode") - } - var dataSource types.DataSource rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) resourceName := "aws_bedrockagent_data_source.test" - foundationModel := "amazon.titan-embed-text-v1" + foundationModel := "amazon.titan-embed-text-v2:0" resource.Test(t, resource.TestCase{ - PreCheck: func() { - acctest.PreCheck(ctx, t) - }, + PreCheck: func() { acctest.PreCheck(ctx, t) }, ErrorCheck: acctest.ErrorCheck(t, names.BedrockAgentServiceID), ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, - ExternalProviders: map[string]resource.ExternalProvider{ - "null": { - Source: "hashicorp/null", - VersionConstraint: "3.2.2", - }, - }, - CheckDestroy: testAccCheckDataSourceDestroy(ctx), + CheckDestroy: testAccCheckDataSourceDestroy(ctx), Steps: []resource.TestStep{ { Config: testAccDataSourceConfig_basic(rName, foundationModel), @@ -66,37 +47,18 @@ func testAccDataSource_basic(t *testing.T) { }) } -// Prerequisites: -// * psql run via null_resource/provisioner "local-exec" -// * jq for parsing output from aws cli to retrieve postgres password func testAccDataSource_full(t *testing.T) { - acctest.SkipIfExeNotOnPath(t, "psql") - acctest.SkipIfExeNotOnPath(t, "jq") - acctest.SkipIfExeNotOnPath(t, "aws") - ctx := acctest.Context(t) - if testing.Short() { - t.Skip("skipping long-running test in short mode") - } - var dataSource types.DataSource rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) resourceName := "aws_bedrockagent_data_source.test" - foundationModel := "amazon.titan-embed-text-v1" + foundationModel := "amazon.titan-embed-text-v2:0" resource.Test(t, resource.TestCase{ - PreCheck: func() { - acctest.PreCheck(ctx, t) - }, + PreCheck: func() { acctest.PreCheck(ctx, t) }, ErrorCheck: acctest.ErrorCheck(t, names.BedrockAgentServiceID), ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, - ExternalProviders: map[string]resource.ExternalProvider{ - "null": { - Source: "hashicorp/null", - VersionConstraint: "3.2.2", - }, - }, - CheckDestroy: testAccCheckDataSourceDestroy(ctx), + CheckDestroy: testAccCheckDataSourceDestroy(ctx), Steps: []resource.TestStep{ { Config: testAccDataSourceConfig_full(rName, foundationModel), @@ -132,33 +94,17 @@ func testAccDataSource_full(t *testing.T) { } func testAccDataSource_fullSemantic(t *testing.T) { - acctest.SkipIfExeNotOnPath(t, "psql") - acctest.SkipIfExeNotOnPath(t, "jq") - acctest.SkipIfExeNotOnPath(t, "aws") - ctx := acctest.Context(t) - if testing.Short() { - t.Skip("skipping long-running test in short mode") - } - var dataSource types.DataSource rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) resourceName := "aws_bedrockagent_data_source.test" - foundationModel := "amazon.titan-embed-text-v1" + foundationModel := "amazon.titan-embed-text-v2:0" resource.Test(t, resource.TestCase{ - PreCheck: func() { - acctest.PreCheck(ctx, t) - }, + PreCheck: func() { acctest.PreCheck(ctx, t) }, ErrorCheck: acctest.ErrorCheck(t, names.BedrockAgentServiceID), ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, - ExternalProviders: map[string]resource.ExternalProvider{ - "null": { - Source: "hashicorp/null", - VersionConstraint: "3.2.2", - }, - }, - CheckDestroy: testAccCheckDataSourceDestroy(ctx), + CheckDestroy: testAccCheckDataSourceDestroy(ctx), Steps: []resource.TestStep{ { Config: testAccDataSourceConfig_fullSemantic(rName, foundationModel), @@ -195,33 +141,17 @@ func testAccDataSource_fullSemantic(t *testing.T) { } func testAccDataSource_fullHierarchical(t *testing.T) { - acctest.SkipIfExeNotOnPath(t, "psql") - acctest.SkipIfExeNotOnPath(t, "jq") - acctest.SkipIfExeNotOnPath(t, "aws") - ctx := acctest.Context(t) - if testing.Short() { - t.Skip("skipping long-running test in short mode") - } - var dataSource types.DataSource rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) resourceName := "aws_bedrockagent_data_source.test" - foundationModel := "amazon.titan-embed-text-v1" + foundationModel := "amazon.titan-embed-text-v2:0" resource.Test(t, resource.TestCase{ - PreCheck: func() { - acctest.PreCheck(ctx, t) - }, + PreCheck: func() { acctest.PreCheck(ctx, t) }, ErrorCheck: acctest.ErrorCheck(t, names.BedrockAgentServiceID), ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, - ExternalProviders: map[string]resource.ExternalProvider{ - "null": { - Source: "hashicorp/null", - VersionConstraint: "3.2.2", - }, - }, - CheckDestroy: testAccCheckDataSourceDestroy(ctx), + CheckDestroy: testAccCheckDataSourceDestroy(ctx), Steps: []resource.TestStep{ { Config: testAccDataSourceConfig_fullHierarchical(rName, foundationModel), @@ -258,37 +188,18 @@ func testAccDataSource_fullHierarchical(t *testing.T) { }) } -// Prerequisites: -// * psql run via null_resource/provisioner "local-exec" -// * jq for parsing output from aws cli to retrieve postgres password func testAccDataSource_fullCustomTranformation(t *testing.T) { - acctest.SkipIfExeNotOnPath(t, "psql") - acctest.SkipIfExeNotOnPath(t, "jq") - acctest.SkipIfExeNotOnPath(t, "aws") - ctx := acctest.Context(t) - if testing.Short() { - t.Skip("skipping long-running test in short mode") - } - var dataSource types.DataSource rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) resourceName := "aws_bedrockagent_data_source.test" - foundationModel := "amazon.titan-embed-text-v1" + foundationModel := "amazon.titan-embed-text-v2:0" resource.Test(t, resource.TestCase{ - PreCheck: func() { - acctest.PreCheck(ctx, t) - }, + PreCheck: func() { acctest.PreCheck(ctx, t) }, ErrorCheck: acctest.ErrorCheck(t, names.BedrockAgentServiceID), ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, - ExternalProviders: map[string]resource.ExternalProvider{ - "null": { - Source: "hashicorp/null", - VersionConstraint: "3.2.2", - }, - }, - CheckDestroy: testAccCheckDataSourceDestroy(ctx), + CheckDestroy: testAccCheckDataSourceDestroy(ctx), Steps: []resource.TestStep{ { Config: testAccDataSourceConfig_fullCustomTransformation(rName, foundationModel), @@ -323,38 +234,19 @@ func testAccDataSource_fullCustomTranformation(t *testing.T) { }) } -// Prerequisites: -// * psql run via null_resource/provisioner "local-exec" -// * jq for parsing output from aws cli to retrieve postgres password func testAccDataSource_parsing(t *testing.T) { - acctest.SkipIfExeNotOnPath(t, "psql") - acctest.SkipIfExeNotOnPath(t, "jq") - acctest.SkipIfExeNotOnPath(t, "aws") - ctx := acctest.Context(t) - if testing.Short() { - t.Skip("skipping long-running test in short mode") - } - var dataSource types.DataSource rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) resourceName := "aws_bedrockagent_data_source.test" - foundationModel := "amazon.titan-embed-text-v1" + foundationModel := "amazon.titan-embed-text-v2:0" parsingModel := "anthropic.claude-3-sonnet-20240229-v1:0" resource.Test(t, resource.TestCase{ - PreCheck: func() { - acctest.PreCheck(ctx, t) - }, + PreCheck: func() { acctest.PreCheck(ctx, t) }, ErrorCheck: acctest.ErrorCheck(t, names.BedrockAgentServiceID), ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, - ExternalProviders: map[string]resource.ExternalProvider{ - "null": { - Source: "hashicorp/null", - VersionConstraint: "3.2.2", - }, - }, - CheckDestroy: testAccCheckDataSourceDestroy(ctx), + CheckDestroy: testAccCheckDataSourceDestroy(ctx), Steps: []resource.TestStep{ { Config: testAccDataSourceConfig_parsing(rName, foundationModel, parsingModel), @@ -391,37 +283,18 @@ func testAccDataSource_parsing(t *testing.T) { }) } -// Prerequisites: -// * psql run via null_resource/provisioner "local-exec" -// * jq for parsing output from aws cli to retrieve postgres password func testAccDataSource_disappears(t *testing.T) { - acctest.SkipIfExeNotOnPath(t, "psql") - acctest.SkipIfExeNotOnPath(t, "jq") - acctest.SkipIfExeNotOnPath(t, "aws") - ctx := acctest.Context(t) - if testing.Short() { - t.Skip("skipping long-running test in short mode") - } - var dataSource types.DataSource rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) resourceName := "aws_bedrockagent_data_source.test" - foundationModel := "amazon.titan-embed-text-v1" + foundationModel := "amazon.titan-embed-text-v2:0" resource.Test(t, resource.TestCase{ - PreCheck: func() { - acctest.PreCheck(ctx, t) - }, + PreCheck: func() { acctest.PreCheck(ctx, t) }, ErrorCheck: acctest.ErrorCheck(t, names.BedrockAgentServiceID), ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, - ExternalProviders: map[string]resource.ExternalProvider{ - "null": { - Source: "hashicorp/null", - VersionConstraint: "3.2.2", - }, - }, - CheckDestroy: testAccCheckDataSourceDestroy(ctx), + CheckDestroy: testAccCheckDataSourceDestroy(ctx), Steps: []resource.TestStep{ { Config: testAccDataSourceConfig_basic(rName, foundationModel), @@ -435,37 +308,18 @@ func testAccDataSource_disappears(t *testing.T) { }) } -// Prerequisites: -// * psql run via null_resource/provisioner "local-exec" -// * jq for parsing output from aws cli to retrieve postgres password func testAccDataSource_update(t *testing.T) { - acctest.SkipIfExeNotOnPath(t, "psql") - acctest.SkipIfExeNotOnPath(t, "jq") - acctest.SkipIfExeNotOnPath(t, "aws") - ctx := acctest.Context(t) - if testing.Short() { - t.Skip("skipping long-running test in short mode") - } - var dataSource types.DataSource rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) resourceName := "aws_bedrockagent_data_source.test" - foundationModel := "amazon.titan-embed-text-v1" + foundationModel := "amazon.titan-embed-text-v2:0" resource.Test(t, resource.TestCase{ - PreCheck: func() { - acctest.PreCheck(ctx, t) - }, + PreCheck: func() { acctest.PreCheck(ctx, t) }, ErrorCheck: acctest.ErrorCheck(t, names.BedrockAgentServiceID), ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, - ExternalProviders: map[string]resource.ExternalProvider{ - "null": { - Source: "hashicorp/null", - VersionConstraint: "3.2.2", - }, - }, - CheckDestroy: testAccCheckDataSourceDestroy(ctx), + CheckDestroy: testAccCheckDataSourceDestroy(ctx), Steps: []resource.TestStep{ { Config: testAccDataSourceConfig_basic(rName, foundationModel), @@ -599,7 +453,7 @@ func testAccCheckDataSourceExists(ctx context.Context, n string, v *types.DataSo } func testAccDataSourceConfig_base(rName, embeddingModel string) string { - return acctest.ConfigCompose(testAccKnowledgeBaseConfig_basicRDS(rName, embeddingModel, ""), fmt.Sprintf(` + return acctest.ConfigCompose(testAccKnowledgeBaseConfig_S3VectorsByIndexARN(rName, embeddingModel), fmt.Sprintf(` resource "aws_s3_bucket" "test" { bucket = %[1]q } From b96add5b497f8f69ea3123fd566e92420db499b6 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Thu, 11 Dec 2025 15:27:50 -0500 Subject: [PATCH 65/65] Modernize 'testAccKnowledgeBase_OpenSearchServerless_basic'. --- .../bedrockagent/knowledge_base_test.go | 58 ++++++++++--------- 1 file changed, 32 insertions(+), 26 deletions(-) diff --git a/internal/service/bedrockagent/knowledge_base_test.go b/internal/service/bedrockagent/knowledge_base_test.go index 9efa49b0a87f..95ee5aae5ea5 100644 --- a/internal/service/bedrockagent/knowledge_base_test.go +++ b/internal/service/bedrockagent/knowledge_base_test.go @@ -6,7 +6,6 @@ package bedrockagent_test import ( "context" "fmt" - "os" "testing" awstypes "github.com/aws/aws-sdk-go-v2/service/bedrockagent/types" @@ -158,7 +157,7 @@ func testAccKnowledgeBase_RDS_basic(t *testing.T) { CheckDestroy: testAccCheckKnowledgeBaseDestroy(ctx), Steps: []resource.TestStep{ { - Config: testAccKnowledgeBaseConfig_basicRDS(rName, foundationModel), + Config: testAccKnowledgeBaseConfig_RDS_basic(rName, foundationModel), Check: resource.ComposeTestCheckFunc( testAccCheckKnowledgeBaseExists(ctx, resourceName, &knowledgebase), ), @@ -209,9 +208,7 @@ func testAccKnowledgeBase_OpenSearchServerless_basic(t *testing.T) { foundationModel := "amazon.titan-embed-text-v2:0" resource.Test(t, resource.TestCase{ - PreCheck: func() { - acctest.PreCheck(ctx, t) - }, + PreCheck: func() { acctest.PreCheck(ctx, t) }, ErrorCheck: acctest.ErrorCheck(t, names.BedrockAgentServiceID), ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, CheckDestroy: testAccCheckKnowledgeBaseDestroy(ctx), @@ -220,19 +217,35 @@ func testAccKnowledgeBase_OpenSearchServerless_basic(t *testing.T) { Config: testAccKnowledgeBaseConfig_OpenSearchServerless_basic(rName, collectionName, foundationModel), Check: resource.ComposeTestCheckFunc( testAccCheckKnowledgeBaseExists(ctx, resourceName, &knowledgebase), - resource.TestCheckResourceAttrPair(resourceName, names.AttrRoleARN, "aws_iam_role.test", names.AttrARN), - resource.TestCheckResourceAttr(resourceName, "knowledge_base_configuration.#", "1"), - resource.TestCheckResourceAttr(resourceName, "knowledge_base_configuration.0.vector_knowledge_base_configuration.#", "1"), - resource.TestCheckResourceAttr(resourceName, "knowledge_base_configuration.0.type", "VECTOR"), - resource.TestCheckResourceAttr(resourceName, "storage_configuration.#", "1"), - resource.TestCheckResourceAttr(resourceName, "storage_configuration.0.type", "OPENSEARCH_SERVERLESS"), - resource.TestCheckResourceAttr(resourceName, "storage_configuration.0.opensearch_serverless_configuration.#", "1"), - resource.TestCheckResourceAttr(resourceName, "storage_configuration.0.opensearch_serverless_configuration.0.vector_index_name", "bedrock-knowledge-base-default-index"), - resource.TestCheckResourceAttr(resourceName, "storage_configuration.0.opensearch_serverless_configuration.0.field_mapping.#", "1"), - resource.TestCheckResourceAttr(resourceName, "storage_configuration.0.opensearch_serverless_configuration.0.field_mapping.0.vector_field", "bedrock-knowledge-base-default-vector"), - resource.TestCheckResourceAttr(resourceName, "storage_configuration.0.opensearch_serverless_configuration.0.field_mapping.0.text_field", "AMAZON_BEDROCK_TEXT_CHUNK"), - resource.TestCheckResourceAttr(resourceName, "storage_configuration.0.opensearch_serverless_configuration.0.field_mapping.0.metadata_field", "AMAZON_BEDROCK_METADATA"), ), + ConfigPlanChecks: resource.ConfigPlanChecks{ + PreApply: []plancheck.PlanCheck{ + plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate), + }, + }, + ConfigStateChecks: []statecheck.StateCheck{ + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("knowledge_base_configuration"), knownvalue.ListExact([]knownvalue.Check{ + knownvalue.MapExact(map[string]knownvalue.Check{ + "kendra_knowledge_base_configuration": knownvalue.ListSizeExact(0), + "sql_knowledge_base_configuration": knownvalue.ListSizeExact(0), + names.AttrType: tfknownvalue.StringExact(awstypes.KnowledgeBaseTypeVector), + "vector_knowledge_base_configuration": knownvalue.ListSizeExact(1), + }), + })), + statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("storage_configuration"), knownvalue.ListExact([]knownvalue.Check{ + knownvalue.MapExact(map[string]knownvalue.Check{ + "mongo_db_atlas_configuration": knownvalue.ListSizeExact(0), + "neptune_analytics_configuration": knownvalue.ListSizeExact(0), + "opensearch_managed_cluster_configuration": knownvalue.ListSizeExact(0), + "opensearch_serverless_configuration": knownvalue.ListSizeExact(1), + names.AttrType: tfknownvalue.StringExact(awstypes.KnowledgeBaseStorageTypeOpensearchServerless), + "pinecone_configuration": knownvalue.ListSizeExact(0), + "rds_configuration": knownvalue.ListSizeExact(0), + "redis_enterprise_cloud_configuration": knownvalue.ListSizeExact(0), + "s3_vectors_configuration": knownvalue.ListSizeExact(0), + }), + })), + }, }, { ResourceName: resourceName, @@ -791,14 +804,7 @@ func testAccCheckKnowledgeBaseExists(ctx context.Context, n string, v *awstypes. // environment variable below. func skipIfOSSCollectionNameEnvVarNotSet(t *testing.T) string { t.Helper() - - v := os.Getenv("TF_AWS_BEDROCK_OSS_COLLECTION_NAME") - if v == "" { - acctest.Skip(t, "This test requires external configuration of an OpenSearch collection vector index. "+ - "Set the TF_AWS_BEDROCK_OSS_COLLECTION_NAME environment variable to the OpenSearch collection name "+ - "where the vector index is configured.") - } - return v + return acctest.SkipIfEnvVarNotSet(t, "TF_AWS_BEDROCK_OSS_COLLECTION_NAME") } func testAccKnowledgeBaseConfig_tags1(rName, model, tag1Key, tag1Value string) string { @@ -1087,7 +1093,7 @@ resource "null_resource" "db_setup" { `, rName, model)) } -func testAccKnowledgeBaseConfig_basicRDS(rName, model string) string { +func testAccKnowledgeBaseConfig_RDS_basic(rName, model string) string { return acctest.ConfigCompose(testAccKnowledgeBaseConfig_baseRDS(rName, model), fmt.Sprintf(` resource "aws_bedrockagent_knowledge_base" "test" { name = %[1]q