From cfd2686135821dda4089233a7cda49059c94685d Mon Sep 17 00:00:00 2001 From: Benny Lu Date: Fri, 30 Dec 2022 21:15:33 -0800 Subject: [PATCH 01/10] aws_transfer_server - protocol_details --- internal/service/transfer/server.go | 90 ++++++++++++++++++++++++ internal/service/transfer/server_test.go | 52 ++++++++++++++ 2 files changed, 142 insertions(+) diff --git a/internal/service/transfer/server.go b/internal/service/transfer/server.go index 7f749c1a6fe1..a5df7926c19c 100644 --- a/internal/service/transfer/server.go +++ b/internal/service/transfer/server.go @@ -176,6 +176,37 @@ func ResourceServer() *schema.Resource { ValidateFunc: validation.StringInSlice(transfer.Protocol_Values(), false), }, }, + "protocol_details": { + Type: schema.TypeList, + Optional: true, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "passive_ip": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.StringLenBetween(0, 15), + }, + "set_stat_option": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.StringInSlice([]string{ + "DEFAULT", + "ENABLE_NO_OP", + }, false), + }, + "tls_session_resumption_mode": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.StringInSlice([]string{ + "DISABLED", + "ENABLED", + "ENFORCED", + }, false), + }, + }, + }, + }, "security_policy_name": { Type: schema.TypeString, Optional: true, @@ -297,6 +328,10 @@ func resourceServerCreate(d *schema.ResourceData, meta interface{}) error { input.Protocols = flex.ExpandStringSet(v.(*schema.Set)) } + if v, ok := d.GetOk("protocol_details"); ok && len(v.([]interface{})) > 0 { + input.ProtocolDetails = expandProtocolDetails(v.([]interface{})) + } + if v, ok := d.GetOk("security_policy_name"); ok { input.SecurityPolicyName = aws.String(v.(string)) } @@ -423,6 +458,11 @@ func resourceServerRead(d *schema.ResourceData, meta interface{}) error { d.Set("post_authentication_login_banner", output.PostAuthenticationLoginBanner) d.Set("pre_authentication_login_banner", output.PreAuthenticationLoginBanner) d.Set("protocols", aws.StringValueSlice(output.Protocols)) + + if err := d.Set("protocol_details", flattenProtocolDetails(output.ProtocolDetails)); err != nil { + return fmt.Errorf("error setting protocol_details: %w", err) + } + d.Set("security_policy_name", output.SecurityPolicyName) if output.IdentityProviderDetails != nil { d.Set("url", output.IdentityProviderDetails.Url) @@ -603,6 +643,10 @@ func resourceServerUpdate(d *schema.ResourceData, meta interface{}) error { input.Protocols = flex.ExpandStringSet(d.Get("protocols").(*schema.Set)) } + if d.HasChange("protocol_details") { + input.ProtocolDetails = expandProtocolDetails(d.Get("protocol_details").([]interface{})) + } + if d.HasChange("security_policy_name") { input.SecurityPolicyName = aws.String(d.Get("security_policy_name").(string)) } @@ -794,6 +838,52 @@ func flattenEndpointDetails(apiObject *transfer.EndpointDetails, securityGroupID return tfMap } +func expandProtocolDetails(m []interface{}) *transfer.ProtocolDetails { + if len(m) < 1 || m[0] == nil { + return nil + } + + tfMap := m[0].(map[string]interface{}) + + apiObject := &transfer.ProtocolDetails{} + + if v, ok := tfMap["passive_ip"].(string); ok && len(v) > 0 { + apiObject.PassiveIp = aws.String(v) + } + + if v, ok := tfMap["set_stat_option"].(string); ok && len(v) > 0 { + apiObject.SetStatOption = aws.String(v) + } + + if v, ok := tfMap["tls_session_resumption_mode"].(string); ok && len(v) > 0 { + apiObject.TlsSessionResumptionMode = aws.String(v) + } + + return apiObject +} + +func flattenProtocolDetails(apiObject *transfer.ProtocolDetails) []interface{} { + if apiObject == nil { + return nil + } + + tfMap := map[string]interface{}{} + + if v := apiObject.PassiveIp; v != nil { + tfMap["passive_ip"] = aws.StringValue(v) + } + + if v := apiObject.SetStatOption; v != nil { + tfMap["set_stat_option"] = aws.StringValue(v) + } + + if v := apiObject.TlsSessionResumptionMode; v != nil { + tfMap["tls_session_resumption_mode"] = aws.StringValue(v) + } + + return []interface{}{tfMap} +} + func expandWorkflowDetails(tfMap []interface{}) *transfer.WorkflowDetails { if tfMap == nil { return nil diff --git a/internal/service/transfer/server_test.go b/internal/service/transfer/server_test.go index 3a0b296f08fb..9b437e92e005 100644 --- a/internal/service/transfer/server_test.go +++ b/internal/service/transfer/server_test.go @@ -727,6 +727,46 @@ func testAccServer_protocols(t *testing.T) { }) } +func TestAccServer_protocolDetails(t *testing.T) { + var s transfer.DescribedServer + resourceName := "aws_transfer_server.test" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(t); testAccPreCheck(t) }, + ErrorCheck: acctest.ErrorCheck(t, transfer.EndpointsID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + CheckDestroy: testAccCheckServerDestroy, + Steps: []resource.TestStep{ + { + Config: testAccServerConfig_protocolDetails("AUTO", "DEFAULT", "ENFORCED"), + Check: resource.ComposeTestCheckFunc( + testAccCheckServerExists(resourceName, &s), + resource.TestCheckResourceAttr(resourceName, "protocol_details.#", "1"), + resource.TestCheckResourceAttr(resourceName, "protocol_details.0.passive_ip", "AUTO"), + resource.TestCheckResourceAttr(resourceName, "protocol_details.0.set_stat_option", "DEFAULT"), + resource.TestCheckResourceAttr(resourceName, "protocol_details.0.tls_session_resumption_mode", "ENFORCED"), + ), + }, + { + ResourceName: resourceName, + ImportState: true, + ImportStateVerify: true, + ImportStateVerifyIgnore: []string{"force_destroy"}, + }, + { + Config: testAccServerConfig_protocolDetails("AUTO", "ENABLE_NO_OP", "DISABLED"), + Check: resource.ComposeTestCheckFunc( + testAccCheckServerExists(resourceName, &s), + resource.TestCheckResourceAttr(resourceName, "protocol_details.#", "1"), + resource.TestCheckResourceAttr(resourceName, "protocol_details.0.passive_ip", "AUTO"), + resource.TestCheckResourceAttr(resourceName, "protocol_details.0.set_stat_option", "ENABLE_NO_OP"), + resource.TestCheckResourceAttr(resourceName, "protocol_details.0.tls_session_resumption_mode", "DISABLED"), + ), + }, + }, + }) +} + func testAccServer_apiGateway(t *testing.T) { var conf transfer.DescribedServer resourceName := "aws_transfer_server.test" @@ -1599,6 +1639,18 @@ resource "aws_transfer_server" "test" { `) } +func testAccServerConfig_protocolDetails(passive_ip, set_stat_option, tls_session_resumption_mode string) string { + return fmt.Sprintf(` +resource "aws_transfer_server" "test" { + protocol_details { + passive_ip = %[1]q + set_stat_option = %[2]q + tls_session_resumption_mode = %[3]q + } +} +`, passive_ip, set_stat_option, tls_session_resumption_mode) +} + func testAccServerConfig_rootCA(domain string) string { return fmt.Sprintf(` resource "aws_acmpca_certificate_authority" "test" { From 603a3276cbd4aeb6608368e50f6a2fa68e99d046 Mon Sep 17 00:00:00 2001 From: Benny Lu Date: Fri, 30 Dec 2022 21:21:52 -0800 Subject: [PATCH 02/10] Update doc --- website/docs/r/transfer_server.html.markdown | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/website/docs/r/transfer_server.html.markdown b/website/docs/r/transfer_server.html.markdown index db9baebfa3d3..db8df2fb142d 100644 --- a/website/docs/r/transfer_server.html.markdown +++ b/website/docs/r/transfer_server.html.markdown @@ -108,6 +108,7 @@ The following arguments are supported: * `force_destroy` - (Optional) A boolean that indicates all users associated with the server should be deleted so that the Server can be destroyed without error. The default value is `false`. This option only applies to servers configured with a `SERVICE_MANAGED` `identity_provider_type`. * `post_authentication_login_banner`- (Optional) Specify a string to display when users connect to a server. This string is displayed after the user authenticates. The SFTP protocol does not support post-authentication display banners. * `pre_authentication_login_banner`- (Optional) Specify a string to display when users connect to a server. This string is displayed before the user authenticates. +* `protocol_details`- (Optional) The protocol settings that are configured for your server. * `security_policy_name` - (Optional) Specifies the name of the security policy that is attached to the server. Possible values are `TransferSecurityPolicy-2018-11`, `TransferSecurityPolicy-2020-06`, `TransferSecurityPolicy-FIPS-2020-06` and `TransferSecurityPolicy-2022-03`. Default value is: `TransferSecurityPolicy-2018-11`. * `tags` - (Optional) A map of tags to assign to the resource. If configured with a provider [`default_tags` configuration block](https://registry.terraform.io/providers/hashicorp/aws/latest/docs#default_tags-configuration-block) present, tags with matching keys will overwrite those defined at the provider-level. * `workflow_details` - (Optional) Specifies the workflow details. See Workflow Details below. @@ -120,6 +121,12 @@ The following arguments are supported: * `vpc_endpoint_id` - (Optional) The ID of the VPC endpoint. This property can only be used when `endpoint_type` is set to `VPC_ENDPOINT` * `vpc_id` - (Optional) The VPC ID of the virtual private cloud in which the SFTP server's endpoint will be hosted. This property can only be used when `endpoint_type` is set to `VPC`. +### Protocol Details + +* `passive_ip` - (Optional) Indicates passive mode, for FTP and FTPS protocols. Enter a single IPv4 address, such as the public IP address of a firewall, router, or load balancer. +* `set_stat_option` - (Optional) Use to ignore the error that is generated when the client attempts to use `SETSTAT` on a file you are uploading to an S3 bucket. +* `tls_session_resumption_mode` - (Optional) A property used with Transfer Family servers that use the FTPS protocol. Provides a mechanism to resume or share a negotiated secret key between the control and data connection for an FTPS session. + ### Workflow Details * `on_upload` - (Optional) A trigger that starts a workflow: the workflow begins to execute after a file is uploaded. See Workflow Detail below. From 6b0aace22c2f0e6a82bc3a9b53dc8bf463f0a4dd Mon Sep 17 00:00:00 2001 From: Benny Lu Date: Fri, 30 Dec 2022 21:22:58 -0800 Subject: [PATCH 03/10] Add to serial tests --- internal/service/transfer/server_test.go | 2 +- internal/service/transfer/transfer_test.go | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/internal/service/transfer/server_test.go b/internal/service/transfer/server_test.go index 9b437e92e005..5a5aeb4cc2cc 100644 --- a/internal/service/transfer/server_test.go +++ b/internal/service/transfer/server_test.go @@ -727,7 +727,7 @@ func testAccServer_protocols(t *testing.T) { }) } -func TestAccServer_protocolDetails(t *testing.T) { +func testAccServer_protocolDetails(t *testing.T) { var s transfer.DescribedServer resourceName := "aws_transfer_server.test" diff --git a/internal/service/transfer/transfer_test.go b/internal/service/transfer/transfer_test.go index 2f2e955361b6..494d629ca25f 100644 --- a/internal/service/transfer/transfer_test.go +++ b/internal/service/transfer/transfer_test.go @@ -24,6 +24,7 @@ func TestAccTransfer_serial(t *testing.T) { "HostKey": testAccServer_hostKey, "LambdaFunction": testAccServer_lambdaFunction, "Protocols": testAccServer_protocols, + "ProtocolDetails": testAccServer_protocolDetails, "SecurityPolicy": testAccServer_securityPolicy, "UpdateEndpointTypePublicToVPC": testAccServer_updateEndpointType_publicToVPC, "UpdateEndpointTypePublicToVPCAddressAllocationIDs": testAccServer_updateEndpointType_publicToVPC_addressAllocationIDs, From 97192ff13825486e6269f48dbfbb45c86fa6d6e7 Mon Sep 17 00:00:00 2001 From: Benny Lu Date: Fri, 30 Dec 2022 21:25:16 -0800 Subject: [PATCH 04/10] Lint --- internal/service/transfer/server_test.go | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/internal/service/transfer/server_test.go b/internal/service/transfer/server_test.go index 5a5aeb4cc2cc..8f1d0f80dfd9 100644 --- a/internal/service/transfer/server_test.go +++ b/internal/service/transfer/server_test.go @@ -1642,11 +1642,11 @@ resource "aws_transfer_server" "test" { func testAccServerConfig_protocolDetails(passive_ip, set_stat_option, tls_session_resumption_mode string) string { return fmt.Sprintf(` resource "aws_transfer_server" "test" { - protocol_details { - passive_ip = %[1]q - set_stat_option = %[2]q - tls_session_resumption_mode = %[3]q - } + protocol_details { + passive_ip = %[1]q + set_stat_option = %[2]q + tls_session_resumption_mode = %[3]q + } } `, passive_ip, set_stat_option, tls_session_resumption_mode) } From 81319bc1b44b58f7d56fcc1739ba6e2283f765e1 Mon Sep 17 00:00:00 2001 From: Benny Lu Date: Fri, 30 Dec 2022 21:28:35 -0800 Subject: [PATCH 05/10] changelog --- .changelog/28621.txt | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 .changelog/28621.txt diff --git a/.changelog/28621.txt b/.changelog/28621.txt new file mode 100644 index 000000000000..e73f9209efa6 --- /dev/null +++ b/.changelog/28621.txt @@ -0,0 +1,3 @@ +```release-note:enhancement +resource/aws_transfer_server: Add `protocol_details` argument +``` From 4702aa1ac2f153f9e871dbd83c82717ef87f38a3 Mon Sep 17 00:00:00 2001 From: Benny Lu Date: Fri, 30 Dec 2022 21:38:00 -0800 Subject: [PATCH 06/10] Order --- internal/service/transfer/server.go | 42 ++++++++++++++--------------- 1 file changed, 21 insertions(+), 21 deletions(-) diff --git a/internal/service/transfer/server.go b/internal/service/transfer/server.go index a5df7926c19c..00d84f566edc 100644 --- a/internal/service/transfer/server.go +++ b/internal/service/transfer/server.go @@ -165,17 +165,6 @@ func ResourceServer() *schema.Resource { Sensitive: true, ValidateFunc: validation.StringLenBetween(0, 512), }, - "protocols": { - Type: schema.TypeSet, - MinItems: 1, - MaxItems: 3, - Optional: true, - Computed: true, - Elem: &schema.Schema{ - Type: schema.TypeString, - ValidateFunc: validation.StringInSlice(transfer.Protocol_Values(), false), - }, - }, "protocol_details": { Type: schema.TypeList, Optional: true, @@ -207,6 +196,17 @@ func ResourceServer() *schema.Resource { }, }, }, + "protocols": { + Type: schema.TypeSet, + MinItems: 1, + MaxItems: 3, + Optional: true, + Computed: true, + Elem: &schema.Schema{ + Type: schema.TypeString, + ValidateFunc: validation.StringInSlice(transfer.Protocol_Values(), false), + }, + }, "security_policy_name": { Type: schema.TypeString, Optional: true, @@ -324,14 +324,14 @@ func resourceServerCreate(d *schema.ResourceData, meta interface{}) error { input.PreAuthenticationLoginBanner = aws.String(v.(string)) } - if v, ok := d.GetOk("protocols"); ok && v.(*schema.Set).Len() > 0 { - input.Protocols = flex.ExpandStringSet(v.(*schema.Set)) - } - if v, ok := d.GetOk("protocol_details"); ok && len(v.([]interface{})) > 0 { input.ProtocolDetails = expandProtocolDetails(v.([]interface{})) } + if v, ok := d.GetOk("protocols"); ok && v.(*schema.Set).Len() > 0 { + input.Protocols = flex.ExpandStringSet(v.(*schema.Set)) + } + if v, ok := d.GetOk("security_policy_name"); ok { input.SecurityPolicyName = aws.String(v.(string)) } @@ -457,12 +457,12 @@ func resourceServerRead(d *schema.ResourceData, meta interface{}) error { d.Set("logging_role", output.LoggingRole) d.Set("post_authentication_login_banner", output.PostAuthenticationLoginBanner) d.Set("pre_authentication_login_banner", output.PreAuthenticationLoginBanner) - d.Set("protocols", aws.StringValueSlice(output.Protocols)) - + if err := d.Set("protocol_details", flattenProtocolDetails(output.ProtocolDetails)); err != nil { return fmt.Errorf("error setting protocol_details: %w", err) } + d.Set("protocols", aws.StringValueSlice(output.Protocols)) d.Set("security_policy_name", output.SecurityPolicyName) if output.IdentityProviderDetails != nil { d.Set("url", output.IdentityProviderDetails.Url) @@ -639,13 +639,13 @@ func resourceServerUpdate(d *schema.ResourceData, meta interface{}) error { input.PreAuthenticationLoginBanner = aws.String(d.Get("pre_authentication_login_banner").(string)) } - if d.HasChange("protocols") { - input.Protocols = flex.ExpandStringSet(d.Get("protocols").(*schema.Set)) - } - if d.HasChange("protocol_details") { input.ProtocolDetails = expandProtocolDetails(d.Get("protocol_details").([]interface{})) } + + if d.HasChange("protocols") { + input.Protocols = flex.ExpandStringSet(d.Get("protocols").(*schema.Set)) + } if d.HasChange("security_policy_name") { input.SecurityPolicyName = aws.String(d.Get("security_policy_name").(string)) From dd56faa378661fd43cf2b99ddc83ee507372d38b Mon Sep 17 00:00:00 2001 From: Benny Lu Date: Fri, 30 Dec 2022 21:41:52 -0800 Subject: [PATCH 07/10] lint --- internal/service/transfer/server.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/internal/service/transfer/server.go b/internal/service/transfer/server.go index 00d84f566edc..7f835dee3ee1 100644 --- a/internal/service/transfer/server.go +++ b/internal/service/transfer/server.go @@ -457,7 +457,7 @@ func resourceServerRead(d *schema.ResourceData, meta interface{}) error { d.Set("logging_role", output.LoggingRole) d.Set("post_authentication_login_banner", output.PostAuthenticationLoginBanner) d.Set("pre_authentication_login_banner", output.PreAuthenticationLoginBanner) - + if err := d.Set("protocol_details", flattenProtocolDetails(output.ProtocolDetails)); err != nil { return fmt.Errorf("error setting protocol_details: %w", err) } @@ -642,7 +642,7 @@ func resourceServerUpdate(d *schema.ResourceData, meta interface{}) error { if d.HasChange("protocol_details") { input.ProtocolDetails = expandProtocolDetails(d.Get("protocol_details").([]interface{})) } - + if d.HasChange("protocols") { input.Protocols = flex.ExpandStringSet(d.Get("protocols").(*schema.Set)) } From 044dd3f63d02dff39f907cf897505f3823e0c665 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Fri, 3 Mar 2023 13:41:19 -0500 Subject: [PATCH 08/10] r/aws_transfer_server: 'protocol_details' is Computed. Acceptance test output: % make testacc TESTARGS='-run=TestAccTransfer_serial/Server/basic' PKG=transfer ==> Checking that code complies with gofmt requirements... TF_ACC=1 go test ./internal/service/transfer/... -v -count 1 -parallel 20 -run=TestAccTransfer_serial/Server/basic -timeout 180m === RUN TestAccTransfer_serial === PAUSE TestAccTransfer_serial === CONT TestAccTransfer_serial === RUN TestAccTransfer_serial/Server === RUN TestAccTransfer_serial/Server/basic --- PASS: TestAccTransfer_serial (201.82s) --- PASS: TestAccTransfer_serial/Server (201.82s) --- PASS: TestAccTransfer_serial/Server/basic (201.82s) PASS ok github.com/hashicorp/terraform-provider-aws/internal/service/transfer 207.022s % make testacc TESTARGS='-run=TestAccTransfer_serial/Server/ProtocolDetails' PKG=transfer ==> Checking that code complies with gofmt requirements... TF_ACC=1 go test ./internal/service/transfer/... -v -count 1 -parallel 20 -run=TestAccTransfer_serial/Server/ProtocolDetails -timeout 180m === RUN TestAccTransfer_serial === PAUSE TestAccTransfer_serial === CONT TestAccTransfer_serial === RUN TestAccTransfer_serial/Server === RUN TestAccTransfer_serial/Server/ProtocolDetails --- PASS: TestAccTransfer_serial (200.96s) --- PASS: TestAccTransfer_serial/Server (200.96s) --- PASS: TestAccTransfer_serial/Server/ProtocolDetails (200.96s) PASS ok github.com/hashicorp/terraform-provider-aws/internal/service/transfer 206.064s --- internal/service/transfer/server.go | 45 +++++++++++++------- internal/service/transfer/server_test.go | 20 ++++++--- website/docs/r/transfer_server.html.markdown | 5 ++- 3 files changed, 46 insertions(+), 24 deletions(-) diff --git a/internal/service/transfer/server.go b/internal/service/transfer/server.go index c226649fef43..35b3be4d1769 100644 --- a/internal/service/transfer/server.go +++ b/internal/service/transfer/server.go @@ -171,30 +171,37 @@ func ResourceServer() *schema.Resource { "protocol_details": { Type: schema.TypeList, Optional: true, + Computed: true, MaxItems: 1, Elem: &schema.Resource{ Schema: map[string]*schema.Schema{ + "as2_transports": { + Type: schema.TypeSet, + Optional: true, + Computed: true, + MaxItems: 1, + Elem: &schema.Schema{ + Type: schema.TypeString, + ValidateFunc: validation.StringInSlice(transfer.As2Transport_Values(), false), + }, + }, "passive_ip": { Type: schema.TypeString, Optional: true, + Computed: true, ValidateFunc: validation.StringLenBetween(0, 15), }, "set_stat_option": { - Type: schema.TypeString, - Optional: true, - ValidateFunc: validation.StringInSlice([]string{ - "DEFAULT", - "ENABLE_NO_OP", - }, false), + Type: schema.TypeString, + Optional: true, + Computed: true, + ValidateFunc: validation.StringInSlice(transfer.SetStatOption_Values(), false), }, "tls_session_resumption_mode": { - Type: schema.TypeString, - Optional: true, - ValidateFunc: validation.StringInSlice([]string{ - "DISABLED", - "ENABLED", - "ENFORCED", - }, false), + Type: schema.TypeString, + Optional: true, + Computed: true, + ValidateFunc: validation.StringInSlice(transfer.TlsSessionResumptionMode_Values(), false), }, }, }, @@ -479,11 +486,9 @@ func resourceServerRead(ctx context.Context, d *schema.ResourceData, meta interf d.Set("logging_role", output.LoggingRole) d.Set("post_authentication_login_banner", output.PostAuthenticationLoginBanner) d.Set("pre_authentication_login_banner", output.PreAuthenticationLoginBanner) - if err := d.Set("protocol_details", flattenProtocolDetails(output.ProtocolDetails)); err != nil { - return fmt.Errorf("error setting protocol_details: %w", err) + return sdkdiag.AppendErrorf(diags, "setting protocol_details: %s", err) } - d.Set("protocols", aws.StringValueSlice(output.Protocols)) d.Set("security_policy_name", output.SecurityPolicyName) if output.IdentityProviderDetails != nil { @@ -864,6 +869,10 @@ func expandProtocolDetails(m []interface{}) *transfer.ProtocolDetails { apiObject := &transfer.ProtocolDetails{} + if v, ok := tfMap["as2_transports"].(*schema.Set); ok && v.Len() > 0 { + apiObject.As2Transports = flex.ExpandStringSet(v) + } + if v, ok := tfMap["passive_ip"].(string); ok && len(v) > 0 { apiObject.PassiveIp = aws.String(v) } @@ -886,6 +895,10 @@ func flattenProtocolDetails(apiObject *transfer.ProtocolDetails) []interface{} { tfMap := map[string]interface{}{} + if v := apiObject.As2Transports; v != nil { + tfMap["as2_transport"] = aws.StringValueSlice(v) + } + if v := apiObject.PassiveIp; v != nil { tfMap["passive_ip"] = aws.StringValue(v) } diff --git a/internal/service/transfer/server_test.go b/internal/service/transfer/server_test.go index 0be3b05c1975..73724ff3e29e 100644 --- a/internal/service/transfer/server_test.go +++ b/internal/service/transfer/server_test.go @@ -60,6 +60,11 @@ func testAccServer_basic(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "logging_role", ""), resource.TestCheckResourceAttr(resourceName, "post_authentication_login_banner", ""), resource.TestCheckResourceAttr(resourceName, "pre_authentication_login_banner", ""), + resource.TestCheckResourceAttr(resourceName, "protocol_details.#", "1"), + resource.TestCheckResourceAttr(resourceName, "protocol_details.0.as2_transports.#", "0"), + resource.TestCheckResourceAttr(resourceName, "protocol_details.0.passive_ip", "AUTO"), + resource.TestCheckResourceAttr(resourceName, "protocol_details.0.set_stat_option", "DEFAULT"), + resource.TestCheckResourceAttr(resourceName, "protocol_details.0.tls_session_resumption_mode", "ENFORCED"), resource.TestCheckResourceAttr(resourceName, "protocols.#", "1"), resource.TestCheckTypeSetElemAttr(resourceName, "protocols.*", "SFTP"), resource.TestCheckResourceAttr(resourceName, "security_policy_name", "TransferSecurityPolicy-2018-11"), @@ -792,20 +797,22 @@ func testAccServer_protocols(t *testing.T) { } func testAccServer_protocolDetails(t *testing.T) { + ctx := acctest.Context(t) var s transfer.DescribedServer resourceName := "aws_transfer_server.test" resource.Test(t, resource.TestCase{ - PreCheck: func() { acctest.PreCheck(t); testAccPreCheck(t) }, + PreCheck: func() { acctest.PreCheck(t); testAccPreCheck(ctx, t) }, ErrorCheck: acctest.ErrorCheck(t, transfer.EndpointsID), ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, - CheckDestroy: testAccCheckServerDestroy, + CheckDestroy: testAccCheckServerDestroy(ctx), Steps: []resource.TestStep{ { Config: testAccServerConfig_protocolDetails("AUTO", "DEFAULT", "ENFORCED"), Check: resource.ComposeTestCheckFunc( - testAccCheckServerExists(resourceName, &s), + testAccCheckServerExists(ctx, resourceName, &s), resource.TestCheckResourceAttr(resourceName, "protocol_details.#", "1"), + resource.TestCheckResourceAttr(resourceName, "protocol_details.0.as2_transports.#", "0"), resource.TestCheckResourceAttr(resourceName, "protocol_details.0.passive_ip", "AUTO"), resource.TestCheckResourceAttr(resourceName, "protocol_details.0.set_stat_option", "DEFAULT"), resource.TestCheckResourceAttr(resourceName, "protocol_details.0.tls_session_resumption_mode", "ENFORCED"), @@ -818,11 +825,12 @@ func testAccServer_protocolDetails(t *testing.T) { ImportStateVerifyIgnore: []string{"force_destroy"}, }, { - Config: testAccServerConfig_protocolDetails("AUTO", "ENABLE_NO_OP", "DISABLED"), + Config: testAccServerConfig_protocolDetails("8.8.8.8", "ENABLE_NO_OP", "DISABLED"), Check: resource.ComposeTestCheckFunc( - testAccCheckServerExists(resourceName, &s), + testAccCheckServerExists(ctx, resourceName, &s), resource.TestCheckResourceAttr(resourceName, "protocol_details.#", "1"), - resource.TestCheckResourceAttr(resourceName, "protocol_details.0.passive_ip", "AUTO"), + resource.TestCheckResourceAttr(resourceName, "protocol_details.0.as2_transports.#", "0"), + resource.TestCheckResourceAttr(resourceName, "protocol_details.0.passive_ip", "8.8.8.8"), resource.TestCheckResourceAttr(resourceName, "protocol_details.0.set_stat_option", "ENABLE_NO_OP"), resource.TestCheckResourceAttr(resourceName, "protocol_details.0.tls_session_resumption_mode", "DISABLED"), ), diff --git a/website/docs/r/transfer_server.html.markdown b/website/docs/r/transfer_server.html.markdown index a5c881a3fdf8..f06f3be50676 100644 --- a/website/docs/r/transfer_server.html.markdown +++ b/website/docs/r/transfer_server.html.markdown @@ -123,9 +123,10 @@ The following arguments are supported: ### Protocol Details +* `as2_transports` - (Optional) Indicates the transport method for the AS2 messages. Currently, only `HTTP` is supported. * `passive_ip` - (Optional) Indicates passive mode, for FTP and FTPS protocols. Enter a single IPv4 address, such as the public IP address of a firewall, router, or load balancer. -* `set_stat_option` - (Optional) Use to ignore the error that is generated when the client attempts to use `SETSTAT` on a file you are uploading to an S3 bucket. -* `tls_session_resumption_mode` - (Optional) A property used with Transfer Family servers that use the FTPS protocol. Provides a mechanism to resume or share a negotiated secret key between the control and data connection for an FTPS session. +* `set_stat_option` - (Optional) Use to ignore the error that is generated when the client attempts to use `SETSTAT` on a file you are uploading to an S3 bucket. Valid values: `DEFAULT`, `ENABLE_NO_OP`. +* `tls_session_resumption_mode` - (Optional) A property used with Transfer Family servers that use the FTPS protocol. Provides a mechanism to resume or share a negotiated secret key between the control and data connection for an FTPS session. Valid values: `DISABLED`, `ENABLED`, `ENFORCED`. ### Workflow Details From 52ad6cf221036b6428981d61ddbbb68ec37b01e7 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Fri, 3 Mar 2023 14:12:50 -0500 Subject: [PATCH 09/10] Fix providerlint 'S018: schema should use TypeList with MaxItems 1'. --- internal/service/transfer/server.go | 1 - 1 file changed, 1 deletion(-) diff --git a/internal/service/transfer/server.go b/internal/service/transfer/server.go index 35b3be4d1769..fe2f3afe685f 100644 --- a/internal/service/transfer/server.go +++ b/internal/service/transfer/server.go @@ -179,7 +179,6 @@ func ResourceServer() *schema.Resource { Type: schema.TypeSet, Optional: true, Computed: true, - MaxItems: 1, Elem: &schema.Schema{ Type: schema.TypeString, ValidateFunc: validation.StringInSlice(transfer.As2Transport_Values(), false), From c0c6a7e6b73c43715b68ba69cc0a69430fc75d55 Mon Sep 17 00:00:00 2001 From: Kit Ewbank Date: Fri, 3 Mar 2023 15:33:37 -0500 Subject: [PATCH 10/10] Update transfer_server.html.markdown --- website/docs/r/transfer_server.html.markdown | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/website/docs/r/transfer_server.html.markdown b/website/docs/r/transfer_server.html.markdown index f06f3be50676..77a64d2d71da 100644 --- a/website/docs/r/transfer_server.html.markdown +++ b/website/docs/r/transfer_server.html.markdown @@ -99,7 +99,7 @@ The following arguments are supported: * `endpoint_details` - (Optional) The virtual private cloud (VPC) endpoint settings that you want to configure for your SFTP server. Fields documented below. * `endpoint_type` - (Optional) The type of endpoint that you want your SFTP server connect to. If you connect to a `VPC` (or `VPC_ENDPOINT`), your SFTP server isn't accessible over the public internet. If you want to connect your SFTP server via public internet, set `PUBLIC`. Defaults to `PUBLIC`. * `invocation_role` - (Optional) Amazon Resource Name (ARN) of the IAM role used to authenticate the user account with an `identity_provider_type` of `API_GATEWAY`. -* `host_key` - (Optional) RSA private key (e.g., as generated by the `ssh-keygen -N "" -m PEM -f my-new-server-key` command). +* `host_key` - (Optional) RSA, ECDSA, or ED25519 private key (e.g., as generated by the `ssh-keygen -t rsa -b 2048 -N "" -m PEM -f my-new-server-key`, `ssh-keygen -t ecdsa -b 256 -N "" -m PEM -f my-new-server-key` or `ssh-keygen -t ed25519 -N "" -f my-new-server-key` commands). * `url` - (Optional) - URL of the service endpoint used to authenticate users with an `identity_provider_type` of `API_GATEWAY`. * `identity_provider_type` - (Optional) The mode of authentication enabled for this service. The default value is `SERVICE_MANAGED`, which allows you to store and access SFTP user credentials within the service. `API_GATEWAY` indicates that user authentication requires a call to an API Gateway endpoint URL provided by you to integrate an identity provider of your choice. Using `AWS_DIRECTORY_SERVICE` will allow for authentication against AWS Managed Active Directory or Microsoft Active Directory in your on-premises environment, or in AWS using AD Connectors. Use the `AWS_LAMBDA` value to directly use a Lambda function as your identity provider. If you choose this value, you must specify the ARN for the lambda function in the `function` argument. * `directory_id` - (Optional) The directory service ID of the directory service you want to connect to with an `identity_provider_type` of `AWS_DIRECTORY_SERVICE`.