diff --git a/.changelog/27057.txt b/.changelog/27057.txt new file mode 100644 index 00000000000..324b621b654 --- /dev/null +++ b/.changelog/27057.txt @@ -0,0 +1,3 @@ +```release-note:new-data-source +aws_appmesh_virtual_gateway +``` diff --git a/internal/service/appmesh/appmesh_test.go b/internal/service/appmesh/appmesh_test.go index 166965e227c..a9f85caa578 100644 --- a/internal/service/appmesh/appmesh_test.go +++ b/internal/service/appmesh/appmesh_test.go @@ -67,6 +67,7 @@ func TestAccAppMesh_serial(t *testing.T) { "multiListenerValidation": testAccVirtualGateway_MultiListenerValidation, "logging": testAccVirtualGateway_Logging, "tags": testAccVirtualGateway_Tags, + "dataSourceBasic": testAccVirtualGatewayDataSource_basic, }, "VirtualNode": { "basic": testAccVirtualNode_basic, diff --git a/internal/service/appmesh/find.go b/internal/service/appmesh/find.go index 36da81180d1..34d40766c8f 100644 --- a/internal/service/appmesh/find.go +++ b/internal/service/appmesh/find.go @@ -30,26 +30,3 @@ func FindGatewayRoute(ctx context.Context, conn *appmesh.AppMesh, meshName, virt return output.GatewayRoute, nil } - -// FindVirtualGateway returns the virtual gateway corresponding to the specified mesh name, virtual gateway name and optional mesh owner. -// Returns an error if no virtual gateway is found. -func FindVirtualGateway(ctx context.Context, conn *appmesh.AppMesh, meshName, virtualGatewayName, meshOwner string) (*appmesh.VirtualGatewayData, error) { - input := &appmesh.DescribeVirtualGatewayInput{ - MeshName: aws.String(meshName), - VirtualGatewayName: aws.String(virtualGatewayName), - } - if meshOwner != "" { - input.MeshOwner = aws.String(meshOwner) - } - - output, err := conn.DescribeVirtualGatewayWithContext(ctx, input) - if err != nil { - return nil, err - } - - if output == nil { - return nil, nil - } - - return output.VirtualGateway, nil -} diff --git a/internal/service/appmesh/mesh.go b/internal/service/appmesh/mesh.go index 7e62ec0be76..46621b2ce7b 100644 --- a/internal/service/appmesh/mesh.go +++ b/internal/service/appmesh/mesh.go @@ -298,22 +298,21 @@ func dataSourcePropertyFromResourceProperty(rs *schema.Schema) *schema.Schema { case schema.TypeSet: ds.Set = rs.Set fallthrough - case schema.TypeList: + case schema.TypeList, schema.TypeMap: // List & Set types are generally used for 2 cases: // - a list/set of simple primitive values (e.g. list of strings) // - a sub resource - if elem, ok := rs.Elem.(*schema.Resource); ok { + // Maps are usually used for maps of simple primitives + switch elem := rs.Elem.(type) { + case *schema.Resource: // handle the case where the Element is a sub-resource ds.Elem = &schema.Resource{ Schema: dataSourceSchemaFromResourceSchema(elem.Schema), } - } else { + case *schema.Schema: // handle simple primitive case - ds.Elem = rs.Elem + ds.Elem = &schema.Schema{Type: elem.Type} } - default: - // Elem of all other types are copied as-is - ds.Elem = rs.Elem } return ds diff --git a/internal/service/appmesh/service_package_gen.go b/internal/service/appmesh/service_package_gen.go index df05813cbc0..df8943d96d1 100644 --- a/internal/service/appmesh/service_package_gen.go +++ b/internal/service/appmesh/service_package_gen.go @@ -29,6 +29,10 @@ func (p *servicePackage) SDKDataSources(ctx context.Context) []*types.ServicePac Factory: DataSourceRoute, TypeName: "aws_appmesh_route", }, + { + Factory: DataSourceVirtualGateway, + TypeName: "aws_appmesh_virtual_gateway", + }, { Factory: DataSourceVirtualService, TypeName: "aws_appmesh_virtual_service", diff --git a/internal/service/appmesh/virtual_gateway.go b/internal/service/appmesh/virtual_gateway.go index 5df6cf14061..375dfb512e6 100644 --- a/internal/service/appmesh/virtual_gateway.go +++ b/internal/service/appmesh/virtual_gateway.go @@ -20,6 +20,7 @@ import ( tftags "github.com/hashicorp/terraform-provider-aws/internal/tags" "github.com/hashicorp/terraform-provider-aws/internal/tfresource" "github.com/hashicorp/terraform-provider-aws/internal/verify" + "github.com/hashicorp/terraform-provider-aws/names" ) // @SDKResource("aws_appmesh_virtual_gateway") @@ -35,20 +36,24 @@ func ResourceVirtualGateway() *schema.Resource { }, Schema: map[string]*schema.Schema{ - "name": { - Type: schema.TypeString, - Required: true, - ForceNew: true, - ValidateFunc: validation.StringLenBetween(1, 255), + "arn": { + Type: schema.TypeString, + Computed: true, + }, + "created_date": { + Type: schema.TypeString, + Computed: true, + }, + "last_updated_date": { + Type: schema.TypeString, + Computed: true, }, - "mesh_name": { Type: schema.TypeString, Required: true, ForceNew: true, ValidateFunc: validation.StringLenBetween(1, 255), }, - "mesh_owner": { Type: schema.TypeString, Optional: true, @@ -56,214 +61,220 @@ func ResourceVirtualGateway() *schema.Resource { ForceNew: true, ValidateFunc: verify.ValidAccountID, }, + "name": { + Type: schema.TypeString, + Required: true, + ForceNew: true, + ValidateFunc: validation.StringLenBetween(1, 255), + }, + "resource_owner": { + Type: schema.TypeString, + Computed: true, + }, + "spec": resourceVirtualGatewaySpecSchema(), + names.AttrTags: tftags.TagsSchema(), + names.AttrTagsAll: tftags.TagsSchemaComputed(), + }, - "spec": { - Type: schema.TypeList, - Required: true, - MinItems: 1, - MaxItems: 1, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "backend_defaults": { - Type: schema.TypeList, - Optional: true, - MinItems: 0, - MaxItems: 1, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "client_policy": { - Type: schema.TypeList, - Optional: true, - MinItems: 0, - MaxItems: 1, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "tls": { - Type: schema.TypeList, - Optional: true, - MinItems: 0, - MaxItems: 1, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "certificate": { - Type: schema.TypeList, - Optional: true, - MinItems: 0, - MaxItems: 1, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "file": { - Type: schema.TypeList, - Optional: true, - MinItems: 0, - MaxItems: 1, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "certificate_chain": { - Type: schema.TypeString, - Required: true, - ValidateFunc: validation.StringLenBetween(1, 255), - }, + CustomizeDiff: verify.SetTagsDiff, + } +} - "private_key": { - Type: schema.TypeString, - Required: true, - ValidateFunc: validation.StringLenBetween(1, 255), - }, - }, +func resourceVirtualGatewaySpecSchema() *schema.Schema { + return &schema.Schema{ + Type: schema.TypeList, + Required: true, + MinItems: 1, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "backend_defaults": { + Type: schema.TypeList, + Optional: true, + MinItems: 0, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "client_policy": { + Type: schema.TypeList, + Optional: true, + MinItems: 0, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "tls": { + Type: schema.TypeList, + Optional: true, + MinItems: 0, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "certificate": { + Type: schema.TypeList, + Optional: true, + MinItems: 0, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "file": { + Type: schema.TypeList, + Optional: true, + MinItems: 0, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "certificate_chain": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringLenBetween(1, 255), }, - ExactlyOneOf: []string{ - "spec.0.backend_defaults.0.client_policy.0.tls.0.certificate.0.file", - "spec.0.backend_defaults.0.client_policy.0.tls.0.certificate.0.sds", + "private_key": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringLenBetween(1, 255), }, }, - - "sds": { - Type: schema.TypeList, - Optional: true, - MinItems: 0, - MaxItems: 1, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "secret_name": { - Type: schema.TypeString, - Required: true, - }, - }, - }, - ExactlyOneOf: []string{ - "spec.0.backend_defaults.0.client_policy.0.tls.0.certificate.0.file", - "spec.0.backend_defaults.0.client_policy.0.tls.0.certificate.0.sds", + }, + ExactlyOneOf: []string{ + "spec.0.backend_defaults.0.client_policy.0.tls.0.certificate.0.file", + "spec.0.backend_defaults.0.client_policy.0.tls.0.certificate.0.sds", + }, + }, + "sds": { + Type: schema.TypeList, + Optional: true, + MinItems: 0, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "secret_name": { + Type: schema.TypeString, + Required: true, }, }, }, + ExactlyOneOf: []string{ + "spec.0.backend_defaults.0.client_policy.0.tls.0.certificate.0.file", + "spec.0.backend_defaults.0.client_policy.0.tls.0.certificate.0.sds", + }, }, }, - - "enforce": { - Type: schema.TypeBool, - Optional: true, - Default: true, - }, - - "ports": { - Type: schema.TypeSet, - Optional: true, - Elem: &schema.Schema{ - Type: schema.TypeInt, - ValidateFunc: validation.IsPortNumber, - }, - Set: schema.HashInt, - }, - - "validation": { - Type: schema.TypeList, - Required: true, - MinItems: 1, - MaxItems: 1, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "subject_alternative_names": { - Type: schema.TypeList, - Optional: true, - MinItems: 0, - MaxItems: 1, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "match": { - Type: schema.TypeList, - Required: true, - MinItems: 1, - MaxItems: 1, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "exact": { - Type: schema.TypeSet, - Required: true, - Elem: &schema.Schema{Type: schema.TypeString}, - Set: schema.HashString, - }, - }, + }, + }, + "enforce": { + Type: schema.TypeBool, + Optional: true, + Default: true, + }, + "ports": { + Type: schema.TypeSet, + Optional: true, + Elem: &schema.Schema{ + Type: schema.TypeInt, + ValidateFunc: validation.IsPortNumber, + }, + }, + "validation": { + Type: schema.TypeList, + Required: true, + MinItems: 1, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "subject_alternative_names": { + Type: schema.TypeList, + Optional: true, + MinItems: 0, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "match": { + Type: schema.TypeList, + Required: true, + MinItems: 1, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "exact": { + Type: schema.TypeSet, + Required: true, + Elem: &schema.Schema{Type: schema.TypeString}, }, }, }, }, }, - - "trust": { - 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_authority_arns": { - Type: schema.TypeSet, - Required: true, - Elem: &schema.Schema{ - Type: schema.TypeString, - ValidateFunc: verify.ValidARN, - }, - Set: schema.HashString, - }, + }, + }, + "trust": { + 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_authority_arns": { + Type: schema.TypeSet, + Required: true, + Elem: &schema.Schema{ + Type: schema.TypeString, + ValidateFunc: verify.ValidARN, }, }, - ExactlyOneOf: []string{ - "spec.0.backend_defaults.0.client_policy.0.tls.0.validation.0.trust.0.acm", - "spec.0.backend_defaults.0.client_policy.0.tls.0.validation.0.trust.0.file", - "spec.0.backend_defaults.0.client_policy.0.tls.0.validation.0.trust.0.sds", - }, }, - - "file": { - Type: schema.TypeList, - Optional: true, - MinItems: 0, - MaxItems: 1, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "certificate_chain": { - Type: schema.TypeString, - Required: true, - ValidateFunc: validation.StringLenBetween(1, 255), - }, - }, - }, - ExactlyOneOf: []string{ - "spec.0.backend_defaults.0.client_policy.0.tls.0.validation.0.trust.0.acm", - "spec.0.backend_defaults.0.client_policy.0.tls.0.validation.0.trust.0.file", - "spec.0.backend_defaults.0.client_policy.0.tls.0.validation.0.trust.0.sds", + }, + ExactlyOneOf: []string{ + "spec.0.backend_defaults.0.client_policy.0.tls.0.validation.0.trust.0.acm", + "spec.0.backend_defaults.0.client_policy.0.tls.0.validation.0.trust.0.file", + "spec.0.backend_defaults.0.client_policy.0.tls.0.validation.0.trust.0.sds", + }, + }, + "file": { + Type: schema.TypeList, + Optional: true, + MinItems: 0, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "certificate_chain": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringLenBetween(1, 255), }, }, - - "sds": { - Type: schema.TypeList, - Optional: true, - MinItems: 0, - MaxItems: 1, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "secret_name": { - Type: schema.TypeString, - Required: true, - ValidateFunc: validation.StringLenBetween(1, 255), - }, - }, - }, - ExactlyOneOf: []string{ - "spec.0.backend_defaults.0.client_policy.0.tls.0.validation.0.trust.0.acm", - "spec.0.backend_defaults.0.client_policy.0.tls.0.validation.0.trust.0.file", - "spec.0.backend_defaults.0.client_policy.0.tls.0.validation.0.trust.0.sds", + }, + ExactlyOneOf: []string{ + "spec.0.backend_defaults.0.client_policy.0.tls.0.validation.0.trust.0.acm", + "spec.0.backend_defaults.0.client_policy.0.tls.0.validation.0.trust.0.file", + "spec.0.backend_defaults.0.client_policy.0.tls.0.validation.0.trust.0.sds", + }, + }, + "sds": { + Type: schema.TypeList, + Optional: true, + MinItems: 0, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "secret_name": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringLenBetween(1, 255), }, }, }, + ExactlyOneOf: []string{ + "spec.0.backend_defaults.0.client_policy.0.tls.0.validation.0.trust.0.acm", + "spec.0.backend_defaults.0.client_policy.0.tls.0.validation.0.trust.0.file", + "spec.0.backend_defaults.0.client_policy.0.tls.0.validation.0.trust.0.sds", + }, }, }, }, @@ -278,297 +289,275 @@ func ResourceVirtualGateway() *schema.Resource { }, }, }, - - "listener": { - Type: schema.TypeList, - Required: true, - MinItems: 1, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "connection_pool": { - Type: schema.TypeList, - Optional: true, - MinItems: 0, - MaxItems: 1, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "grpc": { - Type: schema.TypeList, - Optional: true, - MinItems: 0, - MaxItems: 1, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "max_requests": { - Type: schema.TypeInt, - Required: true, - ValidateFunc: validation.IntAtLeast(1), - }, - }, + }, + }, + "listener": { + Type: schema.TypeList, + Required: true, + MinItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "connection_pool": { + Type: schema.TypeList, + Optional: true, + MinItems: 0, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "grpc": { + Type: schema.TypeList, + Optional: true, + MinItems: 0, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "max_requests": { + Type: schema.TypeInt, + Required: true, + ValidateFunc: validation.IntAtLeast(1), }, }, - - "http": { - Type: schema.TypeList, - Optional: true, - MinItems: 0, - MaxItems: 1, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "max_connections": { - Type: schema.TypeInt, - Required: true, - ValidateFunc: validation.IntAtLeast(1), - }, - - "max_pending_requests": { - Type: schema.TypeInt, - Optional: true, - ValidateFunc: validation.IntAtLeast(1), - }, - }, + }, + }, + "http": { + Type: schema.TypeList, + Optional: true, + MinItems: 0, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "max_connections": { + Type: schema.TypeInt, + Required: true, + ValidateFunc: validation.IntAtLeast(1), }, - }, - - "http2": { - Type: schema.TypeList, - Optional: true, - MinItems: 0, - MaxItems: 1, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "max_requests": { - Type: schema.TypeInt, - Required: true, - ValidateFunc: validation.IntAtLeast(1), - }, - }, + "max_pending_requests": { + Type: schema.TypeInt, + Optional: true, + ValidateFunc: validation.IntAtLeast(1), }, }, }, }, - }, - - "health_check": { - Type: schema.TypeList, - Optional: true, - MinItems: 0, - MaxItems: 1, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "healthy_threshold": { - Type: schema.TypeInt, - Required: true, - ValidateFunc: validation.IntBetween(2, 10), - }, - - "interval_millis": { - Type: schema.TypeInt, - Required: true, - ValidateFunc: validation.IntBetween(5000, 300000), - }, - - "path": { - Type: schema.TypeString, - Optional: true, - }, - - "port": { - Type: schema.TypeInt, - Optional: true, - Computed: true, - ValidateFunc: validation.IsPortNumber, - }, - - "protocol": { - Type: schema.TypeString, - Required: true, - ValidateFunc: validation.StringInSlice(appmesh.VirtualGatewayPortProtocol_Values(), false), - }, - - "timeout_millis": { - Type: schema.TypeInt, - Required: true, - ValidateFunc: validation.IntBetween(2000, 60000), - }, - - "unhealthy_threshold": { - Type: schema.TypeInt, - Required: true, - ValidateFunc: validation.IntBetween(2, 10), + "http2": { + Type: schema.TypeList, + Optional: true, + MinItems: 0, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "max_requests": { + Type: schema.TypeInt, + Required: true, + ValidateFunc: validation.IntAtLeast(1), + }, }, }, }, }, - - "port_mapping": { - Type: schema.TypeList, - Required: true, - MinItems: 1, - MaxItems: 1, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "port": { - Type: schema.TypeInt, - Required: true, - ValidateFunc: validation.IsPortNumber, - }, - - "protocol": { - Type: schema.TypeString, - Required: true, - ValidateFunc: validation.StringInSlice(appmesh.VirtualGatewayPortProtocol_Values(), false), - }, - }, + }, + }, + "health_check": { + Type: schema.TypeList, + Optional: true, + MinItems: 0, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "healthy_threshold": { + Type: schema.TypeInt, + Required: true, + ValidateFunc: validation.IntBetween(2, 10), + }, + "interval_millis": { + Type: schema.TypeInt, + Required: true, + ValidateFunc: validation.IntBetween(5000, 300000), + }, + "path": { + Type: schema.TypeString, + Optional: true, + }, + "port": { + Type: schema.TypeInt, + Optional: true, + Computed: true, + ValidateFunc: validation.IsPortNumber, + }, + "protocol": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringInSlice(appmesh.VirtualGatewayPortProtocol_Values(), false), + }, + "timeout_millis": { + Type: schema.TypeInt, + Required: true, + ValidateFunc: validation.IntBetween(2000, 60000), + }, + "unhealthy_threshold": { + Type: schema.TypeInt, + Required: true, + ValidateFunc: validation.IntBetween(2, 10), }, }, - - "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: verify.ValidARN, - }, - }, + }, + }, + "port_mapping": { + Type: schema.TypeList, + Required: true, + MinItems: 1, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "port": { + Type: schema.TypeInt, + Required: true, + ValidateFunc: validation.IsPortNumber, + }, + "protocol": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringInSlice(appmesh.VirtualGatewayPortProtocol_Values(), false), + }, + }, + }, + }, + "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: verify.ValidARN, }, }, - - "file": { - Type: schema.TypeList, - Optional: true, - MinItems: 0, - MaxItems: 1, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "certificate_chain": { - Type: schema.TypeString, - Required: true, - ValidateFunc: validation.StringLenBetween(1, 255), - }, - - "private_key": { - Type: schema.TypeString, - Required: true, - ValidateFunc: validation.StringLenBetween(1, 255), - }, - }, + }, + }, + "file": { + Type: schema.TypeList, + Optional: true, + MinItems: 0, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "certificate_chain": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringLenBetween(1, 255), + }, + "private_key": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringLenBetween(1, 255), }, }, - - "sds": { - Type: schema.TypeList, - Optional: true, - MinItems: 0, - MaxItems: 1, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "secret_name": { - Type: schema.TypeString, - Required: true, - }, - }, + }, + }, + "sds": { + Type: schema.TypeList, + Optional: true, + MinItems: 0, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "secret_name": { + Type: schema.TypeString, + Required: true, }, }, }, }, }, - - "mode": { - Type: schema.TypeString, - Required: true, - ValidateFunc: validation.StringInSlice(appmesh.VirtualGatewayListenerTlsMode_Values(), false), - }, - - "validation": { - Type: schema.TypeList, - Optional: true, - MinItems: 0, - MaxItems: 1, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "subject_alternative_names": { - Type: schema.TypeList, - Optional: true, - MinItems: 0, - MaxItems: 1, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "match": { - Type: schema.TypeList, - Required: true, - MinItems: 1, - MaxItems: 1, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "exact": { - Type: schema.TypeSet, - Required: true, - Elem: &schema.Schema{Type: schema.TypeString}, - Set: schema.HashString, - }, - }, + }, + }, + "mode": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringInSlice(appmesh.VirtualGatewayListenerTlsMode_Values(), false), + }, + "validation": { + Type: schema.TypeList, + Optional: true, + MinItems: 0, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "subject_alternative_names": { + Type: schema.TypeList, + Optional: true, + MinItems: 0, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "match": { + Type: schema.TypeList, + Required: true, + MinItems: 1, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "exact": { + Type: schema.TypeSet, + Required: true, + Elem: &schema.Schema{Type: schema.TypeString}, }, }, }, }, }, - - "trust": { - Type: schema.TypeList, - Required: true, - MinItems: 1, - MaxItems: 1, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "file": { - Type: schema.TypeList, - Optional: true, - MinItems: 0, - MaxItems: 1, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "certificate_chain": { - Type: schema.TypeString, - Required: true, - ValidateFunc: validation.StringLenBetween(1, 255), - }, - }, + }, + }, + "trust": { + Type: schema.TypeList, + Required: true, + MinItems: 1, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "file": { + Type: schema.TypeList, + Optional: true, + MinItems: 0, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "certificate_chain": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringLenBetween(1, 255), }, }, - - "sds": { - Type: schema.TypeList, - Optional: true, - MinItems: 0, - MaxItems: 1, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "secret_name": { - Type: schema.TypeString, - Required: true, - ValidateFunc: validation.StringLenBetween(1, 255), - }, - }, + }, + }, + "sds": { + Type: schema.TypeList, + Optional: true, + MinItems: 0, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "secret_name": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringLenBetween(1, 255), }, }, }, @@ -583,68 +572,67 @@ func ResourceVirtualGateway() *schema.Resource { }, }, }, - - "logging": { - Type: schema.TypeList, - Optional: true, - MinItems: 0, - MaxItems: 1, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "access_log": { - Type: schema.TypeList, - Optional: true, - MinItems: 0, - MaxItems: 1, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "file": { - Type: schema.TypeList, - Optional: true, - MinItems: 0, - MaxItems: 1, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "format": { - Type: schema.TypeList, - Optional: true, - MinItems: 0, - MaxItems: 1, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "json": { - Type: schema.TypeList, - Optional: true, - Elem: &schema.Resource{ - Schema: map[string]*schema.Schema{ - "key": { - Type: schema.TypeString, - Required: true, - ValidateFunc: validation.StringLenBetween(1, 100), - }, - "value": { - Type: schema.TypeString, - Required: true, - ValidateFunc: validation.StringLenBetween(1, 100), - }, - }, + }, + }, + "logging": { + Type: schema.TypeList, + Optional: true, + MinItems: 0, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "access_log": { + Type: schema.TypeList, + Optional: true, + MinItems: 0, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "file": { + Type: schema.TypeList, + Optional: true, + MinItems: 0, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "format": { + Type: schema.TypeList, + Optional: true, + MinItems: 0, + MaxItems: 1, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "json": { + Type: schema.TypeList, + Optional: true, + Elem: &schema.Resource{ + Schema: map[string]*schema.Schema{ + "key": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringLenBetween(1, 100), + }, + "value": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringLenBetween(1, 100), }, - }, - "text": { - Type: schema.TypeString, - Optional: true, - ValidateFunc: validation.StringLenBetween(1, 1000), }, }, }, - }, - "path": { - Type: schema.TypeString, - Required: true, - ValidateFunc: validation.StringLenBetween(1, 255), + "text": { + Type: schema.TypeString, + Optional: true, + ValidateFunc: validation.StringLenBetween(1, 1000), + }, }, }, }, + "path": { + Type: schema.TypeString, + Required: true, + ValidateFunc: validation.StringLenBetween(1, 255), + }, }, }, }, @@ -655,33 +643,7 @@ func ResourceVirtualGateway() *schema.Resource { }, }, }, - - "arn": { - Type: schema.TypeString, - Computed: true, - }, - - "created_date": { - Type: schema.TypeString, - Computed: true, - }, - - "last_updated_date": { - Type: schema.TypeString, - Computed: true, - }, - - "resource_owner": { - Type: schema.TypeString, - Computed: true, - }, - - "tags": tftags.TagsSchema(), - - "tags_all": tftags.TagsSchemaComputed(), }, - - CustomizeDiff: verify.SetTagsDiff, } } @@ -691,21 +653,22 @@ func resourceVirtualGatewayCreate(ctx context.Context, d *schema.ResourceData, m defaultTagsConfig := meta.(*conns.AWSClient).DefaultTagsConfig tags := defaultTagsConfig.MergeTags(tftags.New(ctx, d.Get("tags").(map[string]interface{}))) + name := d.Get("name").(string) input := &appmesh.CreateVirtualGatewayInput{ MeshName: aws.String(d.Get("mesh_name").(string)), Spec: expandVirtualGatewaySpec(d.Get("spec").([]interface{})), Tags: Tags(tags.IgnoreAWS()), - VirtualGatewayName: aws.String(d.Get("name").(string)), + VirtualGatewayName: aws.String(name), } + if v, ok := d.GetOk("mesh_owner"); ok { input.MeshOwner = aws.String(v.(string)) } - log.Printf("[DEBUG] Creating App Mesh virtual gateway: %s", input) output, err := conn.CreateVirtualGatewayWithContext(ctx, input) if err != nil { - return sdkdiag.AppendErrorf(diags, "creating App Mesh virtual gateway: %s", err) + return sdkdiag.AppendErrorf(diags, "creating App Mesh Virtual Gateway (%s): %s", name, err) } d.SetId(aws.StringValue(output.VirtualGateway.Metadata.Uid)) @@ -719,57 +682,21 @@ func resourceVirtualGatewayRead(ctx context.Context, d *schema.ResourceData, met defaultTagsConfig := meta.(*conns.AWSClient).DefaultTagsConfig ignoreTagsConfig := meta.(*conns.AWSClient).IgnoreTagsConfig - var virtualGateway *appmesh.VirtualGatewayData - - err := resource.RetryContext(ctx, propagationTimeout, func() *resource.RetryError { - var err error - - virtualGateway, err = FindVirtualGateway(ctx, conn, d.Get("mesh_name").(string), d.Get("name").(string), d.Get("mesh_owner").(string)) - - if d.IsNewResource() && tfawserr.ErrCodeEquals(err, appmesh.ErrCodeNotFoundException) { - return resource.RetryableError(err) - } - - if err != nil { - return resource.NonRetryableError(err) - } + outputRaw, err := tfresource.RetryWhenNewResourceNotFound(ctx, propagationTimeout, func() (interface{}, error) { + return FindVirtualGatewayByThreePartKey(ctx, conn, d.Get("mesh_name").(string), d.Get("mesh_owner").(string), d.Get("name").(string)) + }, d.IsNewResource()) - return nil - }) - - if tfresource.TimedOut(err) { - virtualGateway, err = FindVirtualGateway(ctx, conn, d.Get("mesh_name").(string), d.Get("name").(string), d.Get("mesh_owner").(string)) - } - - if !d.IsNewResource() && tfawserr.ErrCodeEquals(err, appmesh.ErrCodeNotFoundException) { + if !d.IsNewResource() && tfresource.NotFound(err) { log.Printf("[WARN] App Mesh Virtual Gateway (%s) not found, removing from state", d.Id()) d.SetId("") return diags } if err != nil { - return sdkdiag.AppendErrorf(diags, "reading App Mesh Virtual Gateway: %s", err) + return sdkdiag.AppendErrorf(diags, "reading App Mesh Virtual Gateway (%s): %s", d.Id(), err) } - if virtualGateway == nil { - if d.IsNewResource() { - return sdkdiag.AppendErrorf(diags, "reading App Mesh Virtual Gateway: not found after creation") - } - - log.Printf("[WARN] App Mesh Virtual Gateway (%s) not found, removing from state", d.Id()) - d.SetId("") - return diags - } - - if aws.StringValue(virtualGateway.Status.Status) == appmesh.VirtualGatewayStatusCodeDeleted { - if d.IsNewResource() { - return sdkdiag.AppendErrorf(diags, "reading App Mesh Virtual Gateway: %s after creation", aws.StringValue(virtualGateway.Status.Status)) - } - - log.Printf("[WARN] App Mesh Virtual Gateway (%s) not found, removing from state", d.Id()) - d.SetId("") - return diags - } + virtualGateway := outputRaw.(*appmesh.VirtualGatewayData) arn := aws.StringValue(virtualGateway.Metadata.Arn) d.Set("arn", arn) @@ -779,15 +706,14 @@ func resourceVirtualGatewayRead(ctx context.Context, d *schema.ResourceData, met d.Set("mesh_owner", virtualGateway.Metadata.MeshOwner) d.Set("name", virtualGateway.VirtualGatewayName) d.Set("resource_owner", virtualGateway.Metadata.ResourceOwner) - err = d.Set("spec", flattenVirtualGatewaySpec(virtualGateway.Spec)) - if err != nil { + if err := d.Set("spec", flattenVirtualGatewaySpec(virtualGateway.Spec)); err != nil { return sdkdiag.AppendErrorf(diags, "setting spec: %s", err) } tags, err := ListTags(ctx, conn, arn) if err != nil { - return sdkdiag.AppendErrorf(diags, "listing tags for App Mesh virtual gateway (%s): %s", arn, err) + return sdkdiag.AppendErrorf(diags, "listing tags for App Mesh Virtual Gateway (%s): %s", arn, err) } tags = tags.IgnoreAWS().IgnoreConfig(ignoreTagsConfig) @@ -814,24 +740,24 @@ func resourceVirtualGatewayUpdate(ctx context.Context, d *schema.ResourceData, m Spec: expandVirtualGatewaySpec(d.Get("spec").([]interface{})), VirtualGatewayName: aws.String(d.Get("name").(string)), } + if v, ok := d.GetOk("mesh_owner"); ok { input.MeshOwner = aws.String(v.(string)) } - log.Printf("[DEBUG] Updating App Mesh virtual gateway: %s", input) _, err := conn.UpdateVirtualGatewayWithContext(ctx, input) if err != nil { - return sdkdiag.AppendErrorf(diags, "updating App Mesh virtual gateway (%s): %s", d.Id(), err) + return sdkdiag.AppendErrorf(diags, "updating App Mesh Virtual Gateway (%s): %s", d.Id(), err) } } - arn := d.Get("arn").(string) if d.HasChange("tags_all") { + arn := d.Get("arn").(string) o, n := d.GetChange("tags_all") if err := UpdateTags(ctx, conn, arn, o, n); err != nil { - return sdkdiag.AppendErrorf(diags, "updating App Mesh virtual gateway (%s) tags: %s", arn, err) + return sdkdiag.AppendErrorf(diags, "updating App Mesh Virtual Gateway (%s) tags: %s", arn, err) } } @@ -871,13 +797,12 @@ func resourceVirtualGatewayImport(ctx context.Context, d *schema.ResourceData, m return []*schema.ResourceData{}, fmt.Errorf("wrong format of import ID (%s), use: 'mesh-name/virtual-gateway-name'", d.Id()) } - mesh := parts[0] + meshName := parts[0] name := parts[1] - log.Printf("[DEBUG] Importing App Mesh virtual gateway %s from mesh %s", name, mesh) conn := meta.(*conns.AWSClient).AppMeshConn() - virtualGateway, err := FindVirtualGateway(ctx, conn, mesh, name, "") + virtualGateway, err := FindVirtualGatewayByThreePartKey(ctx, conn, meshName, "", name) if err != nil { return nil, err @@ -890,6 +815,52 @@ func resourceVirtualGatewayImport(ctx context.Context, d *schema.ResourceData, m return []*schema.ResourceData{d}, nil } +func FindVirtualGatewayByThreePartKey(ctx context.Context, conn *appmesh.AppMesh, meshName, meshOwner, name string) (*appmesh.VirtualGatewayData, error) { + input := &appmesh.DescribeVirtualGatewayInput{ + MeshName: aws.String(meshName), + VirtualGatewayName: aws.String(name), + } + if meshOwner != "" { + input.MeshOwner = aws.String(meshOwner) + } + + output, err := findVirtualGateway(ctx, conn, input) + + if err != nil { + return nil, err + } + + if status := aws.StringValue(output.Status.Status); status == appmesh.VirtualGatewayStatusCodeDeleted { + return nil, &resource.NotFoundError{ + Message: status, + LastRequest: input, + } + } + + return output, nil +} + +func findVirtualGateway(ctx context.Context, conn *appmesh.AppMesh, input *appmesh.DescribeVirtualGatewayInput) (*appmesh.VirtualGatewayData, error) { + output, err := conn.DescribeVirtualGatewayWithContext(ctx, input) + + if tfawserr.ErrCodeEquals(err, appmesh.ErrCodeNotFoundException) { + return nil, &resource.NotFoundError{ + LastError: err, + LastRequest: input, + } + } + + if err != nil { + return nil, err + } + + if output == nil || output.VirtualGateway == nil || output.VirtualGateway.Metadata == nil || output.VirtualGateway.Status == nil { + return nil, tfresource.NewEmptyResultError(input) + } + + return output.VirtualGateway, nil +} + func expandVirtualGatewaySpec(vSpec []interface{}) *appmesh.VirtualGatewaySpec { if len(vSpec) == 0 || vSpec[0] == nil { return nil diff --git a/internal/service/appmesh/virtual_gateway_data_source.go b/internal/service/appmesh/virtual_gateway_data_source.go new file mode 100644 index 00000000000..6c8f548ece1 --- /dev/null +++ b/internal/service/appmesh/virtual_gateway_data_source.go @@ -0,0 +1,100 @@ +package appmesh + +import ( + "context" + "time" + + "github.com/aws/aws-sdk-go/aws" + "github.com/hashicorp/terraform-plugin-sdk/v2/diag" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema" + "github.com/hashicorp/terraform-provider-aws/internal/conns" + "github.com/hashicorp/terraform-provider-aws/internal/errs/sdkdiag" + tftags "github.com/hashicorp/terraform-provider-aws/internal/tags" + "github.com/hashicorp/terraform-provider-aws/names" +) + +// @SDKDataSource("aws_appmesh_virtual_gateway") +func DataSourceVirtualGateway() *schema.Resource { + return &schema.Resource{ + ReadWithoutTimeout: dataSourceVirtualGatewayRead, + + Schema: map[string]*schema.Schema{ + "arn": { + Type: schema.TypeString, + Computed: true, + }, + "created_date": { + Type: schema.TypeString, + Computed: true, + }, + "last_updated_date": { + Type: schema.TypeString, + Computed: true, + }, + "mesh_name": { + Type: schema.TypeString, + Required: true, + }, + "mesh_owner": { + Type: schema.TypeString, + Computed: true, + }, + "name": { + Type: schema.TypeString, + Required: true, + }, + "resource_owner": { + Type: schema.TypeString, + Computed: true, + }, + "spec": dataSourcePropertyFromResourceProperty(resourceVirtualGatewaySpecSchema()), + names.AttrTags: tftags.TagsSchemaComputed(), + }, + } +} + +func dataSourceVirtualGatewayRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics { + var diags diag.Diagnostics + conn := meta.(*conns.AWSClient).AppMeshConn() + ignoreTagsConfig := meta.(*conns.AWSClient).IgnoreTagsConfig + + virtualGatewayName := d.Get("name").(string) + virtualGateway, err := FindVirtualGatewayByThreePartKey(ctx, conn, d.Get("mesh_name").(string), d.Get("mesh_owner").(string), virtualGatewayName) + + if err != nil { + return sdkdiag.AppendErrorf(diags, "reading App Mesh Virtual Gateway (%s): %s", virtualGatewayName, err) + } + + d.SetId(aws.StringValue(virtualGateway.VirtualGatewayName)) + arn := aws.StringValue(virtualGateway.Metadata.Arn) + d.Set("arn", arn) + d.Set("created_date", virtualGateway.Metadata.CreatedAt.Format(time.RFC3339)) + d.Set("last_updated_date", virtualGateway.Metadata.LastUpdatedAt.Format(time.RFC3339)) + d.Set("mesh_name", virtualGateway.MeshName) + meshOwner := aws.StringValue(virtualGateway.Metadata.MeshOwner) + d.Set("mesh_owner", meshOwner) + d.Set("name", virtualGateway.VirtualGatewayName) + d.Set("resource_owner", virtualGateway.Metadata.ResourceOwner) + if err := d.Set("spec", flattenVirtualGatewaySpec(virtualGateway.Spec)); err != nil { + return sdkdiag.AppendErrorf(diags, "setting spec: %s", err) + } + + // https://docs.aws.amazon.com/app-mesh/latest/userguide/sharing.html#sharing-permissions + // Owners and consumers can list tags and can tag/untag resources in a mesh that the account created. + // They can't list tags and tag/untag resources in a mesh that aren't created by the account. + var tags tftags.KeyValueTags + + if meshOwner == meta.(*conns.AWSClient).AccountID { + tags, err = ListTags(ctx, conn, arn) + + if err != nil { + return sdkdiag.AppendErrorf(diags, "listing tags for App Mesh Virtual Gateway (%s): %s", arn, err) + } + } + + if err := d.Set("tags", tags.IgnoreAWS().IgnoreConfig(ignoreTagsConfig).Map()); err != nil { + return sdkdiag.AppendErrorf(diags, "setting tags: %s", err) + } + + return diags +} diff --git a/internal/service/appmesh/virtual_gateway_data_source_test.go b/internal/service/appmesh/virtual_gateway_data_source_test.go new file mode 100644 index 00000000000..482c2628373 --- /dev/null +++ b/internal/service/appmesh/virtual_gateway_data_source_test.go @@ -0,0 +1,70 @@ +package appmesh_test + +import ( + "fmt" + "testing" + + "github.com/aws/aws-sdk-go/service/appmesh" + sdkacctest "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" + "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" + "github.com/hashicorp/terraform-provider-aws/internal/acctest" +) + +func testAccVirtualGatewayDataSource_basic(t *testing.T) { + ctx := acctest.Context(t) + rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + vgName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix) + resourceName := "aws_appmesh_virtual_gateway.test" + dataSourceName := "data.aws_appmesh_virtual_gateway.test" + + resource.Test(t, resource.TestCase{ + PreCheck: func() { acctest.PreCheck(ctx, t); acctest.PreCheckPartitionHasService(t, appmesh.EndpointsID) }, + ErrorCheck: acctest.ErrorCheck(t, appmesh.EndpointsID), + ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories, + Steps: []resource.TestStep{ + { + Config: testAccVirtualGatewayDataSourceConfig_basic(rName, vgName), + Check: resource.ComposeAggregateTestCheckFunc( + resource.TestCheckResourceAttrPair(resourceName, "arn", dataSourceName, "arn"), + resource.TestCheckResourceAttrPair(resourceName, "created_date", dataSourceName, "created_date"), + resource.TestCheckResourceAttrPair(resourceName, "last_updated_date", dataSourceName, "last_updated_date"), + resource.TestCheckResourceAttrPair(resourceName, "mesh_owner", dataSourceName, "mesh_owner"), + resource.TestCheckResourceAttrPair(resourceName, "name", dataSourceName, "name"), + resource.TestCheckResourceAttrPair(resourceName, "resource_owner", dataSourceName, "resource_owner"), + resource.TestCheckResourceAttrPair(resourceName, "spec.#", dataSourceName, "spec.#"), + resource.TestCheckResourceAttrPair(resourceName, "spec.0.backend_defaults.#", dataSourceName, "spec.0.backend_defaults.#"), + resource.TestCheckResourceAttrPair(resourceName, "spec.0.listener.#", dataSourceName, "spec.0.listener.#"), + resource.TestCheckResourceAttrPair(resourceName, "spec.0.logging.#", dataSourceName, "spec.0.logging.#"), + resource.TestCheckResourceAttrPair(resourceName, "tags.%", dataSourceName, "tags.%"), + ), + }, + }, + }) +} + +func testAccVirtualGatewayDataSourceConfig_basic(meshName, vgName string) string { + return fmt.Sprintf(` +resource "aws_appmesh_mesh" "test" { + name = %[1]q +} + +resource "aws_appmesh_virtual_gateway" "test" { + name = %[2]q + mesh_name = aws_appmesh_mesh.test.id + + spec { + listener { + port_mapping { + port = 8080 + protocol = "http" + } + } + } +} + +data "aws_appmesh_virtual_gateway" "test" { + name = aws_appmesh_virtual_gateway.test.name + mesh_name = aws_appmesh_mesh.test.name +} +`, meshName, vgName) +} diff --git a/internal/service/appmesh/virtual_gateway_test.go b/internal/service/appmesh/virtual_gateway_test.go index 747c8abf51d..4bafc9a4c5f 100644 --- a/internal/service/appmesh/virtual_gateway_test.go +++ b/internal/service/appmesh/virtual_gateway_test.go @@ -7,13 +7,13 @@ import ( "github.com/aws/aws-sdk-go/service/acmpca" "github.com/aws/aws-sdk-go/service/appmesh" - "github.com/hashicorp/aws-sdk-go-base/v2/awsv1shim/v2/tfawserr" sdkacctest "github.com/hashicorp/terraform-plugin-sdk/v2/helper/acctest" "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource" "github.com/hashicorp/terraform-plugin-sdk/v2/terraform" "github.com/hashicorp/terraform-provider-aws/internal/acctest" "github.com/hashicorp/terraform-provider-aws/internal/conns" tfappmesh "github.com/hashicorp/terraform-provider-aws/internal/service/appmesh" + "github.com/hashicorp/terraform-provider-aws/internal/tfresource" ) func testAccVirtualGateway_basic(t *testing.T) { @@ -922,43 +922,47 @@ func testAccCheckVirtualGatewayDestroy(ctx context.Context) resource.TestCheckFu conn := acctest.Provider.Meta().(*conns.AWSClient).AppMeshConn() for _, rs := range s.RootModule().Resources { - if rs.Type != "aws_appmesh_virtual_node" { + if rs.Type != "aws_appmesh_virtual_gateway" { continue } - _, err := tfappmesh.FindVirtualGateway(ctx, conn, rs.Primary.Attributes["mesh_name"], rs.Primary.Attributes["name"], rs.Primary.Attributes["mesh_owner"]) - if tfawserr.ErrCodeEquals(err, appmesh.ErrCodeNotFoundException) { + _, err := tfappmesh.FindVirtualGatewayByThreePartKey(ctx, conn, rs.Primary.Attributes["mesh_name"], rs.Primary.Attributes["mesh_owner"], rs.Primary.Attributes["name"]) + + if tfresource.NotFound(err) { continue } + if err != nil { return err } - return fmt.Errorf("App Mesh virtual gateway still exists: %s", rs.Primary.ID) + + return fmt.Errorf("App Mesh Virtual Gateway %s still exists", rs.Primary.ID) } return nil } } -func testAccCheckVirtualGatewayExists(ctx context.Context, name string, v *appmesh.VirtualGatewayData) resource.TestCheckFunc { +func testAccCheckVirtualGatewayExists(ctx context.Context, n string, v *appmesh.VirtualGatewayData) resource.TestCheckFunc { return func(s *terraform.State) error { conn := acctest.Provider.Meta().(*conns.AWSClient).AppMeshConn() - rs, ok := s.RootModule().Resources[name] + rs, ok := s.RootModule().Resources[n] if !ok { - return fmt.Errorf("Not found: %s", name) + return fmt.Errorf("Not found: %s", n) } if rs.Primary.ID == "" { - return fmt.Errorf("No App Mesh virtual gateway ID is set") + return fmt.Errorf("No App Mesh Virtual Gateway ID is set") } - out, err := tfappmesh.FindVirtualGateway(ctx, conn, rs.Primary.Attributes["mesh_name"], rs.Primary.Attributes["name"], rs.Primary.Attributes["mesh_owner"]) + output, err := tfappmesh.FindVirtualGatewayByThreePartKey(ctx, conn, rs.Primary.Attributes["mesh_name"], rs.Primary.Attributes["mesh_owner"], rs.Primary.Attributes["name"]) + if err != nil { return err } - *v = *out + *v = *output return nil } diff --git a/internal/service/appmesh/virtual_service_data_source.go b/internal/service/appmesh/virtual_service_data_source.go index f926dd8838a..804cc7cf481 100644 --- a/internal/service/appmesh/virtual_service_data_source.go +++ b/internal/service/appmesh/virtual_service_data_source.go @@ -49,7 +49,7 @@ func DataSourceVirtualService() *schema.Resource { Computed: true, }, "spec": dataSourcePropertyFromResourceProperty(resourceVirualServiceSpecSchema()), - names.AttrTags: tftags.TagsSchema(), + names.AttrTags: tftags.TagsSchemaComputed(), }, } } diff --git a/website/docs/d/appmesh_virtual_gateway.html.markdown b/website/docs/d/appmesh_virtual_gateway.html.markdown new file mode 100644 index 00000000000..439597ff310 --- /dev/null +++ b/website/docs/d/appmesh_virtual_gateway.html.markdown @@ -0,0 +1,221 @@ +--- +subcategory: "App Mesh" +layout: "aws" +page_title: "AWS: aws_appmesh_virtual_gateway" +description: |- + Terraform data source for managing an AWS App Mesh Virtual Gateway. +--- + +# Data Source: aws_appmesh_virtual_gateway + +Terraform data source for managing an AWS App Mesh Virtual Gateway. + +## Example Usage + +### Basic Usage + +```hcl +data "aws_appmesh_virtual_gateway" "example" { + mesh_name = "mesh-gateway" + name = "example-mesh" +} +``` + +```hcl +data "aws_caller_identity" "current" {} + +data "aws_appmesh_virtual_gateway" "test" { + name = "example.mesh.local" + mesh_name = "example-mesh" + mesh_owner = data.aws_caller_identity.current.account_id +} +``` + +## Argument Reference + +The following arguments are required: + +* `name` - (Required) Name of the virtual gateway. +* `mesh_name` - (Required) Name of the service mesh in which the virtual gateway exists. +* `mesh_owner` - (Optional) AWS account ID of the service mesh's owner. + +## Attributes Reference + +In addition to all arguments above, the following attributes are exported: + +* `arn` - ARN of the virtual gateway. +* `created_date` - Creation date of the virtual gateway. +* `last_updated_date` - Last update date of the virtual gateway. +* `resource_owner` - Resource owner's AWS account ID. +* `spec` - Virtual gateway specification +* `tags` - Map of tags. + +### Spec + +* `listener` - Listeners that the mesh endpoint is expected to receive inbound traffic from. You can specify one listener. +* `backend_defaults` - Defaults for backends. +* `logging` - Inbound and outbound access logging information for the virtual gateway. + +### Backend_defaults + +* `client_policy` - Default client policy for virtual gateway backends. + +### Client_policy + +* `tls` - Transport Layer Security (TLS) client policy. + +### Tls + +* `certificate` - Virtual gateway's client's Transport Layer Security (TLS) certificate. +* `enforce` - Whether the policy is enforced. Default is `true`. +* `ports` - One or more ports that the policy is enforced for. +* `validation` - TLS validation context. + +### Certificate + +* `file` - Local file certificate. +* `sds` - A [Secret Discovery Service](https://www.envoyproxy.io/docs/envoy/latest/configuration/security/secret#secret-discovery-service-sds) certificate. + +### File + +* `certificate_chain` - Certificate chain for the certificate. +* `private_key` - Private key for a certificate stored on the file system of the mesh endpoint that the proxy is running on. + +### Sds + +* `secret_name` - Name of the secret requested from the Secret Discovery Service provider representing Transport Layer Security (TLS) materials like a certificate or certificate chain. + +### Validation + +* `subject_alternative_names` - SANs for a virtual gateway's listener's Transport Layer Security (TLS) validation context. +* `trust` - TLS validation context trust. + +### Subject_alternative_names + +* `match` - Criteria for determining a SAN's match. + +### Match + +* `exact` - Values sent must match the specified values exactly. + +### Trust + +* `acm` - TLS validation context trust for an AWS Certificate Manager (ACM) certificate. +* `file` - TLS validation context trust for a local file certificate. +* `sds` - TLS validation context trust for a [Secret Discovery Service](https://www.envoyproxy.io/docs/envoy/latest/configuration/security/secret#secret-discovery-service-sds) certificate. + +### Acm + +* `certificate_authority_arns` - One or more ACM ARNs. + +### File + +* `certificate_chain` - Certificate trust chain for a certificate stored on the file system of the mesh endpoint that the proxy is running on. Must be between 1 and 255 characters in length. + +### Sds + +* `secret_name` - Name of the secret for a virtual gateway's Transport Layer Security (TLS) Secret Discovery Service validation context trust. + +### Listener + +* `port_mapping` - Port mapping information for the listener. +* `connection_pool` - Connection pool information for the listener. +* `health_check` - Health check information for the listener. +* `tls` - Transport Layer Security (TLS) properties for the listener + +### Logging + +* `access_log` - Access log configuration for a virtual gateway. + +### Access_log + +* `file` - File object to send virtual gateway access logs to. + +### File + +* `path` - File path to write access logs to. You can use `/dev/stdout` to send access logs to standard out. Must be between 1 and 255 characters in length. + +### Port_mapping + +* `port` - Port used for the port mapping. +* `protocol` - Protocol used for the port mapping. Valid values are `http`, `http2`, `tcp` and `grpc`. + +### Connection_pool + +* `grpc` - Connection pool information for gRPC listeners. +* `http` - Connection pool information for HTTP listeners. +* `http2` - Connection pool information for HTTP2 listeners. + +### Grpc + +* `max_requests` - Maximum number of inflight requests Envoy can concurrently support across hosts in upstream cluster. Minimum value of `1`. + +### Http + +* `max_connections` - Maximum number of outbound TCP connections Envoy can establish concurrently with all hosts in upstream cluster. Minimum value of `1`. +* `max_pending_requests` - Number of overflowing requests after `max_connections` Envoy will queue to upstream cluster. Minimum value of `1`. + +### Http2 + +* `max_requests` - Maximum number of inflight requests Envoy can concurrently support across hosts in upstream cluster. Minimum value of `1`. + +### Health_check + +* `healthy_threshold` - Number of consecutive successful health checks that must occur before declaring listener healthy. +* `interval_millis`- Time period in milliseconds between each health check execution. +* `protocol` - Protocol for the health check request. Valid values are `http`, `http2`, and `grpc`. +* `timeout_millis` - Amount of time to wait when receiving a response from the health check, in milliseconds. +* `unhealthy_threshold` - Number of consecutive failed health checks that must occur before declaring a virtual gateway unhealthy. +* `path` - Destination path for the health check request. This is only required if the specified protocol is `http` or `http2`. +* `port` - Destination port for the health check request. This port must match the port defined in the `port_mapping` for the listener. + +### Tls + +* `certificate` - Listener's TLS certificate. +* `mode`- Listener's TLS mode. Valid values: `DISABLED`, `PERMISSIVE`, `STRICT`. +* `validation`- Listener's Transport Layer Security (TLS) validation context. + +### Certificate + +* `acm` - An AWS Certificate Manager (ACM) certificate. +* `file` - Local file certificate. +* `sds` - A [Secret Discovery Service](https://www.envoyproxy.io/docs/envoy/latest/configuration/security/secret#secret-discovery-service-sds) certificate. + +### Acm + +* `certificate_arn` - ARN for the certificate. + +### File + +* `certificate_chain` - Certificate chain for the certificate. Must be between 1 and 255 characters in length. +* `private_key` - Private key for a certificate stored on the file system of the mesh endpoint that the proxy is running on. Must be between 1 and 255 characters in length. + +### Sds + +* `secret_name` - Name of the secret requested from the Secret Discovery Service provider representing Transport Layer Security (TLS) materials like a certificate or certificate chain. + +### Validation + +* `subject_alternative_names` - SANs for a virtual gateway's listener's Transport Layer Security (TLS) validation context. +* `trust` - TLS validation context trust. + +### Subject_alternative_names + +* `match` - Criteria for determining a SAN's match. + +### Match + +* `exact` - Values sent must match the specified values exactly. + +### Trust + +* `file` - TLS validation context trust for a local file certificate. +* `sds` - TLS validation context trust for a [Secret Discovery Service](https://www.envoyproxy.io/docs/envoy/latest/configuration/security/secret#secret-discovery-service-sds) certificate. + +### File + +* `certificate_chain` - Certificate trust chain for a certificate stored on the file system of the mesh endpoint that the proxy is running on. Must be between 1 and 255 characters in length. + +### Sds + +* `secret_name` - Name of the secret for a virtual gateway's Transport Layer Security (TLS) Secret Discovery Service validation context trust.