Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .changelog/44995.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
```release-note:enhancement
resource/aws_cloudwatch_log_delivery_destination: Make `delivery_destination_type` and `delivery_destination_configuration` optional to support AWS X-Ray as a destination
```
70 changes: 70 additions & 0 deletions internal/service/bedrockagentcore/gateway_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,41 @@ func TestAccBedrockAgentCoreGateway_basic(t *testing.T) {
})
}

func TestAccBedrockAgentCoreGateway_xrayDelivery(t *testing.T) {
ctx := acctest.Context(t)
var gateway bedrockagentcorecontrol.GetGatewayOutput
rName := sdkacctest.RandomWithPrefix(acctest.ResourcePrefix)
resourceName := "aws_bedrockagentcore_gateway.test"
deliveryResourceName := "aws_cloudwatch_log_delivery.test"

resource.ParallelTest(t, resource.TestCase{
PreCheck: func() {
acctest.PreCheck(ctx, t)
acctest.PreCheckPartitionHasService(t, names.BedrockEndpointID)
testAccPreCheckGateways(ctx, t)
},
ErrorCheck: acctest.ErrorCheck(t, names.BedrockAgentCoreServiceID),
ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories,
CheckDestroy: testAccCheckGatewayDestroy(ctx),
Steps: []resource.TestStep{
{
Config: testAccGatewayConfig_xrayDelivery(rName),
Check: resource.ComposeAggregateTestCheckFunc(
testAccCheckGatewayExists(ctx, resourceName, &gateway),
resource.TestCheckResourceAttrSet(deliveryResourceName, names.AttrID),
resource.TestCheckResourceAttr(deliveryResourceName, "delivery_source_name", rName+"-source"),
),
ConfigPlanChecks: resource.ConfigPlanChecks{
PreApply: []plancheck.PlanCheck{
plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate),
plancheck.ExpectResourceAction(deliveryResourceName, plancheck.ResourceActionCreate),
},
},
},
},
})
}

