Skip to content

Commit

Permalink
provider: add services map to private_endpoint_services (#219)
Browse files Browse the repository at this point in the history
Previously, the private_endpoint_services resource contains the regional
services in a list. This made it hard for users to access the service
for a given region. This commit adds a service map that contains all the
services but are keyed by the cloud region.
  • Loading branch information
carloruiz authored Jun 19, 2024
1 parent 052f11c commit bc77c78
Show file tree
Hide file tree
Showing 15 changed files with 341 additions and 59 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

- Enable log export for serverless clusters.

- Add services_map to private_endpoint_services resource.

## [1.7.6] - 2024-06-10

## Fixed
Expand Down
6 changes: 3 additions & 3 deletions docs/resources/private_endpoint_connection.md
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ resource "cockroach_private_endpoint_services" "aws_cluster_services" {
# Create a PrivateLink endpoint and associate it with the PrivateLink Service.
resource "aws_vpc_endpoint" "my_endpoint" {
vpc_id = "vpc-7fc0a543"
service_name = cockroach_private_endpoint_services.aws_cluster_services.services[0].name
service_name = cockroach_private_endpoint_services.aws_cluster_services.services_map["us-east-1"].name
vpc_endpoint_type = "Interface"
subnet_ids = ["subnet-de0406d2"]
security_group_ids = ["sg-3f238186"]
Expand All @@ -49,8 +49,8 @@ resource "azurerm_private_endpoint" "my_endpoint" {
resource_group_name = var.resource_group_name
subnet_id = azurerm_subnet.my_subnet.id
private_service_connection {
name = cockroach_private_endpoint_services.azure_cluster_services.services[0].name
private_connection_resource_id = cockroach_private_endpoint_services.azure_cluster_services.services[0].endpoint_service_id
name = cockroach_private_endpoint_services.azure_cluster_services.services_map["eastus2"].name
private_connection_resource_id = cockroach_private_endpoint_services.azure_cluster_services.services_map["eastus2"].endpoint_service_id
is_manual_connection = true
request_message = "Azure Private Link test"
}
Expand Down
25 changes: 25 additions & 0 deletions docs/resources/private_endpoint_services.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ resource "cockroach_private_endpoint_services" "cockroach" {

- `id` (String) Always matches the cluster ID. Required by Terraform.
- `services` (Attributes List) (see [below for nested schema](#nestedatt--services))
- `services_map` (Attributes Map) a map of services keyed by the region name (see [below for nested schema](#nestedatt--services_map))

<a id="nestedatt--services"></a>
### Nested Schema for `services`
Expand All @@ -56,6 +57,30 @@ Read-Only:
- `service_id` (String) Server side ID of the PrivateLink connection.
- `service_name` (String) AWS service name used to create endpoints.



<a id="nestedatt--services_map"></a>
### Nested Schema for `services_map`

Read-Only:

- `availability_zone_ids` (List of String) Availability Zone IDs of the private endpoint service. It is recommended, for cost optimization purposes, to create the private endpoint spanning these same availability zones. For more information, see data transfer cost information for your cloud provider.
- `aws` (Attributes, Deprecated) (see [below for nested schema](#nestedatt--services_map--aws))
- `cloud_provider` (String) Cloud provider associated with this service.
- `endpoint_service_id` (String) Server side ID of the private endpoint connection.
- `name` (String) Name of the endpoint service.
- `region_name` (String) Cloud provider region code associated with this service.
- `status` (String) Operation status of the service.

<a id="nestedatt--services_map--aws"></a>
### Nested Schema for `services_map.aws`

Read-Only:

- `availability_zone_ids` (List of String) AZ IDs users should create their VPCs in to minimize their cost.
- `service_id` (String) Server side ID of the PrivateLink connection.
- `service_name` (String) AWS service name used to create endpoints.

## Import

Import is supported using the following syntax:
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ resource "cockroach_private_endpoint_services" "aws_cluster_services" {
# Create a PrivateLink endpoint and associate it with the PrivateLink Service.
resource "aws_vpc_endpoint" "my_endpoint" {
vpc_id = "vpc-7fc0a543"
service_name = cockroach_private_endpoint_services.aws_cluster_services.services[0].name
service_name = cockroach_private_endpoint_services.aws_cluster_services.services_map["us-east-1"].name
vpc_endpoint_type = "Interface"
subnet_ids = ["subnet-de0406d2"]
security_group_ids = ["sg-3f238186"]
Expand All @@ -34,8 +34,8 @@ resource "azurerm_private_endpoint" "my_endpoint" {
resource_group_name = var.resource_group_name
subnet_id = azurerm_subnet.my_subnet.id
private_service_connection {
name = cockroach_private_endpoint_services.azure_cluster_services.services[0].name
private_connection_resource_id = cockroach_private_endpoint_services.azure_cluster_services.services[0].endpoint_service_id
name = cockroach_private_endpoint_services.azure_cluster_services.services_map["eastus2"].name
private_connection_resource_id = cockroach_private_endpoint_services.azure_cluster_services.services_map["eastus2"].endpoint_service_id
is_manual_connection = true
request_message = "Azure Private Link test"
}
Expand Down
2 changes: 1 addition & 1 deletion examples/workflows/aws_privatelink/main.tf
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,7 @@ resource "aws_subnet" "example" {

resource "aws_vpc_endpoint" "example" {
vpc_id = aws_vpc.example.id
service_name = cockroach_private_endpoint_services.example.services[0].aws.service_name
service_name = cockroach_private_endpoint_services.example.services_map[var.aws_region].name
vpc_endpoint_type = "Interface"
security_group_ids = [aws_security_group.example.id]
subnet_ids = [for s in aws_subnet.example : s.id]
Expand Down
7 changes: 4 additions & 3 deletions internal/provider/models.go
Original file line number Diff line number Diff line change
Expand Up @@ -118,9 +118,10 @@ type PrivateEndpointService struct {
}

type PrivateEndpointServices struct {
ClusterID types.String `tfsdk:"cluster_id"`
Services types.List `tfsdk:"services"`
ID types.String `tfsdk:"id"`
ClusterID types.String `tfsdk:"cluster_id"`
Services types.List `tfsdk:"services"`
ServicesMap types.Map `tfsdk:"services_map"`
ID types.String `tfsdk:"id"`
}

type PrivateEndpointConnection struct {
Expand Down
124 changes: 75 additions & 49 deletions internal/provider/private_endpoint_services_resource.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import (
"github.com/hashicorp/terraform-plugin-framework/resource"
"github.com/hashicorp/terraform-plugin-framework/resource/schema"
"github.com/hashicorp/terraform-plugin-framework/resource/schema/listplanmodifier"
"github.com/hashicorp/terraform-plugin-framework/resource/schema/mapplanmodifier"
"github.com/hashicorp/terraform-plugin-framework/resource/schema/objectplanmodifier"
"github.com/hashicorp/terraform-plugin-framework/resource/schema/planmodifier"
"github.com/hashicorp/terraform-plugin-framework/resource/schema/stringplanmodifier"
Expand Down Expand Up @@ -57,60 +58,70 @@ var endpointServicesSchema = schema.Schema{
},
MarkdownDescription: "Always matches the cluster ID. Required by Terraform.",
},
"services_map": schema.MapNestedAttribute{
Computed: true,
Description: "a map of services keyed by the region name",
PlanModifiers: []planmodifier.Map{
mapplanmodifier.UseStateForUnknown(),
},
NestedObject: serviceObject,
},
"services": schema.ListNestedAttribute{
Computed: true,
PlanModifiers: []planmodifier.List{
listplanmodifier.UseStateForUnknown(),
},
NestedObject: schema.NestedAttributeObject{
Attributes: map[string]schema.Attribute{
"region_name": schema.StringAttribute{
Computed: true,
Description: "Cloud provider region code associated with this service.",
},
"cloud_provider": schema.StringAttribute{
Computed: true,
Description: "Cloud provider associated with this service.",
},
"status": schema.StringAttribute{
Computed: true,
Description: "Operation status of the service.",
},
"name": schema.StringAttribute{
Computed: true,
Description: "Name of the endpoint service.",
},
"endpoint_service_id": schema.StringAttribute{
Computed: true,
Description: "Server side ID of the private endpoint connection.",
},
"availability_zone_ids": schema.ListAttribute{
Computed: true,
ElementType: types.StringType,
MarkdownDescription: "Availability Zone IDs of the private endpoint service. It is recommended, for cost optimization purposes, to create the private endpoint spanning these same availability zones. For more information, see data transfer cost information for your cloud provider.",
},
"aws": schema.SingleNestedAttribute{
DeprecationMessage: "nested aws fields have been moved one level up. These fields will be removed in a future version",
Computed: true,
PlanModifiers: []planmodifier.Object{
objectplanmodifier.UseStateForUnknown(),
},
Attributes: map[string]schema.Attribute{
"service_name": schema.StringAttribute{
Computed: true,
Description: "AWS service name used to create endpoints.",
},
"service_id": schema.StringAttribute{
Computed: true,
Description: "Server side ID of the PrivateLink connection.",
},
"availability_zone_ids": schema.ListAttribute{
Computed: true,
ElementType: types.StringType,
MarkdownDescription: "AZ IDs users should create their VPCs in to minimize their cost.",
},
},
},
NestedObject: serviceObject,
},
},
}

var serviceObject = schema.NestedAttributeObject{
Attributes: map[string]schema.Attribute{
"region_name": schema.StringAttribute{
Computed: true,
Description: "Cloud provider region code associated with this service.",
},
"cloud_provider": schema.StringAttribute{
Computed: true,
Description: "Cloud provider associated with this service.",
},
"status": schema.StringAttribute{
Computed: true,
Description: "Operation status of the service.",
},
"name": schema.StringAttribute{
Computed: true,
Description: "Name of the endpoint service.",
},
"endpoint_service_id": schema.StringAttribute{
Computed: true,
Description: "Server side ID of the private endpoint connection.",
},
"availability_zone_ids": schema.ListAttribute{
Computed: true,
ElementType: types.StringType,
MarkdownDescription: "Availability Zone IDs of the private endpoint service. It is recommended, for cost optimization purposes, to create the private endpoint spanning these same availability zones. For more information, see data transfer cost information for your cloud provider.",
},
"aws": schema.SingleNestedAttribute{
DeprecationMessage: "nested aws fields have been moved one level up. These fields will be removed in a future version",
Computed: true,
PlanModifiers: []planmodifier.Object{
objectplanmodifier.UseStateForUnknown(),
},
Attributes: map[string]schema.Attribute{
"service_name": schema.StringAttribute{
Computed: true,
Description: "AWS service name used to create endpoints.",
},
"service_id": schema.StringAttribute{
Computed: true,
Description: "Server side ID of the PrivateLink connection.",
},
"availability_zone_ids": schema.ListAttribute{
Computed: true,
ElementType: types.StringType,
MarkdownDescription: "AZ IDs users should create their VPCs in to minimize their cost.",
},
},
},
Expand Down Expand Up @@ -277,6 +288,21 @@ func loadEndpointServicesIntoTerraformState(
endpointServicesSchema.Attributes["services"].(schema.ListNestedAttribute).NestedObject.Type(),
services,
)

servicesMap := map[string]PrivateEndpointService{}
for _, svc := range services {
servicesMap[svc.RegionName.ValueString()] = svc
}

var diags2 diag.Diagnostics
state.ServicesMap, diags2 = types.MapValueFrom(
ctx,
endpointServicesSchema.Attributes["services_map"].(schema.MapNestedAttribute).NestedObject.Type(),
servicesMap,
)

diags.Append(diags2...)

return diags
}

Expand Down
5 changes: 5 additions & 0 deletions internal/provider/private_endpoint_services_resource_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -227,13 +227,18 @@ func testPrivateEndpointServicesResource(
checks := []resource.TestCheckFunc{
resource.TestCheckResourceAttr(clusterResourceName, "name", clusterName),
resource.TestCheckResourceAttr(resourceName, "services.#", strconv.Itoa(numExpectedServices)),
resource.TestCheckResourceAttr(resourceName, "services_map.%", strconv.Itoa(numExpectedServices)),
}
for i := 0; i < numExpectedServices; i++ {
svc := fmt.Sprintf("services.%d", i)
checks = append(checks,
resource.TestCheckResourceAttr(resourceName, svc+".status", string(client.PRIVATEENDPOINTSERVICESTATUSTYPE_AVAILABLE)),
)

checks = append(checks,
resource.TestCheckResourceAttrPair(resourceName, svc, resourceName, "services_map.us-east-1"),
)

if cloud == client.CLOUDPROVIDERTYPE_AWS {
checks = append(checks, []resource.TestCheckFunc{
resource.TestCheckResourceAttrPair(resourceName, svc+".name", resourceName, svc+".aws.service_name"),
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading

0 comments on commit bc77c78

Please sign in to comment.