Skip to content

Commit

Permalink
fix: display project_vpc_id computed on plan
Browse files Browse the repository at this point in the history
  • Loading branch information
byashimov committed Dec 17, 2024
1 parent 1da9ad7 commit eca4031
Show file tree
Hide file tree
Showing 4 changed files with 90 additions and 5 deletions.
3 changes: 2 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@ nav_order: 1
- Add `alloydbomni` BETA resource and datasource
- Add `aiven_alloydbomni_user` BETA resource and datasource
- Add `aiven_alloydbomni_database` BETA resource and datasource
- Fix `terraform plan`: new resources don't display zero values for user configuration options
- Fix `terraform plan` doesn't display automatically assigned `project_vpc_id`
- Fix `terraform plan` doesn't display fields with zero values in service user config
- Add `aiven_service_integration` resource and datasource field `destination_service_project`: Destination service project name
- Add `aiven_service_integration` resource and datasource field `source_service_project`: Source service project name
- Change `aiven_account_team_project` resource and datasource field `team_type` (enum): remove
Expand Down
58 changes: 58 additions & 0 deletions internal/schemautil/custom_diff.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import (
func CustomizeDiffGenericService(serviceType string) schema.CustomizeDiffFunc {
return customdiff.Sequence(
SetServiceTypeIfEmpty(serviceType),
CustomizeDiffProjectVPCID,
CustomizeDiffDisallowMultipleManyToOneKeys,
customdiff.IfValueChange("tag",
ShouldNotBeEmpty,
Expand Down Expand Up @@ -320,3 +321,60 @@ func CustomizeDiffAdditionalDiskSpace(ctx context.Context, diff *schema.Resource
// which otherwise will be suppressed by TF
return diff.SetNew(k, "0B")
}

// CustomizeDiffProjectVPCID
// 1. Validates project_vpc_id when set
// 2. Sets project_vpc_id when there is only one VPC in the cloud (that's how it works on the backend)
func CustomizeDiffProjectVPCID(ctx context.Context, d *schema.ResourceDiff, _ any) error {
client, err := common.GenClient()
if err != nil {
return err
}

if v, ok := d.GetOk("project_vpc_id"); ok {
return validateProjectVPCID(ctx, client, v.(string))
}

project := d.Get("project").(string)
list, err := client.VpcList(ctx, project)
if err != nil {
return err
}

vpcIDs := make([]string, 0)
cloudName := d.Get("cloud_name").(string)
for _, v := range list {
if v.CloudName == cloudName {
vpcIDs = append(vpcIDs, v.ProjectVpcId)
}
}

switch len(vpcIDs) {
case 0:
// It would be nice to set the project_vpc_id to an empty string here,
// but it just won't work because TF takes "" and nil as nothing set.
// That would still result in project_vpc_id marked "known after apply" in the plan,
// even though we know it's going to be empty.
return nil
case 1:
return d.SetNew("project_vpc_id", BuildResourceID(project, vpcIDs[0]))
}

return fmt.Errorf(
"project %q has multiple active VPCs in cloud %q. Please specify the project_vpc_id: %s",
project, cloudName, strings.Join(vpcIDs, ", "),
)
}

func validateProjectVPCID(ctx context.Context, client avngen.Client, projectVPCID string) error {
project, vpcID, err := SplitResourceID2(projectVPCID)
if err != nil {
return err
}

_, err = client.VpcGet(ctx, project, vpcID)
if avngen.IsNotFound(err) {
return fmt.Errorf("VPC ID %q not found in project %q", vpcID, project)
}
return err
}
25 changes: 25 additions & 0 deletions internal/schemautil/schemautil.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ import (
"github.com/aiven/aiven-go-client/v2"
"github.com/aiven/go-client-codegen/handler/service"
"github.com/docker/go-units"
"github.com/hashicorp/go-cty/cty"
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
)

Expand Down Expand Up @@ -195,6 +197,29 @@ func ValidateEmailAddress(v any, k string) (ws []string, errors []error) {
return
}

// ValidateIDN validates that the given string is a valid resource ID with n parts
func ValidateIDN(n int, expected ...string) schema.SchemaValidateDiagFunc {
if n != len(expected) {
panic(fmt.Sprintf("expected %d parts, got %d", n, len(expected)))
}

return func(i any, _ cty.Path) diag.Diagnostics {
_, err := SplitResourceID(i.(string), n)
if err == nil {
return nil
}

return diag.Errorf(
"invalid resource id, should have the following format %q",
strings.Join(expected, "/"),
)
}
}

func ValidateIDWithProject(expected string) schema.SchemaValidateDiagFunc {
return ValidateIDN(2, "project_name", expected)
}

func BuildResourceID(parts ...string) string {
finalParts := make([]string, len(parts))
for idx, part := range parts {
Expand Down
9 changes: 5 additions & 4 deletions internal/schemautil/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -136,10 +136,11 @@ func ServiceCommonSchema() map[string]*schema.Schema {
Description: "Aiven internal service type code",
},
"project_vpc_id": {
Type: schema.TypeString,
Optional: true,
Computed: true,
Description: "Specifies the VPC the service should run in. If the value is not set the service is not run inside a VPC. When set, the value should be given as a reference to set up dependencies correctly and the VPC must be in the same cloud and region as the service itself. Project can be freely moved to and from VPC after creation but doing so triggers migration to new servers so the operation can take significant amount of time to complete if the service has a lot of data.",
Type: schema.TypeString,
Optional: true,
Computed: true,
Description: "Specifies the VPC the service should run in. If the value is not set the service is not run inside a VPC. When set, the value should be given as a reference to set up dependencies correctly and the VPC must be in the same cloud and region as the service itself. Project can be freely moved to and from VPC after creation but doing so triggers migration to new servers so the operation can take significant amount of time to complete if the service has a lot of data.",
ValidateDiagFunc: ValidateIDWithProject("project_vpc_id"),
},
"maintenance_window_dow": {
Type: schema.TypeString,
Expand Down

0 comments on commit eca4031

Please sign in to comment.