func TestAccBedrockAgentCoreGateway_disappears(t *testing.T) {
ctx := acctest.Context(t)
var gateway bedrockagentcorecontrol.GetGatewayOutput
Expand Down Expand Up @@ -492,6 +527,41 @@ resource "aws_bedrockagentcore_gateway" "test" {
`, rName))
}

func testAccGatewayConfig_xrayDelivery(rName string) string {
return acctest.ConfigCompose(testAccGatewayConfig_iamRole(rName), fmt.Sprintf(`
resource "aws_bedrockagentcore_gateway" "test" {
name = %[1]q
role_arn = aws_iam_role.test.arn
authorizer_type = "CUSTOM_JWT"
authorizer_configuration {
custom_jwt_authorizer {
discovery_url = "https://accounts.google.com/.well-known/openid-configuration"
allowed_audience = ["test1", "test2"]
}
}
protocol_type = "MCP"
}
resource "aws_cloudwatch_log_delivery_source" "test" {
name = "%[1]s-source"
log_type = "TRACES"
resource_arn = aws_bedrockagentcore_gateway.test.gateway_arn
}
resource "aws_cloudwatch_log_delivery_destination" "test" {
name = "%[1]s-destination"
delivery_destination_type = "XRAY"
}
resource "aws_cloudwatch_log_delivery" "test" {
delivery_source_name = aws_cloudwatch_log_delivery_source.test.name
delivery_destination_arn = aws_cloudwatch_log_delivery_destination.test.arn
}
`, rName))
}

func testAccGatewayConfig_protocolConfiguration(rName, instructions string) string {
return acctest.ConfigCompose(testAccGatewayConfig_iamRole(rName), fmt.Sprintf(`
resource "aws_bedrockagentcore_gateway" "test" {
Expand Down
40 changes: 37 additions & 3 deletions internal/service/logs/delivery_destination.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,7 @@ func (r *deliveryDestinationResource) Schema(ctx context.Context, request resour
names.AttrARN: framework.ARNAttributeComputedOnly(),
"delivery_destination_type": schema.StringAttribute{
CustomType: fwtypes.StringEnumType[awstypes.DeliveryDestinationType](),
Optional: true,
Computed: true,
},
names.AttrName: schema.StringAttribute{
Expand All @@ -75,15 +76,13 @@ func (r *deliveryDestinationResource) Schema(ctx context.Context, request resour
"delivery_destination_configuration": schema.ListNestedBlock{
CustomType: fwtypes.NewListNestedObjectTypeOf[deliveryDestinationConfigurationModel](ctx),
Validators: []validator.List{
listvalidator.IsRequired(),
listvalidator.SizeAtLeast(1),
listvalidator.SizeAtMost(1),
},
NestedObject: schema.NestedBlockObject{
Attributes: map[string]schema.Attribute{
"destination_resource_arn": schema.StringAttribute{
CustomType: fwtypes.ARNType,
Required: true,
Optional: true,
PlanModifiers: []planmodifier.String{
stringplanmodifier.RequiresReplaceIf(requiresReplaceIfARNServiceChanges, "", ""),
},
Expand All @@ -95,6 +94,34 @@ func (r *deliveryDestinationResource) Schema(ctx context.Context, request resour
}
}

func (r *deliveryDestinationResource) ValidateConfig(ctx context.Context, request resource.ValidateConfigRequest, response *resource.ValidateConfigResponse) {
var data deliveryDestinationResourceModel
response.Diagnostics.Append(request.Config.Get(ctx, &data)...)
if response.Diagnostics.HasError() {
return
}

isXray := !data.DeliveryDestinationType.IsNull() && !data.DeliveryDestinationType.IsUnknown() &&
data.DeliveryDestinationType.ValueString() == string(awstypes.DeliveryDestinationTypeXray)
hasConfig := !data.DeliveryDestinationConfiguration.IsNull() && !data.DeliveryDestinationConfiguration.IsUnknown()

if isXray && hasConfig {
response.Diagnostics.AddAttributeError(
path.Root("delivery_destination_configuration"),
"Invalid Configuration",
"delivery_destination_configuration must not be set when delivery_destination_type is XRAY",
)
}

if !isXray && !hasConfig && !data.DeliveryDestinationType.IsUnknown() && !data.DeliveryDestinationConfiguration.IsUnknown() {
response.Diagnostics.AddAttributeError(
path.Root("delivery_destination_configuration"),
"Missing Configuration",
"delivery_destination_configuration is required when delivery_destination_type is not XRAY",
)
}
}

func (r *deliveryDestinationResource) Create(ctx context.Context, request resource.CreateRequest, response *resource.CreateResponse) {
var data deliveryDestinationResourceModel
response.Diagnostics.Append(request.Plan.Get(ctx, &data)...)
Expand Down Expand Up @@ -152,6 +179,13 @@ func (r *deliveryDestinationResource) Read(ctx context.Context, request resource
return
}

// Handle empty destination_resource_arn for XRAY type destinations
// Clear it before flattening to avoid ARN validation error
if output.DeliveryDestinationConfiguration != nil &&
aws.ToString(output.DeliveryDestinationConfiguration.DestinationResourceArn) == "" {
output.DeliveryDestinationConfiguration = nil
}

// Set attributes for import.
response.Diagnostics.Append(fwflex.Flatten(ctx, output, &data)...)
if response.Diagnostics.HasError() {
Expand Down
50 changes: 50 additions & 0 deletions internal/service/logs/delivery_destination_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,47 @@ func TestAccLogsDeliveryDestination_disappears(t *testing.T) {
})
}

func TestAccLogsDeliveryDestination_XRAY(t *testing.T) {
ctx := acctest.Context(t)
var v awstypes.DeliveryDestination
rName := acctest.RandomWithPrefix(t, acctest.ResourcePrefix)
resourceName := "aws_cloudwatch_log_delivery_destination.test"

acctest.ParallelTest(ctx, t, resource.TestCase{
PreCheck: func() {
acctest.PreCheck(ctx, t)
},
ErrorCheck: acctest.ErrorCheck(t, names.LogsServiceID),
ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories,
CheckDestroy: testAccCheckDeliveryDestinationDestroy(ctx, t),
Steps: []resource.TestStep{
{
Config: testAccDeliveryDestinationConfig_xray(rName),
Check: resource.ComposeTestCheckFunc(
testAccCheckDeliveryDestinationExists(ctx, t, resourceName, &v),
),
ConfigPlanChecks: resource.ConfigPlanChecks{
PreApply: []plancheck.PlanCheck{
plancheck.ExpectResourceAction(resourceName, plancheck.ResourceActionCreate),
},
},
ConfigStateChecks: []statecheck.StateCheck{
statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrARN), knownvalue.NotNull()),
statecheck.ExpectKnownValue(resourceName, tfjsonpath.New("delivery_destination_type"), knownvalue.StringExact("XRAY")),
statecheck.ExpectKnownValue(resourceName, tfjsonpath.New(names.AttrName), knownvalue.StringExact(rName)),
},
},
{
ResourceName: resourceName,
ImportState: true,
ImportStateVerify: true,
ImportStateIdFunc: testAccDeliveryDestinationImportStateIDFunc(resourceName),
ImportStateVerifyIdentifierAttribute: names.AttrName,
},
},
})
}

func TestAccLogsDeliveryDestination_tags(t *testing.T) {
ctx := acctest.Context(t)
var v awstypes.DeliveryDestination
Expand Down Expand Up @@ -456,6 +497,15 @@ resource "aws_cloudwatch_log_delivery_destination" "test" {
`, rName)
}

func testAccDeliveryDestinationConfig_xray(rName string) string {
return fmt.Sprintf(`
resource "aws_cloudwatch_log_delivery_destination" "test" {
name = %[1]q
delivery_destination_type = "XRAY"
}
`, rName)
}

func testAccDeliveryDestinationConfig_tags1(rName, tag1Key, tag1Value string) string {
return fmt.Sprintf(`
resource "aws_cloudwatch_log_group" "test" {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,23 @@ resource "aws_cloudwatch_log_delivery_destination" "example" {
}
```

### X-Ray Trace Delivery

```terraform
resource "aws_cloudwatch_log_delivery_destination" "xray" {
name = "xray-traces"
delivery_destination_type = "XRAY"
}
```

## Argument Reference

This resource supports the following arguments:

* `region` - (Optional) Region where this resource will be [managed](https://docs.aws.amazon.com/general/latest/gr/rande.html#regional-endpoints). Defaults to the Region set in the [provider configuration](https://registry.terraform.io/providers/hashicorp/aws/latest/docs#aws-configuration-reference).
* `delivery_destination_configuration` - (Required) The AWS resource that will receive the logs.
* `destination_resource_arn` - (Required) The ARN of the AWS destination that this delivery destination represents.
* `delivery_destination_configuration` - (Optional) The AWS resource that will receive the logs. Required for CloudWatch Logs, Amazon S3, and Firehose destinations. Not required for X-Ray trace delivery destinations.
* `destination_resource_arn` - (Optional) The ARN of the AWS destination that this delivery destination represents. Required when `delivery_destination_configuration` is specified.
* `delivery_destination_type` - (Optional) The type of delivery destination. Valid values: `S3`, `CWL`, `FH`, `XRAY`. Required for X-Ray trace delivery destinations. For other destination types, this is computed from the `destination_resource_arn`.
* `name` - (Required) The name for this delivery destination.
* `output_format` - (Optional) The format of the logs that are sent to this delivery destination. Valid values: `json`, `plain`, `w3c`, `raw`, `parquet`.
* `tags` - (Optional) A map of tags to assign to the resource. If configured with a provider [`default_tags` configuration block](https://registry.terraform.io/providers/hashicorp/aws/latest/docs#default_tags-configuration-block) present, tags with matching keys will overwrite those defined at the provider-level.
Expand All @@ -40,7 +50,6 @@ This resource supports the following arguments:
This resource exports the following attributes in addition to the arguments above:

* `arn` - The Amazon Resource Name (ARN) of the delivery destination.
* `delivery_destination_type` - Whether this delivery destination is CloudWatch Logs, Amazon S3, or Firehose.
* `tags_all` - A map of tags assigned to the resource, including those inherited from the provider [`default_tags` configuration block](https://registry.terraform.io/providers/hashicorp/aws/latest/docs#default_tags-configuration-block).

## Import
Expand Down
Loading