diff --git a/.changelog/32990.txt b/.changelog/32990.txt new file mode 100644 index 00000000000..221d331f512 --- /dev/null +++ b/.changelog/32990.txt @@ -0,0 +1,3 @@ +```release-note:enhancement +resource/aws_opensearch_outbound_connection: Add `connection_properties`, `connection_mode` and `accept_connection` arguments +``` diff --git a/internal/service/opensearch/inbound_connection_accepter.go b/internal/service/opensearch/inbound_connection_accepter.go index 03e40acf739..8eb6a21dc58 100644 --- a/internal/service/opensearch/inbound_connection_accepter.go +++ b/internal/service/opensearch/inbound_connection_accepter.go @@ -35,8 +35,8 @@ func ResourceInboundConnectionAccepter() *schema.Resource { }, Timeouts: &schema.ResourceTimeout{ - Create: schema.DefaultTimeout(1 * time.Minute), - Delete: schema.DefaultTimeout(1 * time.Minute), + Create: schema.DefaultTimeout(5 * time.Minute), + Delete: schema.DefaultTimeout(5 * time.Minute), }, Schema: map[string]*schema.Schema{ @@ -216,7 +216,7 @@ func statusInboundConnection(ctx context.Context, conn *opensearchservice.OpenSe } } -func waitInboundConnectionAccepted(ctx context.Context, conn *opensearchservice.OpenSearchService, id string, timeout time.Duration) (*opensearchservice.InboundConnection, error) { +func waitInboundConnectionAccepted(ctx context.Context, conn *opensearchservice.OpenSearchService, id string, timeout time.Duration) (*opensearchservice.InboundConnection, error) { //nolint:unparam stateConf := &retry.StateChangeConf{ Pending: []string{opensearchservice.InboundConnectionStatusCodeProvisioning, opensearchservice.InboundConnectionStatusCodeApproved}, Target: []string{opensearchservice.InboundConnectionStatusCodeActive}, diff --git a/internal/service/opensearch/outbound_connection.go b/internal/service/opensearch/outbound_connection.go index 0c1343c07c1..5e0c4fe64ab 100644 --- a/internal/service/opensearch/outbound_connection.go +++ b/internal/service/opensearch/outbound_connection.go @@ -6,7 +6,6 @@ package opensearch import ( "context" "errors" - "fmt" "log" "time" @@ -16,36 +15,108 @@ import ( "github.com/hashicorp/terraform-plugin-sdk/v2/diag" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/retry" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation" "github.com/hashicorp/terraform-provider-aws/internal/conns" + "github.com/hashicorp/terraform-provider-aws/internal/tfresource" ) // @SDKResource("aws_opensearch_outbound_connection") func ResourceOutboundConnection() *schema.Resource { + outboundConnectionDomainInfoSchema := func() *schema.Schema { + return &schema.Schema{ + Type: schema.TypeList, + Required: true, + ForceNew: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "domain_name": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + "owner_id": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + "region": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + }, + }, + } + } + return &schema.Resource{ CreateWithoutTimeout: resourceOutboundConnectionCreate, ReadWithoutTimeout: resourceOutboundConnectionRead, DeleteWithoutTimeout: resourceOutboundConnectionDelete, + Importer: &schema.ResourceImporter{ StateContext: schema.ImportStatePassthroughContext, }, Timeouts: &schema.ResourceTimeout{ - Create: schema.DefaultTimeout(1 * time.Minute), - Delete: schema.DefaultTimeout(1 * time.Minute), + Create: schema.DefaultTimeout(5 * time.Minute), + Delete: schema.DefaultTimeout(5 * time.Minute), }, Schema: map[string]*schema.Schema{ + "accept_connection": { + Type: schema.TypeBool, + Optional: true, + ForceNew: true, + Default: false, + }, "connection_alias": { Type: schema.TypeString, Required: true, ForceNew: true, }, - "local_domain_info": outboundConnectionDomainInfoSchema(), - "remote_domain_info": outboundConnectionDomainInfoSchema(), + "connection_mode": { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + ValidateFunc: validation.StringInSlice(opensearchservice.ConnectionMode_Values(), false), + }, + "connection_properties": { + Type: schema.TypeList, + Optional: true, + Computed: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "cross_cluster_search": { + Type: schema.TypeList, + Optional: true, + ForceNew: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "skip_unavailable": { + Type: schema.TypeString, + Optional: true, + ForceNew: true, + }, + }, + }, + }, + "endpoint": { + Type: schema.TypeString, + Computed: true, + }, + }, + }, + }, "connection_status": { Type: schema.TypeString, Computed: true, }, + "local_domain_info": outboundConnectionDomainInfoSchema(), + "remote_domain_info": outboundConnectionDomainInfoSchema(), }, } } @@ -53,27 +124,41 @@ func ResourceOutboundConnection() *schema.Resource { func resourceOutboundConnectionCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { conn := meta.(*conns.AWSClient).OpenSearchConn(ctx) - // Create the Outbound Connection - createOpts := &opensearchservice.CreateOutboundConnectionInput{ - ConnectionAlias: aws.String(d.Get("connection_alias").(string)), - LocalDomainInfo: expandOutboundConnectionDomainInfo(d.Get("local_domain_info").([]interface{})), - RemoteDomainInfo: expandOutboundConnectionDomainInfo(d.Get("remote_domain_info").([]interface{})), + connectionAlias := d.Get("connection_alias").(string) + input := &opensearchservice.CreateOutboundConnectionInput{ + ConnectionAlias: aws.String(connectionAlias), + ConnectionMode: aws.String(d.Get("connection_mode").(string)), + ConnectionProperties: expandOutboundConnectionConnectionProperties(d.Get("connection_properties").([]interface{})), + LocalDomainInfo: expandOutboundConnectionDomainInfo(d.Get("local_domain_info").([]interface{})), + RemoteDomainInfo: expandOutboundConnectionDomainInfo(d.Get("remote_domain_info").([]interface{})), } - log.Printf("[DEBUG] Outbound Connection Create options: %#v", createOpts) + output, err := conn.CreateOutboundConnectionWithContext(ctx, input) - resp, err := conn.CreateOutboundConnectionWithContext(ctx, createOpts) if err != nil { - return diag.Errorf("creating Outbound Connection: %s", err) + return diag.Errorf("creating OpenSearch Outbound Connection (%s): %s", connectionAlias, err) } - // Get the ID and store it - d.SetId(aws.StringValue(resp.ConnectionId)) - log.Printf("[INFO] Outbound Connection ID: %s", d.Id()) + d.SetId(aws.StringValue(output.ConnectionId)) - err = outboundConnectionWaitUntilAvailable(ctx, conn, d.Id(), d.Timeout(schema.TimeoutCreate)) - if err != nil { - return diag.Errorf("waiting for Outbound Connection to become available: %s", err) + if _, err := waitOutboundConnectionCreated(ctx, conn, d.Id(), d.Timeout(schema.TimeoutCreate)); err != nil { + return diag.Errorf("waiting for OpenSearch Outbound Connection (%s) create: %s", d.Id(), err) + } + + if d.Get("accept_connection").(bool) { + input := &opensearchservice.AcceptInboundConnectionInput{ + ConnectionId: aws.String(d.Id()), + } + + _, err := conn.AcceptInboundConnectionWithContext(ctx, input) + + if err != nil { + return diag.Errorf("accepting OpenSearch Inbound Connection (%s): %s", d.Id(), err) + } + + if _, err := waitInboundConnectionAccepted(ctx, conn, d.Id(), d.Timeout(schema.TimeoutCreate)); err != nil { + return diag.Errorf("waiting for OpenSearch Inbound Connection (%s) accept: %s", d.Id(), err) + } } return resourceOutboundConnectionRead(ctx, d, meta) @@ -82,25 +167,24 @@ func resourceOutboundConnectionCreate(ctx context.Context, d *schema.ResourceDat func resourceOutboundConnectionRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { conn := meta.(*conns.AWSClient).OpenSearchConn(ctx) - ccscRaw, statusCode, err := outboundConnectionRefreshState(ctx, conn, d.Id())() - - if err != nil { - return diag.Errorf("reading Outbound Connection: %s", err) - } + connection, err := FindOutboundConnectionByID(ctx, conn, d.Id()) - ccsc := ccscRaw.(*opensearchservice.OutboundConnection) - log.Printf("[DEBUG] Outbound Connection response: %#v", ccsc) - - if !d.IsNewResource() && statusCode == opensearchservice.OutboundConnectionStatusCodeDeleted { - log.Printf("[INFO] Outbound Connection (%s) deleted, removing from state", d.Id()) + if !d.IsNewResource() && tfresource.NotFound(err) { + log.Printf("[WARN] OpenSearch Outbound Connection (%s) not found, removing from state", d.Id()) d.SetId("") return nil } - d.Set("connection_alias", ccsc.ConnectionAlias) - d.Set("remote_domain_info", flattenOutboundConnectionDomainInfo(ccsc.RemoteDomainInfo)) - d.Set("local_domain_info", flattenOutboundConnectionDomainInfo(ccsc.LocalDomainInfo)) - d.Set("connection_status", statusCode) + if err != nil { + return diag.Errorf("reading OpenSearch Outbound Connection (%s): %s", d.Id(), err) + } + + d.Set("connection_alias", connection.ConnectionAlias) + d.Set("connection_mode", connection.ConnectionMode) + d.Set("connection_properties", flattenOutboundConnectionConnectionProperties(connection.ConnectionProperties)) + d.Set("connection_status", connection.ConnectionStatus.StatusCode) + d.Set("remote_domain_info", flattenOutboundConnectionDomainInfo(connection.RemoteDomainInfo)) + d.Set("local_domain_info", flattenOutboundConnectionDomainInfo(connection.LocalDomainInfo)) return nil } @@ -118,61 +202,99 @@ func resourceOutboundConnectionDelete(ctx context.Context, d *schema.ResourceDat } if err != nil { - return diag.Errorf("deleting Outbound Connection (%s): %s", d.Id(), err) + return diag.Errorf("deleting OpenSearch Outbound Connection (%s): %s", d.Id(), err) } - if err := waitForOutboundConnectionDeletion(ctx, conn, d.Id(), d.Timeout(schema.TimeoutDelete)); err != nil { - return diag.Errorf("waiting for VPC Peering Connection (%s) to be deleted: %s", d.Id(), err) + if _, err := waitOutboundConnectionDeleted(ctx, conn, d.Id(), d.Timeout(schema.TimeoutCreate)); err != nil { + return diag.Errorf("waiting for OpenSearch Outbound Connection (%s) delete: %s", d.Id(), err) } return nil } -func outboundConnectionRefreshState(ctx context.Context, conn *opensearchservice.OpenSearchService, id string) retry.StateRefreshFunc { - return func() (interface{}, string, error) { - resp, err := conn.DescribeOutboundConnectionsWithContext(ctx, &opensearchservice.DescribeOutboundConnectionsInput{ - Filters: []*opensearchservice.Filter{ - { - Name: aws.String("connection-id"), - Values: []*string{aws.String(id)}, - }, +func FindOutboundConnectionByID(ctx context.Context, conn *opensearchservice.OpenSearchService, id string) (*opensearchservice.OutboundConnection, error) { + input := &opensearchservice.DescribeOutboundConnectionsInput{ + Filters: []*opensearchservice.Filter{ + { + Name: aws.String("connection-id"), + Values: aws.StringSlice([]string{id}), }, - }) - if err != nil { - return nil, "", err + }, + } + + output, err := findOutboundConnection(ctx, conn, input) + + if err != nil { + return nil, err + } + + if output.ConnectionStatus == nil { + return nil, tfresource.NewEmptyResultError(input) + } + + if status := aws.StringValue(output.ConnectionStatus.StatusCode); status == opensearchservice.OutboundConnectionStatusCodeDeleted { + return nil, &retry.NotFoundError{ + Message: status, + LastRequest: input, } + } - if resp == nil || resp.Connections == nil || - len(resp.Connections) == 0 || resp.Connections[0] == nil { - // Sometimes AWS just has consistency issues and doesn't see - // our connection yet. Return an empty state. - return nil, "", nil + return output, err +} + +func findOutboundConnection(ctx context.Context, conn *opensearchservice.OpenSearchService, input *opensearchservice.DescribeOutboundConnectionsInput) (*opensearchservice.OutboundConnection, error) { + output, err := findOutboundConnections(ctx, conn, input) + + if err != nil { + return nil, err + } + + return tfresource.AssertSinglePtrResult(output) +} + +func findOutboundConnections(ctx context.Context, conn *opensearchservice.OpenSearchService, input *opensearchservice.DescribeOutboundConnectionsInput) ([]*opensearchservice.OutboundConnection, error) { + var output []*opensearchservice.OutboundConnection + + err := conn.DescribeOutboundConnectionsPagesWithContext(ctx, input, func(page *opensearchservice.DescribeOutboundConnectionsOutput, lastPage bool) bool { + if page == nil { + return !lastPage } - ccsc := resp.Connections[0] - if ccsc.ConnectionStatus == nil { - // Sometimes AWS just has consistency issues and doesn't see - // our connection yet. Return an empty state. + + for _, v := range page.Connections { + if v != nil { + output = append(output, v) + } + } + + return !lastPage + }) + + if err != nil { + return nil, err + } + + return output, nil +} + +func statusOutboundConnection(ctx context.Context, conn *opensearchservice.OpenSearchService, id string) retry.StateRefreshFunc { + return func() (interface{}, string, error) { + output, err := FindOutboundConnectionByID(ctx, conn, id) + + if tfresource.NotFound(err) { return nil, "", nil } - statusCode := aws.StringValue(ccsc.ConnectionStatus.StatusCode) - // A Outbound Connection can exist in a failed state, - // thus we short circuit before the time out would occur. - if statusCode == opensearchservice.OutboundConnectionStatusCodeValidationFailed { - return nil, statusCode, errors.New(aws.StringValue(ccsc.ConnectionStatus.Message)) + if err != nil { + return nil, "", err } - return ccsc, statusCode, nil + return output, aws.StringValue(output.ConnectionStatus.StatusCode), nil } } -func outboundConnectionWaitUntilAvailable(ctx context.Context, conn *opensearchservice.OpenSearchService, id string, timeout time.Duration) error { - log.Printf("[DEBUG] Waiting for Outbound Connection (%s) to become available.", id) +func waitOutboundConnectionCreated(ctx context.Context, conn *opensearchservice.OpenSearchService, id string, timeout time.Duration) (*opensearchservice.OutboundConnection, error) { stateConf := &retry.StateChangeConf{ - Pending: []string{ - opensearchservice.OutboundConnectionStatusCodeValidating, - opensearchservice.OutboundConnectionStatusCodeProvisioning, - }, + Pending: []string{opensearchservice.OutboundConnectionStatusCodeValidating, opensearchservice.OutboundConnectionStatusCodeProvisioning}, Target: []string{ opensearchservice.OutboundConnectionStatusCodePendingAcceptance, opensearchservice.OutboundConnectionStatusCodeActive, @@ -180,16 +302,22 @@ func outboundConnectionWaitUntilAvailable(ctx context.Context, conn *opensearchs opensearchservice.OutboundConnectionStatusCodeRejected, opensearchservice.OutboundConnectionStatusCodeValidationFailed, }, - Refresh: outboundConnectionRefreshState(ctx, conn, id), + Refresh: statusOutboundConnection(ctx, conn, id), Timeout: timeout, } - if _, err := stateConf.WaitForStateContext(ctx); err != nil { - return fmt.Errorf("waiting for Outbound Connection (%s) to become available: %s", id, err) + + outputRaw, err := stateConf.WaitForStateContext(ctx) + + if output, ok := outputRaw.(*opensearchservice.OutboundConnection); ok { + tfresource.SetLastError(err, errors.New(aws.StringValue(output.ConnectionStatus.Message))) + + return output, err } - return nil + + return nil, err } -func waitForOutboundConnectionDeletion(ctx context.Context, conn *opensearchservice.OpenSearchService, id string, timeout time.Duration) error { +func waitOutboundConnectionDeleted(ctx context.Context, conn *opensearchservice.OpenSearchService, id string, timeout time.Duration) (*opensearchservice.OutboundConnection, error) { stateConf := &retry.StateChangeConf{ Pending: []string{ opensearchservice.OutboundConnectionStatusCodeActive, @@ -197,44 +325,20 @@ func waitForOutboundConnectionDeletion(ctx context.Context, conn *opensearchserv opensearchservice.OutboundConnectionStatusCodeDeleting, opensearchservice.OutboundConnectionStatusCodeRejecting, }, - Target: []string{ - opensearchservice.OutboundConnectionStatusCodeDeleted, - }, - Refresh: outboundConnectionRefreshState(ctx, conn, id), + Target: []string{}, + Refresh: statusOutboundConnection(ctx, conn, id), Timeout: timeout, } - _, err := stateConf.WaitForStateContext(ctx) + outputRaw, err := stateConf.WaitForStateContext(ctx) - return err -} + if output, ok := outputRaw.(*opensearchservice.OutboundConnection); ok { + tfresource.SetLastError(err, errors.New(aws.StringValue(output.ConnectionStatus.Message))) -func outboundConnectionDomainInfoSchema() *schema.Schema { - return &schema.Schema{ - Type: schema.TypeList, - Required: true, - ForceNew: true, - MaxItems: 1, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "owner_id": { - Type: schema.TypeString, - Required: true, - ForceNew: true, - }, - "domain_name": { - Type: schema.TypeString, - Required: true, - ForceNew: true, - }, - "region": { - Type: schema.TypeString, - Required: true, - ForceNew: true, - }, - }, - }, + return output, err } + + return nil, err } func expandOutboundConnectionDomainInfo(vOptions []interface{}) *opensearchservice.DomainInformationContainer { @@ -263,3 +367,46 @@ func flattenOutboundConnectionDomainInfo(domainInfo *opensearchservice.DomainInf "region": aws.StringValue(domainInfo.AWSDomainInformation.Region), }} } + +func expandOutboundConnectionConnectionProperties(cProperties []interface{}) *opensearchservice.ConnectionProperties { + if len(cProperties) == 0 || cProperties[0] == nil { + return nil + } + + mOptions := cProperties[0].(map[string]interface{}) + + return &opensearchservice.ConnectionProperties{ + CrossClusterSearch: expandOutboundConnectionCrossClusterSearchConnectionProperties(mOptions["cross_cluster_search"].([]interface{})), + } +} + +func flattenOutboundConnectionConnectionProperties(cProperties *opensearchservice.ConnectionProperties) []interface{} { + if cProperties == nil { + return nil + } + return []interface{}{map[string]interface{}{ + "cross_cluster_search": flattenOutboundConnectionCrossClusterSearchConnectionProperties(cProperties.CrossClusterSearch), + "endpoint": aws.StringValue(cProperties.Endpoint), + }} +} + +func expandOutboundConnectionCrossClusterSearchConnectionProperties(cProperties []interface{}) *opensearchservice.CrossClusterSearchConnectionProperties { + if len(cProperties) == 0 || cProperties[0] == nil { + return nil + } + + mOptions := cProperties[0].(map[string]interface{}) + + return &opensearchservice.CrossClusterSearchConnectionProperties{ + SkipUnavailable: aws.String(mOptions["skip_unavailable"].(string)), + } +} + +func flattenOutboundConnectionCrossClusterSearchConnectionProperties(cProperties *opensearchservice.CrossClusterSearchConnectionProperties) []interface{} { + if cProperties == nil { + return nil + } + return []interface{}{map[string]interface{}{ + "skip_unavailable": aws.StringValue(cProperties.SkipUnavailable), + }} +} diff --git a/internal/service/opensearch/outbound_connection_test.go b/internal/service/opensearch/outbound_connection_test.go index 01c9f0f5b97..9b779e781b8 100644 --- a/internal/service/opensearch/outbound_connection_test.go +++ b/internal/service/opensearch/outbound_connection_test.go @@ -32,13 +32,46 @@ func TestAccOpenSearchOutboundConnection_basic(t *testing.T) { Check: resource.ComposeTestCheckFunc( testAccCheckDomainExists(ctx, "aws_opensearch_domain.domain_1", &domain), testAccCheckDomainExists(ctx, "aws_opensearch_domain.domain_2", &domain), - resource.TestCheckResourceAttr(resourceName, "connection_status", "PENDING_ACCEPTANCE"), + resource.TestCheckResourceAttr(resourceName, "connection_status", "ACTIVE"), ), }, { - ResourceName: resourceName, - ImportState: true, - ImportStateVerify: true, + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"accept_connection"}, + }, + }, + }) +} + +func TestAccOpenSearchOutboundConnection_vpc(t *testing.T) { + ctx := acctest.Context(t) + var domain opensearchservice.DomainStatus + ri := sdkacctest.RandString(10) + name := fmt.Sprintf("tf-test-%s", ri) + resourceName := "aws_opensearch_outbound_connection.test" + + resource.ParallelTest(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t) }, + ErrorCheck: acctest.ErrorCheck(t, opensearchservice.EndpointsID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckDomainDestroy(ctx), + Steps: []resource.TestStep{ + { + Config: testAccOutboundConnectionConfig_vpcEndpoint(name), + Check: resource.ComposeTestCheckFunc( + testAccCheckDomainExists(ctx, "aws_opensearch_domain.domain_1", &domain), + testAccCheckDomainExists(ctx, "aws_opensearch_domain.domain_2", &domain), + resource.TestCheckResourceAttrSet(resourceName, "connection_properties.0.endpoint"), + resource.TestCheckResourceAttr(resourceName, "connection_status", "ACTIVE"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"accept_connection"}, }, }, }) @@ -150,7 +183,16 @@ data "aws_caller_identity" "current" {} data "aws_region" "current" {} resource "aws_opensearch_outbound_connection" "test" { - connection_alias = "%s" + connection_alias = "%s" + connection_mode = "DIRECT" + accept_connection = true + + connection_properties { + cross_cluster_search { + skip_unavailable = "ENABLED" + } + } + local_domain_info { owner_id = data.aws_caller_identity.current.account_id region = data.aws_region.current.name @@ -165,3 +207,126 @@ resource "aws_opensearch_outbound_connection" "test" { } `, name, pw, name, pw, name) } + +func testAccOutboundConnectionConfig_vpcEndpoint(name string) string { + // Satisfy the pw requirements + pw := fmt.Sprintf("Aa1-%s", sdkacctest.RandString(10)) + + return acctest.ConfigCompose( + acctest.ConfigAvailableAZsNoOptIn(), + fmt.Sprintf(` +resource "aws_vpc" "test" { + cidr_block = "192.168.0.0/22" + + tags = { + Name = %[1]q + } +} + +resource "aws_subnet" "test" { + vpc_id = aws_vpc.test.id + availability_zone = data.aws_availability_zones.available.names[0] + cidr_block = "192.168.0.0/24" + + tags = { + Name = %[1]q + } +} + +resource "aws_subnet" "test2" { + vpc_id = aws_vpc.test.id + availability_zone = data.aws_availability_zones.available.names[1] + cidr_block = "192.168.1.0/24" + + tags = { + Name = %[1]q + } +} + +resource "aws_security_group" "test" { + vpc_id = aws_vpc.test.id +} + +resource "aws_security_group" "test2" { + vpc_id = aws_vpc.test.id +} + +resource "aws_opensearch_domain" "domain_1" { + domain_name = "%[1]s-1" + + cluster_config { + instance_type = "t3.small.search" # supported in both aws and aws-us-gov + } + + ebs_options { + ebs_enabled = true + volume_size = 10 + } + + node_to_node_encryption { + enabled = true + } + + advanced_security_options { + enabled = true + internal_user_database_enabled = true + + master_user_options { + master_user_name = "test" + master_user_password = %[2]q + } + } + + encrypt_at_rest { + enabled = true + } + + domain_endpoint_options { + enforce_https = true + tls_security_policy = "Policy-Min-TLS-1-2-2019-07" + } +} + +resource "aws_opensearch_domain" "domain_2" { + domain_name = "%[1]s-2" + + ebs_options { + ebs_enabled = true + volume_size = 10 + } + + cluster_config { + instance_count = 2 + zone_awareness_enabled = true + instance_type = "t3.small.search" + } + + vpc_options { + security_group_ids = [aws_security_group.test.id, aws_security_group.test2.id] + subnet_ids = [aws_subnet.test.id, aws_subnet.test2.id] + } +} + +data "aws_caller_identity" "current" {} +data "aws_region" "current" {} + +resource "aws_opensearch_outbound_connection" "test" { + connection_alias = %[1]q + connection_mode = "VPC_ENDPOINT" + accept_connection = true + + local_domain_info { + owner_id = data.aws_caller_identity.current.account_id + region = data.aws_region.current.name + domain_name = aws_opensearch_domain.domain_1.domain_name + } + + remote_domain_info { + owner_id = data.aws_caller_identity.current.account_id + region = data.aws_region.current.name + domain_name = aws_opensearch_domain.domain_2.domain_name + } +} + +`, name, pw)) +} diff --git a/website/docs/r/opensearch_inbound_connection_accepter.html.markdown b/website/docs/r/opensearch_inbound_connection_accepter.html.markdown index dbceeeda294..7c642498f8a 100644 --- a/website/docs/r/opensearch_inbound_connection_accepter.html.markdown +++ b/website/docs/r/opensearch_inbound_connection_accepter.html.markdown @@ -51,6 +51,13 @@ This resource exports the following attributes in addition to the arguments abov * `id` - The Id of the connection to accept. * `connection_status` - Status of the connection request. +## Timeouts + +[Configuration options](https://developer.hashicorp.com/terraform/language/resources/syntax#operation-timeouts): + +* `create` - (Default `5m`) +* `delete` - (Default `5m`) + ## Import In Terraform v1.5.0 and later, use an [`import` block](https://developer.hashicorp.com/terraform/language/import) to import AWS Opensearch Inbound Connection Accepters using the Inbound Connection ID. For example: diff --git a/website/docs/r/opensearch_outbound_connection.html.markdown b/website/docs/r/opensearch_outbound_connection.html.markdown index 528cc3f8240..ded5205d4d4 100644 --- a/website/docs/r/opensearch_outbound_connection.html.markdown +++ b/website/docs/r/opensearch_outbound_connection.html.markdown @@ -20,6 +20,7 @@ data "aws_region" "current" {} resource "aws_opensearch_outbound_connection" "foo" { connection_alias = "outbound_connection" + connection_mode = "DIRECT" local_domain_info { owner_id = data.aws_caller_identity.current.account_id region = data.aws_region.current.name @@ -39,9 +40,20 @@ resource "aws_opensearch_outbound_connection" "foo" { This resource supports the following arguments: * `connection_alias` - (Required, Forces new resource) Specifies the connection alias that will be used by the customer for this connection. +* `connection_mode` - (Required, Forces new resource) Specifies the connection mode. Accepted values are `DIRECT` or `VPC_ENDPOINT`. +* `accept_connection` - (Optional, Forces new resource) Accepts the connection. +* `connection_properties` - (Optional, Forces new resource) Configuration block for the outbound connection. * `local_domain_info` - (Required, Forces new resource) Configuration block for the local Opensearch domain. * `remote_domain_info` - (Required, Forces new resource) Configuration block for the remote Opensearch domain. +### connection_properties + +* `cross_cluster_search` - (Optional, Forces new resource) Configuration block for cross cluster search. + +### cross_cluster_search + +* `skip_unavailable` - (Optional, Forces new resource) Skips unavailable clusters and can only be used for cross-cluster searches. Accepted values are `ENABLED` or `DISABLED`. + ### local_domain_info * `owner_id` - (Required, Forces new resource) The Account ID of the owner of the local domain. @@ -61,6 +73,17 @@ This resource exports the following attributes in addition to the arguments abov * `id` - The Id of the connection. * `connection_status` - Status of the connection request. +`connection_properties` block exports the following: + +* `endpoint` - The endpoint of the remote domain, is only set when `connection_mode` is `VPC_ENDPOINT` and `accept_connection` is `TRUE`. + +## Timeouts + +[Configuration options](https://developer.hashicorp.com/terraform/language/resources/syntax#operation-timeouts): + +* `create` - (Default `5m`) +* `delete` - (Default `5m`) + ## Import In Terraform v1.5.0 and later, use an [`import` block](https://developer.hashicorp.com/terraform/language/import) to import AWS Opensearch Outbound Connections using the Outbound Connection ID. For example: