diff --git a/aws/resource_aws_appmesh_route_test.go b/aws/resource_aws_appmesh_route_test.go index 050b5733f41..a091e3be136 100644 --- a/aws/resource_aws_appmesh_route_test.go +++ b/aws/resource_aws_appmesh_route_test.go @@ -113,9 +113,11 @@ func testAccAwsAppmeshRoute_httpRoute(t *testing.T) { Config: testAccAwsAppmeshRouteConfig_httpRoute(rName), Check: resource.ComposeTestCheckFunc( testAccCheckAwsAppmeshRouteExists(resourceName, &r), - resource.TestCheckResourceAttr(resourceName, "name", rName), + testAccCheckResourceAttrRegionalARN(resourceName, "arn", "appmesh-preview", fmt.Sprintf("mesh/%s/virtualRouter/%s/route/%s", rName, rName, rName)), + resource.TestCheckResourceAttrSet(resourceName, "created_date"), + resource.TestCheckResourceAttrSet(resourceName, "last_updated_date"), resource.TestCheckResourceAttr(resourceName, "mesh_name", rName), - resource.TestCheckResourceAttr(resourceName, "virtual_router_name", rName), + resource.TestCheckResourceAttr(resourceName, "name", rName), resource.TestCheckResourceAttr(resourceName, "spec.#", "1"), resource.TestCheckResourceAttr(resourceName, "spec.0.http_route.#", "1"), resource.TestCheckResourceAttr(resourceName, "spec.0.http_route.0.action.#", "1"), @@ -127,18 +129,19 @@ func testAccAwsAppmeshRoute_httpRoute(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "spec.0.http_route.0.match.0.scheme", ""), resource.TestCheckResourceAttr(resourceName, "spec.0.http_route.0.retry_policy.#", "0"), resource.TestCheckResourceAttr(resourceName, "spec.0.tcp_route.#", "0"), - resource.TestCheckResourceAttrSet(resourceName, "created_date"), - resource.TestCheckResourceAttrSet(resourceName, "last_updated_date"), - testAccCheckResourceAttrRegionalARN(resourceName, "arn", "appmesh-preview", fmt.Sprintf("mesh/%s/virtualRouter/%s/route/%s", rName, rName, rName)), + resource.TestCheckResourceAttr(resourceName, "tags.%", "0"), + resource.TestCheckResourceAttr(resourceName, "virtual_router_name", rName), ), }, { Config: testAccAwsAppmeshRouteConfig_httpRouteUpdated(rName), Check: resource.ComposeTestCheckFunc( testAccCheckAwsAppmeshRouteExists(resourceName, &r), - resource.TestCheckResourceAttr(resourceName, "name", rName), + testAccCheckResourceAttrRegionalARN(resourceName, "arn", "appmesh-preview", fmt.Sprintf("mesh/%s/virtualRouter/%s/route/%s", rName, rName, rName)), + resource.TestCheckResourceAttrSet(resourceName, "created_date"), + resource.TestCheckResourceAttrSet(resourceName, "last_updated_date"), resource.TestCheckResourceAttr(resourceName, "mesh_name", rName), - resource.TestCheckResourceAttr(resourceName, "virtual_router_name", rName), + resource.TestCheckResourceAttr(resourceName, "name", rName), resource.TestCheckResourceAttr(resourceName, "spec.#", "1"), resource.TestCheckResourceAttr(resourceName, "spec.0.http_route.#", "1"), resource.TestCheckResourceAttr(resourceName, "spec.0.http_route.0.action.#", "1"), @@ -150,9 +153,8 @@ func testAccAwsAppmeshRoute_httpRoute(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "spec.0.http_route.0.match.0.scheme", ""), resource.TestCheckResourceAttr(resourceName, "spec.0.http_route.0.retry_policy.#", "0"), resource.TestCheckResourceAttr(resourceName, "spec.0.tcp_route.#", "0"), - resource.TestCheckResourceAttrSet(resourceName, "created_date"), - resource.TestCheckResourceAttrSet(resourceName, "last_updated_date"), - testAccCheckResourceAttrRegionalARN(resourceName, "arn", "appmesh-preview", fmt.Sprintf("mesh/%s/virtualRouter/%s/route/%s", rName, rName, rName)), + resource.TestCheckResourceAttr(resourceName, "tags.%", "0"), + resource.TestCheckResourceAttr(resourceName, "virtual_router_name", rName), ), }, { @@ -179,9 +181,11 @@ func testAccAwsAppmeshRoute_httpHeader(t *testing.T) { Config: testAccAwsAppmeshRouteConfig_httpHeader(rName), Check: resource.ComposeTestCheckFunc( testAccCheckAwsAppmeshRouteExists(resourceName, &r), - resource.TestCheckResourceAttr(resourceName, "name", rName), + testAccCheckResourceAttrRegionalARN(resourceName, "arn", "appmesh-preview", fmt.Sprintf("mesh/%s/virtualRouter/%s/route/%s", rName, rName, rName)), + resource.TestCheckResourceAttrSet(resourceName, "created_date"), + resource.TestCheckResourceAttrSet(resourceName, "last_updated_date"), resource.TestCheckResourceAttr(resourceName, "mesh_name", rName), - resource.TestCheckResourceAttr(resourceName, "virtual_router_name", rName), + resource.TestCheckResourceAttr(resourceName, "name", rName), resource.TestCheckResourceAttr(resourceName, "spec.#", "1"), resource.TestCheckResourceAttr(resourceName, "spec.0.http_route.#", "1"), resource.TestCheckResourceAttr(resourceName, "spec.0.http_route.0.action.#", "1"), @@ -196,18 +200,19 @@ func testAccAwsAppmeshRoute_httpHeader(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "spec.0.http_route.0.match.0.scheme", "http"), resource.TestCheckResourceAttr(resourceName, "spec.0.http_route.0.retry_policy.#", "0"), resource.TestCheckResourceAttr(resourceName, "spec.0.tcp_route.#", "0"), - resource.TestCheckResourceAttrSet(resourceName, "created_date"), - resource.TestCheckResourceAttrSet(resourceName, "last_updated_date"), - testAccCheckResourceAttrRegionalARN(resourceName, "arn", "appmesh-preview", fmt.Sprintf("mesh/%s/virtualRouter/%s/route/%s", rName, rName, rName)), + resource.TestCheckResourceAttr(resourceName, "tags.%", "0"), + resource.TestCheckResourceAttr(resourceName, "virtual_router_name", rName), ), }, { Config: testAccAwsAppmeshRouteConfig_httpHeaderUpdated(rName), Check: resource.ComposeTestCheckFunc( testAccCheckAwsAppmeshRouteExists(resourceName, &r), - resource.TestCheckResourceAttr(resourceName, "name", rName), + testAccCheckResourceAttrRegionalARN(resourceName, "arn", "appmesh-preview", fmt.Sprintf("mesh/%s/virtualRouter/%s/route/%s", rName, rName, rName)), + resource.TestCheckResourceAttrSet(resourceName, "created_date"), + resource.TestCheckResourceAttrSet(resourceName, "last_updated_date"), resource.TestCheckResourceAttr(resourceName, "mesh_name", rName), - resource.TestCheckResourceAttr(resourceName, "virtual_router_name", rName), + resource.TestCheckResourceAttr(resourceName, "name", rName), resource.TestCheckResourceAttr(resourceName, "spec.#", "1"), resource.TestCheckResourceAttr(resourceName, "spec.0.http_route.#", "1"), resource.TestCheckResourceAttr(resourceName, "spec.0.http_route.0.action.#", "1"), @@ -232,9 +237,8 @@ func testAccAwsAppmeshRoute_httpHeader(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "spec.0.http_route.0.match.0.scheme", "https"), resource.TestCheckResourceAttr(resourceName, "spec.0.http_route.0.retry_policy.#", "0"), resource.TestCheckResourceAttr(resourceName, "spec.0.tcp_route.#", "0"), - resource.TestCheckResourceAttrSet(resourceName, "created_date"), - resource.TestCheckResourceAttrSet(resourceName, "last_updated_date"), - testAccCheckResourceAttrRegionalARN(resourceName, "arn", "appmesh-preview", fmt.Sprintf("mesh/%s/virtualRouter/%s/route/%s", rName, rName, rName)), + resource.TestCheckResourceAttr(resourceName, "tags.%", "0"), + resource.TestCheckResourceAttr(resourceName, "virtual_router_name", rName), ), }, { @@ -261,9 +265,11 @@ func testAccAwsAppmeshRoute_httpRetryPolicy(t *testing.T) { Config: testAccAwsAppmeshRouteConfig_httpRetryPolicy(rName), Check: resource.ComposeTestCheckFunc( testAccCheckAwsAppmeshRouteExists(resourceName, &r), - resource.TestCheckResourceAttr(resourceName, "name", rName), + testAccCheckResourceAttrRegionalARN(resourceName, "arn", "appmesh-preview", fmt.Sprintf("mesh/%s/virtualRouter/%s/route/%s", rName, rName, rName)), + resource.TestCheckResourceAttrSet(resourceName, "created_date"), + resource.TestCheckResourceAttrSet(resourceName, "last_updated_date"), resource.TestCheckResourceAttr(resourceName, "mesh_name", rName), - resource.TestCheckResourceAttr(resourceName, "virtual_router_name", rName), + resource.TestCheckResourceAttr(resourceName, "name", rName), resource.TestCheckResourceAttr(resourceName, "spec.#", "1"), resource.TestCheckResourceAttr(resourceName, "spec.0.http_route.#", "1"), resource.TestCheckResourceAttr(resourceName, "spec.0.http_route.0.action.#", "1"), @@ -280,18 +286,19 @@ func testAccAwsAppmeshRoute_httpRetryPolicy(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "spec.0.http_route.0.retry_policy.0.per_retry_timeout_millis", "15000"), resource.TestCheckResourceAttr(resourceName, "spec.0.http_route.0.retry_policy.0.tcp_retry_events.#", "0"), resource.TestCheckResourceAttr(resourceName, "spec.0.tcp_route.#", "0"), - resource.TestCheckResourceAttrSet(resourceName, "created_date"), - resource.TestCheckResourceAttrSet(resourceName, "last_updated_date"), - testAccCheckResourceAttrRegionalARN(resourceName, "arn", "appmesh-preview", fmt.Sprintf("mesh/%s/virtualRouter/%s/route/%s", rName, rName, rName)), + resource.TestCheckResourceAttr(resourceName, "tags.%", "0"), + resource.TestCheckResourceAttr(resourceName, "virtual_router_name", rName), ), }, { Config: testAccAwsAppmeshRouteConfig_httpRetryPolicyUpdated(rName), Check: resource.ComposeTestCheckFunc( testAccCheckAwsAppmeshRouteExists(resourceName, &r), - resource.TestCheckResourceAttr(resourceName, "name", rName), + testAccCheckResourceAttrRegionalARN(resourceName, "arn", "appmesh-preview", fmt.Sprintf("mesh/%s/virtualRouter/%s/route/%s", rName, rName, rName)), + resource.TestCheckResourceAttrSet(resourceName, "created_date"), + resource.TestCheckResourceAttrSet(resourceName, "last_updated_date"), resource.TestCheckResourceAttr(resourceName, "mesh_name", rName), - resource.TestCheckResourceAttr(resourceName, "virtual_router_name", rName), + resource.TestCheckResourceAttr(resourceName, "name", rName), resource.TestCheckResourceAttr(resourceName, "spec.#", "1"), resource.TestCheckResourceAttr(resourceName, "spec.0.http_route.#", "1"), resource.TestCheckResourceAttr(resourceName, "spec.0.http_route.0.action.#", "1"), @@ -310,9 +317,8 @@ func testAccAwsAppmeshRoute_httpRetryPolicy(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "spec.0.http_route.0.retry_policy.0.tcp_retry_events.#", "1"), resource.TestCheckResourceAttr(resourceName, "spec.0.http_route.0.retry_policy.0.tcp_retry_events.3724400910", "connection-error"), resource.TestCheckResourceAttr(resourceName, "spec.0.tcp_route.#", "0"), - resource.TestCheckResourceAttrSet(resourceName, "created_date"), - resource.TestCheckResourceAttrSet(resourceName, "last_updated_date"), - testAccCheckResourceAttrRegionalARN(resourceName, "arn", "appmesh-preview", fmt.Sprintf("mesh/%s/virtualRouter/%s/route/%s", rName, rName, rName)), + resource.TestCheckResourceAttr(resourceName, "tags.%", "0"), + resource.TestCheckResourceAttr(resourceName, "virtual_router_name", rName), ), }, { @@ -347,6 +353,7 @@ func testAccAwsAppmeshRoute_tcpRoute(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "spec.0.tcp_route.#", "1"), resource.TestCheckResourceAttr(resourceName, "spec.0.tcp_route.0.action.#", "1"), resource.TestCheckResourceAttr(resourceName, "spec.0.tcp_route.0.action.0.weighted_target.#", "1"), + resource.TestCheckResourceAttr(resourceName, "tags.%", "0"), resource.TestCheckResourceAttrSet(resourceName, "created_date"), resource.TestCheckResourceAttrSet(resourceName, "last_updated_date"), testAccCheckResourceAttrRegionalARN(resourceName, "arn", "appmesh-preview", fmt.Sprintf("mesh/%s/virtualRouter/%s/route/%s", rName, rName, rName)), @@ -364,6 +371,7 @@ func testAccAwsAppmeshRoute_tcpRoute(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "spec.0.tcp_route.#", "1"), resource.TestCheckResourceAttr(resourceName, "spec.0.tcp_route.0.action.#", "1"), resource.TestCheckResourceAttr(resourceName, "spec.0.tcp_route.0.action.0.weighted_target.#", "2"), + resource.TestCheckResourceAttr(resourceName, "tags.%", "0"), resource.TestCheckResourceAttrSet(resourceName, "created_date"), resource.TestCheckResourceAttrSet(resourceName, "last_updated_date"), testAccCheckResourceAttrRegionalARN(resourceName, "arn", "appmesh-preview", fmt.Sprintf("mesh/%s/virtualRouter/%s/route/%s", rName, rName, rName)), @@ -498,7 +506,7 @@ func testAccAwsAppmeshRouteImportStateIdFunc(resourceName string) resource.Impor } } -func testAccAwsAppmeshRouteConfigBase(rName string) string { +func testAccAwsAppmeshRouteConfig_base(rName string) string { return fmt.Sprintf(` resource "aws_appmesh_mesh" "test" { name = %[1]q @@ -530,7 +538,7 @@ resource "aws_appmesh_virtual_node" "test" { } func testAccAwsAppmeshRouteConfig_httpRoute(rName string) string { - return testAccAwsAppmeshRouteConfigBase(rName) + fmt.Sprintf(` + return testAccAwsAppmeshRouteConfig_base(rName) + fmt.Sprintf(` resource "aws_appmesh_route" "test" { name = %[1]q mesh_name = "${aws_appmesh_mesh.test.id}" @@ -555,7 +563,7 @@ resource "aws_appmesh_route" "test" { } func testAccAwsAppmeshRouteConfig_httpRouteUpdated(rName string) string { - return testAccAwsAppmeshRouteConfigBase(rName) + fmt.Sprintf(` + return testAccAwsAppmeshRouteConfig_base(rName) + fmt.Sprintf(` resource "aws_appmesh_route" "test" { name = %[1]q mesh_name = "${aws_appmesh_mesh.test.id}" @@ -585,7 +593,7 @@ resource "aws_appmesh_route" "test" { } func testAccAwsAppmeshRouteConfig_httpHeader(rName string) string { - return testAccAwsAppmeshRouteConfigBase(rName) + fmt.Sprintf(` + return testAccAwsAppmeshRouteConfig_base(rName) + fmt.Sprintf(` resource "aws_appmesh_route" "test" { name = %[1]q mesh_name = "${aws_appmesh_mesh.test.id}" @@ -616,7 +624,7 @@ resource "aws_appmesh_route" "test" { } func testAccAwsAppmeshRouteConfig_httpHeaderUpdated(rName string) string { - return testAccAwsAppmeshRouteConfigBase(rName) + fmt.Sprintf(` + return testAccAwsAppmeshRouteConfig_base(rName) + fmt.Sprintf(` resource "aws_appmesh_route" "test" { name = %[1]q mesh_name = "${aws_appmesh_mesh.test.id}" @@ -659,7 +667,7 @@ resource "aws_appmesh_route" "test" { } func testAccAwsAppmeshRouteConfig_httpRetryPolicy(rName string) string { - return testAccAwsAppmeshRouteConfigBase(rName) + fmt.Sprintf(` + return testAccAwsAppmeshRouteConfig_base(rName) + fmt.Sprintf(` resource "aws_appmesh_route" "test" { name = %[1]q mesh_name = "${aws_appmesh_mesh.test.id}" @@ -690,7 +698,7 @@ resource "aws_appmesh_route" "test" { } func testAccAwsAppmeshRouteConfig_httpRetryPolicyUpdated(rName string) string { - return testAccAwsAppmeshRouteConfigBase(rName) + fmt.Sprintf(` + return testAccAwsAppmeshRouteConfig_base(rName) + fmt.Sprintf(` resource "aws_appmesh_route" "test" { name = %[1]q mesh_name = "${aws_appmesh_mesh.test.id}" @@ -729,7 +737,7 @@ resource "aws_appmesh_route" "test" { } func testAccAwsAppmeshRouteConfig_tcpRoute(rName string) string { - return testAccAwsAppmeshRouteConfigBase(rName) + fmt.Sprintf(` + return testAccAwsAppmeshRouteConfig_base(rName) + fmt.Sprintf(` resource "aws_appmesh_route" "test" { name = %[1]q mesh_name = "${aws_appmesh_mesh.test.id}" @@ -750,7 +758,7 @@ resource "aws_appmesh_route" "test" { } func testAccAwsAppmeshRouteConfig_tcpRouteUpdated(rName string) string { - return testAccAwsAppmeshRouteConfigBase(rName) + fmt.Sprintf(` + return testAccAwsAppmeshRouteConfig_base(rName) + fmt.Sprintf(` resource "aws_appmesh_route" "test" { name = %[1]q mesh_name = "${aws_appmesh_mesh.test.id}" diff --git a/aws/resource_aws_appmesh_test.go b/aws/resource_aws_appmesh_test.go index 325929669a6..d9e950fff65 100644 --- a/aws/resource_aws_appmesh_test.go +++ b/aws/resource_aws_appmesh_test.go @@ -22,6 +22,7 @@ func TestAccAWSAppmesh(t *testing.T) { "basic": testAccAwsAppmeshVirtualNode_basic, "cloudMapServiceDiscovery": testAccAwsAppmeshVirtualNode_cloudMapServiceDiscovery, "listenerHealthChecks": testAccAwsAppmeshVirtualNode_listenerHealthChecks, + "listenerTls": testAccAwsAppmeshVirtualNode_listenerTls, "logging": testAccAwsAppmeshVirtualNode_logging, // "tags": testAccAwsAppmeshVirtualNode_tags, }, diff --git a/aws/resource_aws_appmesh_virtual_node.go b/aws/resource_aws_appmesh_virtual_node.go index 2ec61fca962..289b711c16e 100644 --- a/aws/resource_aws_appmesh_virtual_node.go +++ b/aws/resource_aws_appmesh_virtual_node.go @@ -185,6 +185,52 @@ func resourceAwsAppmeshVirtualNode() *schema.Resource { }, }, }, + + "tls": { + Type: schema.TypeList, + Optional: true, + MinItems: 0, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "certificate": { + Type: schema.TypeList, + Required: true, + MinItems: 1, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "acm": { + Type: schema.TypeList, + Optional: true, + MinItems: 0, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "certificate_arn": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validateArn, + }, + }, + }, + }, + }, + }, + }, + + "mode": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringInSlice([]string{ + appmesh.ListenerTlsModeDisabled, + appmesh.ListenerTlsModePermissive, + appmesh.ListenerTlsModeStrict, + }, false), + }, + }, + }, + }, }, }, Set: appmeshListenerHash, @@ -459,10 +505,11 @@ func expandAppmeshVirtualNodeSpec(vSpec []interface{}) *appmesh.VirtualNodeSpec backend.VirtualService = &appmesh.VirtualServiceBackend{} - if vVirtualServiceName, ok := mVirtualService["virtual_service_name"].(string); ok { + if vVirtualServiceName, ok := mVirtualService["virtual_service_name"].(string); ok && vVirtualServiceName != "" { backend.VirtualService.VirtualServiceName = aws.String(vVirtualServiceName) } } + backends = append(backends, backend) } @@ -480,42 +527,74 @@ func expandAppmeshVirtualNodeSpec(vSpec []interface{}) *appmesh.VirtualNodeSpec if vHealthCheck, ok := mListener["health_check"].([]interface{}); ok && len(vHealthCheck) > 0 && vHealthCheck[0] != nil { mHealthCheck := vHealthCheck[0].(map[string]interface{}) - listener.HealthCheck = &appmesh.HealthCheckPolicy{} + healthCheck := &appmesh.HealthCheckPolicy{} if vHealthyThreshold, ok := mHealthCheck["healthy_threshold"].(int); ok && vHealthyThreshold > 0 { - listener.HealthCheck.HealthyThreshold = aws.Int64(int64(vHealthyThreshold)) + healthCheck.HealthyThreshold = aws.Int64(int64(vHealthyThreshold)) } if vIntervalMillis, ok := mHealthCheck["interval_millis"].(int); ok && vIntervalMillis > 0 { - listener.HealthCheck.IntervalMillis = aws.Int64(int64(vIntervalMillis)) + healthCheck.IntervalMillis = aws.Int64(int64(vIntervalMillis)) } if vPath, ok := mHealthCheck["path"].(string); ok && vPath != "" { - listener.HealthCheck.Path = aws.String(vPath) + healthCheck.Path = aws.String(vPath) } if vPort, ok := mHealthCheck["port"].(int); ok && vPort > 0 { - listener.HealthCheck.Port = aws.Int64(int64(vPort)) + healthCheck.Port = aws.Int64(int64(vPort)) } if vProtocol, ok := mHealthCheck["protocol"].(string); ok && vProtocol != "" { - listener.HealthCheck.Protocol = aws.String(vProtocol) + healthCheck.Protocol = aws.String(vProtocol) } if vTimeoutMillis, ok := mHealthCheck["timeout_millis"].(int); ok && vTimeoutMillis > 0 { - listener.HealthCheck.TimeoutMillis = aws.Int64(int64(vTimeoutMillis)) + healthCheck.TimeoutMillis = aws.Int64(int64(vTimeoutMillis)) } if vUnhealthyThreshold, ok := mHealthCheck["unhealthy_threshold"].(int); ok && vUnhealthyThreshold > 0 { - listener.HealthCheck.UnhealthyThreshold = aws.Int64(int64(vUnhealthyThreshold)) + healthCheck.UnhealthyThreshold = aws.Int64(int64(vUnhealthyThreshold)) } + + listener.HealthCheck = healthCheck } if vPortMapping, ok := mListener["port_mapping"].([]interface{}); ok && len(vPortMapping) > 0 && vPortMapping[0] != nil { mPortMapping := vPortMapping[0].(map[string]interface{}) - listener.PortMapping = &appmesh.PortMapping{} + portMapping := &appmesh.PortMapping{} if vPort, ok := mPortMapping["port"].(int); ok && vPort > 0 { - listener.PortMapping.Port = aws.Int64(int64(vPort)) + portMapping.Port = aws.Int64(int64(vPort)) } if vProtocol, ok := mPortMapping["protocol"].(string); ok && vProtocol != "" { - listener.PortMapping.Protocol = aws.String(vProtocol) + portMapping.Protocol = aws.String(vProtocol) + } + + listener.PortMapping = portMapping + } + + if vTls, ok := mListener["tls"].([]interface{}); ok && len(vTls) > 0 && vTls[0] != nil { + mTls := vTls[0].(map[string]interface{}) + + tls := &appmesh.ListenerTls{} + + if vMode, ok := mTls["mode"].(string); ok && vMode != "" { + tls.Mode = aws.String(vMode) + } + + if vCertificate, ok := mTls["certificate"].([]interface{}); ok && len(vCertificate) > 0 && vCertificate[0] != nil { + mCertificate := vCertificate[0].(map[string]interface{}) + + if vAcm, ok := mCertificate["acm"].([]interface{}); ok && len(vAcm) > 0 && vAcm[0] != nil { + mAcm := vAcm[0].(map[string]interface{}) + + if vCertificateArn, ok := mAcm["certificate_arn"].(string); ok && vCertificateArn != "" { + tls.Certificate = &appmesh.ListenerTlsCertificate{ + Acm: &appmesh.ListenerTlsAcmCertificate{ + CertificateArn: aws.String(vCertificateArn), + }, + } + } + } } + + listener.Tls = tls } listeners = append(listeners, listener) @@ -552,10 +631,17 @@ func expandAppmeshVirtualNodeSpec(vSpec []interface{}) *appmesh.VirtualNodeSpec mServiceDiscovery := vServiceDiscovery[0].(map[string]interface{}) if vAwsCloudMap, ok := mServiceDiscovery["aws_cloud_map"].([]interface{}); ok && len(vAwsCloudMap) > 0 && vAwsCloudMap[0] != nil { - spec.ServiceDiscovery.AwsCloudMap = &appmesh.AwsCloudMapServiceDiscovery{} + awsCloudMap := &appmesh.AwsCloudMapServiceDiscovery{} mAwsCloudMap := vAwsCloudMap[0].(map[string]interface{}) + if vNamespaceName, ok := mAwsCloudMap["namespace_name"].(string); ok && vNamespaceName != "" { + awsCloudMap.NamespaceName = aws.String(vNamespaceName) + } + if vServiceName, ok := mAwsCloudMap["service_name"].(string); ok && vServiceName != "" { + awsCloudMap.ServiceName = aws.String(vServiceName) + } + if vAttributes, ok := mAwsCloudMap["attributes"].(map[string]interface{}); ok && len(vAttributes) > 0 { attributes := []*appmesh.AwsCloudMapInstanceAttribute{} @@ -566,14 +652,10 @@ func expandAppmeshVirtualNodeSpec(vSpec []interface{}) *appmesh.VirtualNodeSpec }) } - spec.ServiceDiscovery.AwsCloudMap.Attributes = attributes - } - if vNamespaceName, ok := mAwsCloudMap["namespace_name"].(string); ok && vNamespaceName != "" { - spec.ServiceDiscovery.AwsCloudMap.NamespaceName = aws.String(vNamespaceName) - } - if vServiceName, ok := mAwsCloudMap["service_name"].(string); ok && vServiceName != "" { - spec.ServiceDiscovery.AwsCloudMap.ServiceName = aws.String(vServiceName) + awsCloudMap.Attributes = attributes } + + spec.ServiceDiscovery.AwsCloudMap = awsCloudMap } if vDns, ok := mServiceDiscovery["dns"].([]interface{}); ok && len(vDns) > 0 && vDns[0] != nil { @@ -597,17 +679,18 @@ func flattenAppmeshVirtualNodeSpec(spec *appmesh.VirtualNodeSpec) []interface{} mSpec := map[string]interface{}{} - if spec.Backends != nil { + if backends := spec.Backends; backends != nil { vBackends := []interface{}{} - for _, backend := range spec.Backends { + for _, backend := range backends { mBackend := map[string]interface{}{} - if backend.VirtualService != nil { - mVirtualService := map[string]interface{}{ - "virtual_service_name": aws.StringValue(backend.VirtualService.VirtualServiceName), + if virtualService := backend.VirtualService; virtualService != nil { + mBackend["virtual_service"] = []interface{}{ + map[string]interface{}{ + "virtual_service_name": aws.StringValue(virtualService.VirtualServiceName), + }, } - mBackend["virtual_service"] = []interface{}{mVirtualService} } vBackends = append(vBackends, mBackend) @@ -616,31 +699,55 @@ func flattenAppmeshVirtualNodeSpec(spec *appmesh.VirtualNodeSpec) []interface{} mSpec["backend"] = schema.NewSet(appmeshBackendHash, vBackends) } - if spec.Listeners != nil { + if listeners := spec.Listeners; listeners != nil { vListeners := []interface{}{} - for _, listener := range spec.Listeners { + for _, listener := range listeners { mListener := map[string]interface{}{} - if listener.HealthCheck != nil { - mHealthCheck := map[string]interface{}{ - "healthy_threshold": int(aws.Int64Value(listener.HealthCheck.HealthyThreshold)), - "interval_millis": int(aws.Int64Value(listener.HealthCheck.IntervalMillis)), - "path": aws.StringValue(listener.HealthCheck.Path), - "port": int(aws.Int64Value(listener.HealthCheck.Port)), - "protocol": aws.StringValue(listener.HealthCheck.Protocol), - "timeout_millis": int(aws.Int64Value(listener.HealthCheck.TimeoutMillis)), - "unhealthy_threshold": int(aws.Int64Value(listener.HealthCheck.UnhealthyThreshold)), + if healthCheck := listener.HealthCheck; healthCheck != nil { + mListener["health_check"] = []interface{}{ + map[string]interface{}{ + "healthy_threshold": int(aws.Int64Value(healthCheck.HealthyThreshold)), + "interval_millis": int(aws.Int64Value(healthCheck.IntervalMillis)), + "path": aws.StringValue(healthCheck.Path), + "port": int(aws.Int64Value(healthCheck.Port)), + "protocol": aws.StringValue(healthCheck.Protocol), + "timeout_millis": int(aws.Int64Value(healthCheck.TimeoutMillis)), + "unhealthy_threshold": int(aws.Int64Value(healthCheck.UnhealthyThreshold)), + }, } - mListener["health_check"] = []interface{}{mHealthCheck} } - if listener.PortMapping != nil { - mPortMapping := map[string]interface{}{ - "port": int(aws.Int64Value(listener.PortMapping.Port)), - "protocol": aws.StringValue(listener.PortMapping.Protocol), + if portMapping := listener.PortMapping; portMapping != nil { + mListener["port_mapping"] = []interface{}{ + map[string]interface{}{ + "port": int(aws.Int64Value(portMapping.Port)), + "protocol": aws.StringValue(portMapping.Protocol), + }, } - mListener["port_mapping"] = []interface{}{mPortMapping} + } + + if tls := listener.Tls; tls != nil { + mTls := map[string]interface{}{ + "mode": aws.StringValue(tls.Mode), + } + + if certificate := tls.Certificate; certificate != nil { + if acm := certificate.Acm; acm != nil { + mTls["certificate"] = []interface{}{ + map[string]interface{}{ + "acm": []interface{}{ + map[string]interface{}{ + "certificate_arn": aws.StringValue(acm.CertificateArn), + }, + }, + }, + } + } + } + + mListener["tls"] = []interface{}{mTls} } vListeners = append(vListeners, mListener) @@ -649,45 +756,49 @@ func flattenAppmeshVirtualNodeSpec(spec *appmesh.VirtualNodeSpec) []interface{} mSpec["listener"] = schema.NewSet(appmeshListenerHash, vListeners) } - if spec.Logging != nil && spec.Logging.AccessLog != nil && spec.Logging.AccessLog.File != nil { - mSpec["logging"] = []interface{}{ - map[string]interface{}{ - "access_log": []interface{}{ + if logging := spec.Logging; logging != nil { + if accessLog := logging.AccessLog; accessLog != nil { + if file := accessLog.File; file != nil { + mSpec["logging"] = []interface{}{ map[string]interface{}{ - "file": []interface{}{ + "access_log": []interface{}{ map[string]interface{}{ - "path": aws.StringValue(spec.Logging.AccessLog.File.Path), + "file": []interface{}{ + map[string]interface{}{ + "path": aws.StringValue(file.Path), + }, + }, }, }, }, - }, - }, + } + } } } - if spec.ServiceDiscovery != nil { + if serviceDiscovery := spec.ServiceDiscovery; serviceDiscovery != nil { mServiceDiscovery := map[string]interface{}{} - if spec.ServiceDiscovery.AwsCloudMap != nil { + if awsCloudMap := serviceDiscovery.AwsCloudMap; awsCloudMap != nil { vAttributes := map[string]interface{}{} - for _, attribute := range spec.ServiceDiscovery.AwsCloudMap.Attributes { + for _, attribute := range awsCloudMap.Attributes { vAttributes[aws.StringValue(attribute.Key)] = aws.StringValue(attribute.Value) } mServiceDiscovery["aws_cloud_map"] = []interface{}{ map[string]interface{}{ "attributes": vAttributes, - "namespace_name": aws.StringValue(spec.ServiceDiscovery.AwsCloudMap.NamespaceName), - "service_name": aws.StringValue(spec.ServiceDiscovery.AwsCloudMap.ServiceName), + "namespace_name": aws.StringValue(awsCloudMap.NamespaceName), + "service_name": aws.StringValue(awsCloudMap.ServiceName), }, } } - if spec.ServiceDiscovery.Dns != nil { + if dns := serviceDiscovery.Dns; dns != nil { mServiceDiscovery["dns"] = []interface{}{ map[string]interface{}{ - "hostname": aws.StringValue(spec.ServiceDiscovery.Dns.Hostname), + "hostname": aws.StringValue(dns.Hostname), }, } } @@ -745,5 +856,20 @@ func appmeshListenerHash(vListener interface{}) int { buf.WriteString(fmt.Sprintf("%s-", v)) } } + if vTls, ok := mListener["tls"].([]interface{}); ok && len(vTls) > 0 && vTls[0] != nil { + mTls := vTls[0].(map[string]interface{}) + if vCertificate, ok := mTls["certificate"].([]interface{}); ok && len(vCertificate) > 0 && vCertificate[0] != nil { + mCertificate := vCertificate[0].(map[string]interface{}) + if vAcm, ok := mCertificate["acm"].([]interface{}); ok && len(vAcm) > 0 && vAcm[0] != nil { + mAcm := vAcm[0].(map[string]interface{}) + if v, ok := mAcm["certificate_arn"].(string); ok { + buf.WriteString(fmt.Sprintf("%s-", v)) + } + } + } + if v, ok := mTls["mode"].(string); ok { + buf.WriteString(fmt.Sprintf("%s-", v)) + } + } return hashcode.String(buf.String()) } diff --git a/aws/resource_aws_appmesh_virtual_node_test.go b/aws/resource_aws_appmesh_virtual_node_test.go index e19bbedd21c..5a416b118a7 100644 --- a/aws/resource_aws_appmesh_virtual_node_test.go +++ b/aws/resource_aws_appmesh_virtual_node_test.go @@ -2,7 +2,6 @@ package aws import ( "fmt" - "regexp" "testing" "github.com/aws/aws-sdk-go/aws" @@ -15,8 +14,7 @@ import ( func testAccAwsAppmeshVirtualNode_basic(t *testing.T) { var vn appmesh.VirtualNodeData resourceName := "aws_appmesh_virtual_node.test" - meshName := fmt.Sprintf("tf-test-mesh-%d", acctest.RandInt()) - vnName := fmt.Sprintf("tf-test-node-%d", acctest.RandInt()) + rName := fmt.Sprintf("tf-testacc-appmesh-%s", acctest.RandStringFromCharSet(13, acctest.CharSetAlphaNum)) resource.Test(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, @@ -24,24 +22,25 @@ func testAccAwsAppmeshVirtualNode_basic(t *testing.T) { CheckDestroy: testAccCheckAppmeshVirtualNodeDestroy, Steps: []resource.TestStep{ { - Config: testAccAppmeshVirtualNodeConfig_basic(meshName, vnName), + Config: testAccAppmeshVirtualNodeConfig_basic(rName), Check: resource.ComposeTestCheckFunc( testAccCheckAppmeshVirtualNodeExists(resourceName, &vn), - resource.TestCheckResourceAttr(resourceName, "name", vnName), - resource.TestCheckResourceAttr(resourceName, "mesh_name", meshName), + testAccCheckResourceAttrRegionalARN(resourceName, "arn", "appmesh-preview", fmt.Sprintf("mesh/%s/virtualNode/%s", rName, rName)), + resource.TestCheckResourceAttrSet(resourceName, "created_date"), + resource.TestCheckResourceAttrSet(resourceName, "last_updated_date"), + resource.TestCheckResourceAttr(resourceName, "mesh_name", rName), + resource.TestCheckResourceAttr(resourceName, "name", rName), resource.TestCheckResourceAttr(resourceName, "spec.#", "1"), resource.TestCheckResourceAttr(resourceName, "spec.0.backend.#", "0"), resource.TestCheckResourceAttr(resourceName, "spec.0.listener.#", "0"), resource.TestCheckResourceAttr(resourceName, "spec.0.logging.#", "0"), resource.TestCheckResourceAttr(resourceName, "spec.0.service_discovery.#", "0"), - resource.TestCheckResourceAttrSet(resourceName, "created_date"), - resource.TestCheckResourceAttrSet(resourceName, "last_updated_date"), - resource.TestMatchResourceAttr(resourceName, "arn", regexp.MustCompile(fmt.Sprintf("^arn:[^:]+:appmesh-preview:[^:]+:\\d{12}:mesh/%s/virtualNode/%s", meshName, vnName))), + resource.TestCheckResourceAttr(resourceName, "tags.%", "0"), ), }, { ResourceName: resourceName, - ImportStateId: fmt.Sprintf("%s/%s", meshName, vnName), + ImportStateIdFunc: testAccAwsAppmeshVirtualNodeImportStateIdFunc(resourceName), ImportState: true, ImportStateVerify: true, }, @@ -53,9 +52,7 @@ func testAccAwsAppmeshVirtualNode_cloudMapServiceDiscovery(t *testing.T) { var vn appmesh.VirtualNodeData resourceName := "aws_appmesh_virtual_node.test" nsResourceName := "aws_service_discovery_http_namespace.test" - meshName := fmt.Sprintf("tf-test-mesh-%d", acctest.RandInt()) - vnName := fmt.Sprintf("tf-test-node-%d", acctest.RandInt()) - rName := fmt.Sprintf("tf-testacc-appmeshvn-%s", acctest.RandStringFromCharSet(11, acctest.CharSetAlphaNum)) + rName := fmt.Sprintf("tf-testacc-appmesh-%s", acctest.RandStringFromCharSet(13, acctest.CharSetAlphaNum)) resource.Test(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, @@ -63,38 +60,66 @@ func testAccAwsAppmeshVirtualNode_cloudMapServiceDiscovery(t *testing.T) { CheckDestroy: testAccCheckAppmeshVirtualNodeDestroy, Steps: []resource.TestStep{ { - Config: testAccAppmeshVirtualNodeConfig_cloudMapServiceDiscovery(meshName, vnName, rName, "Key1", "Value1"), + Config: testAccAppmeshVirtualNodeConfig_cloudMapServiceDiscovery(rName, "Key1", "Value1"), Check: resource.ComposeTestCheckFunc( testAccCheckAppmeshVirtualNodeExists(resourceName, &vn), - resource.TestCheckResourceAttr(resourceName, "name", vnName), - resource.TestCheckResourceAttr(resourceName, "mesh_name", meshName), + testAccCheckResourceAttrRegionalARN(resourceName, "arn", "appmesh-preview", fmt.Sprintf("mesh/%s/virtualNode/%s", rName, rName)), + resource.TestCheckResourceAttrSet(resourceName, "created_date"), + resource.TestCheckResourceAttrSet(resourceName, "last_updated_date"), + resource.TestCheckResourceAttr(resourceName, "mesh_name", rName), + resource.TestCheckResourceAttr(resourceName, "name", rName), resource.TestCheckResourceAttr(resourceName, "spec.#", "1"), + resource.TestCheckResourceAttr(resourceName, "spec.0.backend.#", "1"), + resource.TestCheckResourceAttr(resourceName, "spec.0.backend.2622272660.virtual_service.#", "1"), + resource.TestCheckResourceAttr(resourceName, "spec.0.backend.2622272660.virtual_service.0.virtual_service_name", "servicea.simpleapp.local"), + resource.TestCheckResourceAttr(resourceName, "spec.0.listener.#", "1"), + resource.TestCheckResourceAttr(resourceName, "spec.0.listener.2279702354.health_check.#", "0"), + resource.TestCheckResourceAttr(resourceName, "spec.0.listener.2279702354.port_mapping.#", "1"), + resource.TestCheckResourceAttr(resourceName, "spec.0.listener.2279702354.port_mapping.0.port", "8080"), + resource.TestCheckResourceAttr(resourceName, "spec.0.listener.2279702354.port_mapping.0.protocol", "http"), + resource.TestCheckResourceAttr(resourceName, "spec.0.listener.2279702354.tls.#", "0"), + resource.TestCheckResourceAttr(resourceName, "spec.0.logging.#", "0"), resource.TestCheckResourceAttr(resourceName, "spec.0.service_discovery.#", "1"), resource.TestCheckResourceAttr(resourceName, "spec.0.service_discovery.0.aws_cloud_map.#", "1"), resource.TestCheckResourceAttr(resourceName, "spec.0.service_discovery.0.aws_cloud_map.0.attributes.%", "1"), resource.TestCheckResourceAttr(resourceName, "spec.0.service_discovery.0.aws_cloud_map.0.attributes.Key1", "Value1"), resource.TestCheckResourceAttrPair(resourceName, "spec.0.service_discovery.0.aws_cloud_map.0.namespace_name", nsResourceName, "name"), resource.TestCheckResourceAttr(resourceName, "spec.0.service_discovery.0.aws_cloud_map.0.service_name", rName), + resource.TestCheckResourceAttr(resourceName, "tags.%", "0"), ), }, { - Config: testAccAppmeshVirtualNodeConfig_cloudMapServiceDiscovery(meshName, vnName, rName, "Key1", "Value2"), + Config: testAccAppmeshVirtualNodeConfig_cloudMapServiceDiscovery(rName, "Key1", "Value2"), Check: resource.ComposeTestCheckFunc( testAccCheckAppmeshVirtualNodeExists(resourceName, &vn), - resource.TestCheckResourceAttr(resourceName, "name", vnName), - resource.TestCheckResourceAttr(resourceName, "mesh_name", meshName), + testAccCheckResourceAttrRegionalARN(resourceName, "arn", "appmesh-preview", fmt.Sprintf("mesh/%s/virtualNode/%s", rName, rName)), + resource.TestCheckResourceAttrSet(resourceName, "created_date"), + resource.TestCheckResourceAttrSet(resourceName, "last_updated_date"), + resource.TestCheckResourceAttr(resourceName, "mesh_name", rName), + resource.TestCheckResourceAttr(resourceName, "name", rName), resource.TestCheckResourceAttr(resourceName, "spec.#", "1"), + resource.TestCheckResourceAttr(resourceName, "spec.0.backend.#", "1"), + resource.TestCheckResourceAttr(resourceName, "spec.0.backend.2622272660.virtual_service.#", "1"), + resource.TestCheckResourceAttr(resourceName, "spec.0.backend.2622272660.virtual_service.0.virtual_service_name", "servicea.simpleapp.local"), + resource.TestCheckResourceAttr(resourceName, "spec.0.listener.#", "1"), + resource.TestCheckResourceAttr(resourceName, "spec.0.listener.2279702354.health_check.#", "0"), + resource.TestCheckResourceAttr(resourceName, "spec.0.listener.2279702354.port_mapping.#", "1"), + resource.TestCheckResourceAttr(resourceName, "spec.0.listener.2279702354.port_mapping.0.port", "8080"), + resource.TestCheckResourceAttr(resourceName, "spec.0.listener.2279702354.port_mapping.0.protocol", "http"), + resource.TestCheckResourceAttr(resourceName, "spec.0.listener.2279702354.tls.#", "0"), + resource.TestCheckResourceAttr(resourceName, "spec.0.logging.#", "0"), resource.TestCheckResourceAttr(resourceName, "spec.0.service_discovery.#", "1"), resource.TestCheckResourceAttr(resourceName, "spec.0.service_discovery.0.aws_cloud_map.#", "1"), resource.TestCheckResourceAttr(resourceName, "spec.0.service_discovery.0.aws_cloud_map.0.attributes.%", "1"), resource.TestCheckResourceAttr(resourceName, "spec.0.service_discovery.0.aws_cloud_map.0.attributes.Key1", "Value2"), resource.TestCheckResourceAttrPair(resourceName, "spec.0.service_discovery.0.aws_cloud_map.0.namespace_name", nsResourceName, "name"), resource.TestCheckResourceAttr(resourceName, "spec.0.service_discovery.0.aws_cloud_map.0.service_name", rName), + resource.TestCheckResourceAttr(resourceName, "tags.%", "0"), ), }, { ResourceName: resourceName, - ImportStateId: fmt.Sprintf("%s/%s", meshName, vnName), + ImportStateIdFunc: testAccAwsAppmeshVirtualNodeImportStateIdFunc(resourceName), ImportState: true, ImportStateVerify: true, }, @@ -105,8 +130,7 @@ func testAccAwsAppmeshVirtualNode_cloudMapServiceDiscovery(t *testing.T) { func testAccAwsAppmeshVirtualNode_listenerHealthChecks(t *testing.T) { var vn appmesh.VirtualNodeData resourceName := "aws_appmesh_virtual_node.test" - meshName := fmt.Sprintf("tf-test-mesh-%d", acctest.RandInt()) - vnName := fmt.Sprintf("tf-test-node-%d", acctest.RandInt()) + rName := fmt.Sprintf("tf-testacc-appmesh-%s", acctest.RandStringFromCharSet(13, acctest.CharSetAlphaNum)) resource.Test(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, @@ -114,11 +138,14 @@ func testAccAwsAppmeshVirtualNode_listenerHealthChecks(t *testing.T) { CheckDestroy: testAccCheckAppmeshVirtualNodeDestroy, Steps: []resource.TestStep{ { - Config: testAccAppmeshVirtualNodeConfig_listenerHealthChecks(meshName, vnName), + Config: testAccAppmeshVirtualNodeConfig_listenerHealthChecks(rName), Check: resource.ComposeTestCheckFunc( testAccCheckAppmeshVirtualNodeExists(resourceName, &vn), - resource.TestCheckResourceAttr(resourceName, "name", vnName), - resource.TestCheckResourceAttr(resourceName, "mesh_name", meshName), + testAccCheckResourceAttrRegionalARN(resourceName, "arn", "appmesh-preview", fmt.Sprintf("mesh/%s/virtualNode/%s", rName, rName)), + resource.TestCheckResourceAttrSet(resourceName, "created_date"), + resource.TestCheckResourceAttrSet(resourceName, "last_updated_date"), + resource.TestCheckResourceAttr(resourceName, "mesh_name", rName), + resource.TestCheckResourceAttr(resourceName, "name", rName), resource.TestCheckResourceAttr(resourceName, "spec.#", "1"), resource.TestCheckResourceAttr(resourceName, "spec.0.backend.#", "1"), resource.TestCheckResourceAttr(resourceName, "spec.0.backend.2622272660.virtual_service.#", "1"), @@ -135,21 +162,23 @@ func testAccAwsAppmeshVirtualNode_listenerHealthChecks(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "spec.0.listener.433446196.port_mapping.#", "1"), resource.TestCheckResourceAttr(resourceName, "spec.0.listener.433446196.port_mapping.0.port", "8080"), resource.TestCheckResourceAttr(resourceName, "spec.0.listener.433446196.port_mapping.0.protocol", "http"), + resource.TestCheckResourceAttr(resourceName, "spec.0.listener.433446196.tls.#", "0"), resource.TestCheckResourceAttr(resourceName, "spec.0.logging.#", "0"), resource.TestCheckResourceAttr(resourceName, "spec.0.service_discovery.#", "1"), resource.TestCheckResourceAttr(resourceName, "spec.0.service_discovery.0.dns.#", "1"), resource.TestCheckResourceAttr(resourceName, "spec.0.service_discovery.0.dns.0.hostname", "serviceb.simpleapp.local"), - resource.TestCheckResourceAttrSet(resourceName, "created_date"), - resource.TestCheckResourceAttrSet(resourceName, "last_updated_date"), - resource.TestMatchResourceAttr(resourceName, "arn", regexp.MustCompile(fmt.Sprintf("^arn:[^:]+:appmesh-preview:[^:]+:\\d{12}:mesh/%s/virtualNode/%s", meshName, vnName))), + resource.TestCheckResourceAttr(resourceName, "tags.%", "0"), ), }, { - Config: testAccAppmeshVirtualNodeConfig_listenerHealthChecksUpdated(meshName, vnName), + Config: testAccAppmeshVirtualNodeConfig_listenerHealthChecksUpdated(rName), Check: resource.ComposeTestCheckFunc( testAccCheckAppmeshVirtualNodeExists(resourceName, &vn), - resource.TestCheckResourceAttr(resourceName, "name", vnName), - resource.TestCheckResourceAttr(resourceName, "mesh_name", meshName), + testAccCheckResourceAttrRegionalARN(resourceName, "arn", "appmesh-preview", fmt.Sprintf("mesh/%s/virtualNode/%s", rName, rName)), + resource.TestCheckResourceAttrSet(resourceName, "created_date"), + resource.TestCheckResourceAttrSet(resourceName, "last_updated_date"), + resource.TestCheckResourceAttr(resourceName, "mesh_name", rName), + resource.TestCheckResourceAttr(resourceName, "name", rName), resource.TestCheckResourceAttr(resourceName, "spec.#", "1"), resource.TestCheckResourceAttr(resourceName, "spec.0.backend.#", "2"), resource.TestCheckResourceAttr(resourceName, "spec.0.backend.2576932631.virtual_service.#", "1"), @@ -167,18 +196,77 @@ func testAccAwsAppmeshVirtualNode_listenerHealthChecks(t *testing.T) { resource.TestCheckResourceAttr(resourceName, "spec.0.listener.3446683576.port_mapping.#", "1"), resource.TestCheckResourceAttr(resourceName, "spec.0.listener.3446683576.port_mapping.0.port", "8081"), resource.TestCheckResourceAttr(resourceName, "spec.0.listener.3446683576.port_mapping.0.protocol", "http"), + resource.TestCheckResourceAttr(resourceName, "spec.0.listener.3446683576.tls.#", "0"), resource.TestCheckResourceAttr(resourceName, "spec.0.logging.#", "0"), resource.TestCheckResourceAttr(resourceName, "spec.0.service_discovery.#", "1"), resource.TestCheckResourceAttr(resourceName, "spec.0.service_discovery.0.dns.#", "1"), resource.TestCheckResourceAttr(resourceName, "spec.0.service_discovery.0.dns.0.hostname", "serviceb1.simpleapp.local"), + resource.TestCheckResourceAttr(resourceName, "tags.%", "0"), + ), + }, + { + ResourceName: resourceName, + ImportStateIdFunc: testAccAwsAppmeshVirtualNodeImportStateIdFunc(resourceName), + ImportState: true, + ImportStateVerify: true, + }, + }, + }) +} + +func testAccAwsAppmeshVirtualNode_listenerTls(t *testing.T) { + var vn appmesh.VirtualNodeData + resourceName := "aws_appmesh_virtual_node.test" + rName := fmt.Sprintf("tf-testacc-appmesh-%s", acctest.RandStringFromCharSet(13, acctest.CharSetAlphaNum)) + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProvidersWithTLS, + CheckDestroy: testAccCheckAppmeshVirtualNodeDestroy, + Steps: []resource.TestStep{ + { + Config: testAccAppmeshVirtualNodeConfig_listenerTls(rName, "PERMISSIVE"), + Check: resource.ComposeTestCheckFunc( + testAccCheckAppmeshVirtualNodeExists(resourceName, &vn), + testAccCheckResourceAttrRegionalARN(resourceName, "arn", "appmesh-preview", fmt.Sprintf("mesh/%s/virtualNode/%s", rName, rName)), + resource.TestCheckResourceAttrSet(resourceName, "created_date"), + resource.TestCheckResourceAttrSet(resourceName, "last_updated_date"), + resource.TestCheckResourceAttr(resourceName, "mesh_name", rName), + resource.TestCheckResourceAttr(resourceName, "name", rName), + resource.TestCheckResourceAttr(resourceName, "spec.#", "1"), + resource.TestCheckResourceAttr(resourceName, "spec.0.backend.#", "1"), + resource.TestCheckResourceAttr(resourceName, "spec.0.backend.2622272660.virtual_service.#", "1"), + resource.TestCheckResourceAttr(resourceName, "spec.0.backend.2622272660.virtual_service.0.virtual_service_name", "servicea.simpleapp.local"), + resource.TestCheckResourceAttr(resourceName, "spec.0.logging.#", "0"), + resource.TestCheckResourceAttr(resourceName, "spec.0.service_discovery.#", "1"), + resource.TestCheckResourceAttr(resourceName, "spec.0.service_discovery.0.dns.#", "1"), + resource.TestCheckResourceAttr(resourceName, "spec.0.service_discovery.0.dns.0.hostname", "serviceb.simpleapp.local"), + resource.TestCheckResourceAttr(resourceName, "tags.%", "0"), + ), + }, + { + Config: testAccAppmeshVirtualNodeConfig_listenerTls(rName, "STRICT"), + Check: resource.ComposeTestCheckFunc( + testAccCheckAppmeshVirtualNodeExists(resourceName, &vn), + testAccCheckResourceAttrRegionalARN(resourceName, "arn", "appmesh-preview", fmt.Sprintf("mesh/%s/virtualNode/%s", rName, rName)), resource.TestCheckResourceAttrSet(resourceName, "created_date"), resource.TestCheckResourceAttrSet(resourceName, "last_updated_date"), - resource.TestMatchResourceAttr(resourceName, "arn", regexp.MustCompile(fmt.Sprintf("^arn:[^:]+:appmesh-preview:[^:]+:\\d{12}:mesh/%s/virtualNode/%s", meshName, vnName))), + resource.TestCheckResourceAttr(resourceName, "mesh_name", rName), + resource.TestCheckResourceAttr(resourceName, "name", rName), + resource.TestCheckResourceAttr(resourceName, "spec.#", "1"), + resource.TestCheckResourceAttr(resourceName, "spec.0.backend.#", "1"), + resource.TestCheckResourceAttr(resourceName, "spec.0.backend.2622272660.virtual_service.#", "1"), + resource.TestCheckResourceAttr(resourceName, "spec.0.backend.2622272660.virtual_service.0.virtual_service_name", "servicea.simpleapp.local"), + resource.TestCheckResourceAttr(resourceName, "spec.0.logging.#", "0"), + resource.TestCheckResourceAttr(resourceName, "spec.0.service_discovery.#", "1"), + resource.TestCheckResourceAttr(resourceName, "spec.0.service_discovery.0.dns.#", "1"), + resource.TestCheckResourceAttr(resourceName, "spec.0.service_discovery.0.dns.0.hostname", "serviceb.simpleapp.local"), + resource.TestCheckResourceAttr(resourceName, "tags.%", "0"), ), }, { ResourceName: resourceName, - ImportStateId: fmt.Sprintf("%s/%s", meshName, vnName), + ImportStateIdFunc: testAccAwsAppmeshVirtualNodeImportStateIdFunc(resourceName), ImportState: true, ImportStateVerify: true, }, @@ -189,8 +277,7 @@ func testAccAwsAppmeshVirtualNode_listenerHealthChecks(t *testing.T) { func testAccAwsAppmeshVirtualNode_logging(t *testing.T) { var vn appmesh.VirtualNodeData resourceName := "aws_appmesh_virtual_node.test" - meshName := fmt.Sprintf("tf-test-mesh-%d", acctest.RandInt()) - vnName := fmt.Sprintf("tf-test-node-%d", acctest.RandInt()) + rName := fmt.Sprintf("tf-testacc-appmesh-%s", acctest.RandStringFromCharSet(13, acctest.CharSetAlphaNum)) resource.Test(t, resource.TestCase{ PreCheck: func() { testAccPreCheck(t) }, @@ -198,33 +285,63 @@ func testAccAwsAppmeshVirtualNode_logging(t *testing.T) { CheckDestroy: testAccCheckAppmeshVirtualNodeDestroy, Steps: []resource.TestStep{ { - Config: testAccAppmeshVirtualNodeConfig_logging(meshName, vnName, "/dev/stdout"), + Config: testAccAppmeshVirtualNodeConfig_logging(rName, "/dev/stdout"), Check: resource.ComposeTestCheckFunc( testAccCheckAppmeshVirtualNodeExists(resourceName, &vn), - resource.TestCheckResourceAttr(resourceName, "name", vnName), - resource.TestCheckResourceAttr(resourceName, "mesh_name", meshName), + testAccCheckResourceAttrRegionalARN(resourceName, "arn", "appmesh-preview", fmt.Sprintf("mesh/%s/virtualNode/%s", rName, rName)), + resource.TestCheckResourceAttrSet(resourceName, "created_date"), + resource.TestCheckResourceAttrSet(resourceName, "last_updated_date"), + resource.TestCheckResourceAttr(resourceName, "mesh_name", rName), + resource.TestCheckResourceAttr(resourceName, "name", rName), resource.TestCheckResourceAttr(resourceName, "spec.#", "1"), + resource.TestCheckResourceAttr(resourceName, "spec.0.backend.#", "1"), + resource.TestCheckResourceAttr(resourceName, "spec.0.backend.2622272660.virtual_service.#", "1"), + resource.TestCheckResourceAttr(resourceName, "spec.0.backend.2622272660.virtual_service.0.virtual_service_name", "servicea.simpleapp.local"), + resource.TestCheckResourceAttr(resourceName, "spec.0.listener.#", "1"), + resource.TestCheckResourceAttr(resourceName, "spec.0.listener.2279702354.health_check.#", "0"), + resource.TestCheckResourceAttr(resourceName, "spec.0.listener.2279702354.port_mapping.#", "1"), + resource.TestCheckResourceAttr(resourceName, "spec.0.listener.2279702354.port_mapping.0.port", "8080"), + resource.TestCheckResourceAttr(resourceName, "spec.0.listener.2279702354.port_mapping.0.protocol", "http"), + resource.TestCheckResourceAttr(resourceName, "spec.0.listener.2279702354.tls.#", "0"), resource.TestCheckResourceAttr(resourceName, "spec.0.logging.#", "1"), resource.TestCheckResourceAttr(resourceName, "spec.0.logging.0.access_log.#", "1"), resource.TestCheckResourceAttr(resourceName, "spec.0.logging.0.access_log.0.file.#", "1"), resource.TestCheckResourceAttr(resourceName, "spec.0.logging.0.access_log.0.file.0.path", "/dev/stdout"), + resource.TestCheckResourceAttr(resourceName, "spec.0.service_discovery.#", "1"), + resource.TestCheckResourceAttr(resourceName, "spec.0.service_discovery.0.dns.#", "1"), + resource.TestCheckResourceAttr(resourceName, "spec.0.service_discovery.0.dns.0.hostname", "serviceb.simpleapp.local"), ), }, { - Config: testAccAppmeshVirtualNodeConfig_logging(meshName, vnName, "/tmp/access.log"), + Config: testAccAppmeshVirtualNodeConfig_logging(rName, "/tmp/access.log"), Check: resource.ComposeTestCheckFunc( testAccCheckAppmeshVirtualNodeExists(resourceName, &vn), - resource.TestCheckResourceAttr(resourceName, "name", vnName), - resource.TestCheckResourceAttr(resourceName, "mesh_name", meshName), + testAccCheckResourceAttrRegionalARN(resourceName, "arn", "appmesh-preview", fmt.Sprintf("mesh/%s/virtualNode/%s", rName, rName)), + resource.TestCheckResourceAttrSet(resourceName, "created_date"), + resource.TestCheckResourceAttrSet(resourceName, "last_updated_date"), + resource.TestCheckResourceAttr(resourceName, "mesh_name", rName), + resource.TestCheckResourceAttr(resourceName, "name", rName), + resource.TestCheckResourceAttr(resourceName, "spec.0.backend.#", "1"), + resource.TestCheckResourceAttr(resourceName, "spec.0.backend.2622272660.virtual_service.#", "1"), + resource.TestCheckResourceAttr(resourceName, "spec.0.backend.2622272660.virtual_service.0.virtual_service_name", "servicea.simpleapp.local"), + resource.TestCheckResourceAttr(resourceName, "spec.0.listener.#", "1"), + resource.TestCheckResourceAttr(resourceName, "spec.0.listener.2279702354.health_check.#", "0"), + resource.TestCheckResourceAttr(resourceName, "spec.0.listener.2279702354.port_mapping.#", "1"), + resource.TestCheckResourceAttr(resourceName, "spec.0.listener.2279702354.port_mapping.0.port", "8080"), + resource.TestCheckResourceAttr(resourceName, "spec.0.listener.2279702354.port_mapping.0.protocol", "http"), + resource.TestCheckResourceAttr(resourceName, "spec.0.listener.2279702354.tls.#", "0"), resource.TestCheckResourceAttr(resourceName, "spec.0.logging.#", "1"), resource.TestCheckResourceAttr(resourceName, "spec.0.logging.0.access_log.#", "1"), resource.TestCheckResourceAttr(resourceName, "spec.0.logging.0.access_log.0.file.#", "1"), resource.TestCheckResourceAttr(resourceName, "spec.0.logging.0.access_log.0.file.0.path", "/tmp/access.log"), + resource.TestCheckResourceAttr(resourceName, "spec.0.service_discovery.#", "1"), + resource.TestCheckResourceAttr(resourceName, "spec.0.service_discovery.0.dns.#", "1"), + resource.TestCheckResourceAttr(resourceName, "spec.0.service_discovery.0.dns.0.hostname", "serviceb.simpleapp.local"), ), }, { ResourceName: resourceName, - ImportStateId: fmt.Sprintf("%s/%s", meshName, vnName), + ImportStateIdFunc: testAccAwsAppmeshVirtualNodeImportStateIdFunc(resourceName), ImportState: true, ImportStateVerify: true, }, @@ -328,7 +445,18 @@ func testAccCheckAppmeshVirtualNodeExists(name string, v *appmesh.VirtualNodeDat } } -func testAccAppmeshVirtualNodeConfig_mesh(rName string) string { +func testAccAwsAppmeshVirtualNodeImportStateIdFunc(resourceName string) resource.ImportStateIdFunc { + return func(s *terraform.State) (string, error) { + rs, ok := s.RootModule().Resources[resourceName] + if !ok { + return "", fmt.Errorf("Not Found: %s", resourceName) + } + + return fmt.Sprintf("%s/%s", rs.Primary.Attributes["mesh_name"], rs.Primary.Attributes["name"]), nil + } +} + +func testAccAppmeshVirtualNodeConfig_base(rName string) string { return fmt.Sprintf(` resource "aws_appmesh_mesh" "test" { name = %[1]q @@ -336,21 +464,21 @@ resource "aws_appmesh_mesh" "test" { `, rName) } -func testAccAppmeshVirtualNodeConfig_basic(meshName, vnName string) string { - return testAccAppmeshVirtualNodeConfig_mesh(meshName) + fmt.Sprintf(` +func testAccAppmeshVirtualNodeConfig_basic(rName string) string { + return testAccAppmeshVirtualNodeConfig_base(rName) + fmt.Sprintf(` resource "aws_appmesh_virtual_node" "test" { name = %[1]q mesh_name = "${aws_appmesh_mesh.test.id}" spec {} } -`, vnName) +`, rName) } -func testAccAppmeshVirtualNodeConfig_cloudMapServiceDiscovery(meshName, vnName, rName, attrKey, attrValue string) string { - return testAccAppmeshVirtualNodeConfig_mesh(meshName) + fmt.Sprintf(` +func testAccAppmeshVirtualNodeConfig_cloudMapServiceDiscovery(rName, attrKey, attrValue string) string { + return testAccAppmeshVirtualNodeConfig_base(rName) + fmt.Sprintf(` resource "aws_service_discovery_http_namespace" "test" { - name = %[2]q + name = %[1]q } resource "aws_appmesh_virtual_node" "test" { @@ -374,20 +502,20 @@ resource "aws_appmesh_virtual_node" "test" { service_discovery { aws_cloud_map { attributes = { - %[3]s = %[4]q + %[2]s = %[3]q } - service_name = %[2]q + service_name = %[1]q namespace_name = "${aws_service_discovery_http_namespace.test.name}" } } } } -`, vnName, rName, attrKey, attrValue) +`, rName, attrKey, attrValue) } -func testAccAppmeshVirtualNodeConfig_listenerHealthChecks(meshName, vnName string) string { - return testAccAppmeshVirtualNodeConfig_mesh(meshName) + fmt.Sprintf(` +func testAccAppmeshVirtualNodeConfig_listenerHealthChecks(rName string) string { + return testAccAppmeshVirtualNodeConfig_base(rName) + fmt.Sprintf(` resource "aws_appmesh_virtual_node" "test" { name = %[1]q mesh_name = "${aws_appmesh_mesh.test.id}" @@ -422,11 +550,11 @@ resource "aws_appmesh_virtual_node" "test" { } } } -`, vnName) +`, rName) } -func testAccAppmeshVirtualNodeConfig_listenerHealthChecksUpdated(meshName, vnName string) string { - return testAccAppmeshVirtualNodeConfig_mesh(meshName) + fmt.Sprintf(` +func testAccAppmeshVirtualNodeConfig_listenerHealthChecksUpdated(rName string) string { + return testAccAppmeshVirtualNodeConfig_base(rName) + fmt.Sprintf(` resource "aws_appmesh_virtual_node" "test" { name = %[1]q mesh_name = "${aws_appmesh_mesh.test.id}" @@ -467,11 +595,78 @@ resource "aws_appmesh_virtual_node" "test" { } } } -`, vnName) +`, rName) +} + +func testAccAppmeshVirtualNodeConfig_listenerTls(rName, mode string) string { + return testAccAppmeshVirtualNodeConfig_base(rName) + fmt.Sprintf(` +resource "tls_private_key" "test" { + algorithm = "RSA" +} + +resource "tls_self_signed_cert" "test" { + key_algorithm = "RSA" + private_key_pem = "${tls_private_key.test.private_key_pem}" + + subject { + common_name = "test.example.com" + organization = "ACME Examples, Inc" + } + + validity_period_hours = 12 + + allowed_uses = [ + "key_encipherment", + "digital_signature", + "server_auth", + ] +} + +resource "aws_acm_certificate" "test" { + private_key = "${tls_private_key.test.private_key_pem}" + certificate_body = "${tls_self_signed_cert.test.cert_pem}" +} + +resource "aws_appmesh_virtual_node" "test" { + name = %[1]q + mesh_name = "${aws_appmesh_mesh.test.id}" + + spec { + backend { + virtual_service { + virtual_service_name = "servicea.simpleapp.local" + } + } + + listener { + port_mapping { + port = 8080 + protocol = "http" + } + + tls { + mode = %[2]q + + certificate { + acm { + certificate_arn = "${aws_acm_certificate.test.arn}" + } + } + } + } + + service_discovery { + dns { + hostname = "serviceb.simpleapp.local" + } + } + } +} +`, rName, mode) } -func testAccAppmeshVirtualNodeConfig_logging(meshName, vnName, path string) string { - return testAccAppmeshVirtualNodeConfig_mesh(meshName) + fmt.Sprintf(` +func testAccAppmeshVirtualNodeConfig_logging(rName, path string) string { + return testAccAppmeshVirtualNodeConfig_base(rName) + fmt.Sprintf(` resource "aws_appmesh_virtual_node" "test" { name = %[1]q mesh_name = "${aws_appmesh_mesh.test.id}" @@ -505,7 +700,7 @@ resource "aws_appmesh_virtual_node" "test" { } } } -`, vnName, path) +`, rName, path) } // func testAccAppmeshVirtualNodeConfig_tags(meshName, vnName, tagKey1, tagValue1, tagKey2, tagValue2 string) string { diff --git a/website/docs/r/appmesh_virtual_node.html.markdown b/website/docs/r/appmesh_virtual_node.html.markdown index c7f9759805a..a6c0238f6e7 100644 --- a/website/docs/r/appmesh_virtual_node.html.markdown +++ b/website/docs/r/appmesh_virtual_node.html.markdown @@ -197,6 +197,7 @@ The `listener` object supports the following: * `port_mapping` - (Required) The port mapping information for the listener. * `health_check` - (Optional) The health check information for the listener. +* `tls` - (Optional) The TLS information for the listener. The `logging` object supports the following: @@ -241,6 +242,19 @@ The `health_check` object supports the following: * `path` - (Optional) The destination path for the health check request. This is only required if the specified protocol is `http`. * `port` - (Optional) The destination port for the health check request. This port must match the port defined in the `port_mapping` for the listener. +The `tls` object supports the following: + +* `certificate` - (Required) The certificate. +* `mode` - (Required) The TLS mode. Valid values are `DISABLED`, `PERMISSIVE` and `STRICT`. + +The `certificate` object supports the following: + +* `acm` - (Optional) [AWS Certificate Manager](https://aws.amazon.com/certificate-manager/) certificate configuration. + +The `acm` object supports the following: + +* `certificate_arn` - (Required) The [ACM certificate](/docs/providers/aws/r/acm_certificate.html) ARN. + ## Attributes Reference In addition to all arguments above, the following attributes are exported: