Skip to content

Commit a418375

Browse files
authored
Validate that subnetwork_project should match with the project in subnetwork field in google_compute_instance resource (#11537)
1 parent e30f86c commit a418375

File tree

5 files changed

+111
-1
lines changed

5 files changed

+111
-1
lines changed

mmv1/third_party/terraform/services/compute/resource_compute_instance.go.erb

+31
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,36 @@ var (
9999
}
100100
)
101101

102+
// This checks if the project provided in subnetwork's self_link matches
103+
// the project provided in subnetwork_project not to produce a confusing plan diff.
104+
func validateSubnetworkProject(ctx context.Context, d *schema.ResourceDiff, meta interface{}) error {
105+
// separate func to allow unit testing
106+
return ValidateSubnetworkProjectFunc(d)
107+
}
108+
109+
func ValidateSubnetworkProjectFunc(d tpgresource.TerraformResourceDiff) error {
110+
oldCount, newCount := d.GetChange("network_interface.#")
111+
if oldCount.(int) != newCount.(int) {
112+
return nil
113+
}
114+
for i := 0; i < newCount.(int); i++ {
115+
prefix := fmt.Sprintf("network_interface.%d", i)
116+
subnetworkProject := d.Get(prefix + ".subnetwork_project")
117+
subnetwork := d.Get(prefix + ".subnetwork")
118+
119+
_, err := tpgresource.GetRelativePath(subnetwork.(string))
120+
if err != nil {
121+
log.Printf("[DEBUG] Subnetwork %q is not a selflink", subnetwork)
122+
return nil
123+
}
124+
125+
if tpgresource.GetProjectFromRegionalSelfLink(subnetwork.(string)) != subnetworkProject.(string) {
126+
return fmt.Errorf("project in subnetwork's self_link %q must match subnetwork_project %q", subnetwork, subnetworkProject)
127+
}
128+
}
129+
return nil
130+
}
131+
102132
// network_interface.[d].network_ip can only change when subnet/network
103133
// is also changing. Validate that if network_ip is changing this scenario
104134
// holds up to par.
@@ -1224,6 +1254,7 @@ be from 0 to 999,999,999 inclusive.`,
12241254
suppressEmptyGuestAcceleratorDiff,
12251255
),
12261256
desiredStatusDiff,
1257+
validateSubnetworkProject,
12271258
forceNewIfNetworkIPNotUpdatable,
12281259
tpgresource.SetLabelsDiff,
12291260
),

mmv1/third_party/terraform/services/compute/resource_compute_instance_test.go.erb

+56
Original file line numberDiff line numberDiff line change
@@ -2687,6 +2687,23 @@ func TestAccComputeInstance_subnetworkUpdate(t *testing.T) {
26872687
})
26882688
}
26892689

2690+
func TestAccComputeInstance_subnetworkProjectMustMatchError(t *testing.T) {
2691+
t.Parallel()
2692+
instanceName := fmt.Sprintf("tf-test-%s", acctest.RandString(t, 10))
2693+
suffix := fmt.Sprintf("%s", acctest.RandString(t, 10))
2694+
acctest.VcrTest(t, resource.TestCase{
2695+
PreCheck: func() { acctest.AccTestPreCheck(t) },
2696+
ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t),
2697+
CheckDestroy: testAccCheckComputeInstanceDestroyProducer(t),
2698+
Steps: []resource.TestStep{
2699+
{
2700+
Config: testAccComputeInstance_subnetworkProjectExpectError(suffix, instanceName),
2701+
ExpectError: regexp.MustCompile("must match subnetwork_project"),
2702+
},
2703+
},
2704+
})
2705+
}
2706+
26902707
func TestAccComputeInstance_networkIpUpdate(t *testing.T) {
26912708
t.Parallel()
26922709

@@ -8695,6 +8712,45 @@ func testAccComputeInstance_subnetworkUpdateTwo(suffix, instance string) string
86958712
`, suffix, suffix, suffix, suffix, instance)
86968713
}
86978714

8715+
func testAccComputeInstance_subnetworkProjectExpectError(suffix, instance string) string {
8716+
return fmt.Sprintf(`
8717+
data "google_compute_image" "my_image" {
8718+
family = "debian-11"
8719+
project = "debian-cloud"
8720+
}
8721+
8722+
resource "google_compute_network" "inst-test-network" {
8723+
name = "tf-test-network-%s"
8724+
auto_create_subnetworks = false
8725+
}
8726+
8727+
resource "google_compute_subnetwork" "inst-test-subnetwork" {
8728+
name = "tf-test-compute-subnet-%s"
8729+
ip_cidr_range = "10.0.0.0/16"
8730+
region = "us-east1"
8731+
network = google_compute_network.inst-test-network.id
8732+
}
8733+
8734+
resource "google_compute_instance" "foobar" {
8735+
name = "%s"
8736+
machine_type = "e2-medium"
8737+
zone = "us-east1-d"
8738+
allow_stopping_for_update = true
8739+
8740+
boot_disk {
8741+
initialize_params {
8742+
image = data.google_compute_image.my_image.id
8743+
}
8744+
}
8745+
8746+
network_interface {
8747+
subnetwork = google_compute_subnetwork.inst-test-subnetwork.id
8748+
subnetwork_project = "placeholder"
8749+
}
8750+
}
8751+
`, suffix, suffix, instance)
8752+
}
8753+
86988754
func testAccComputeInstance_networkIpUpdate(suffix, instance string) string {
86998755
return fmt.Sprintf(`
87008756
data "google_compute_image" "my_image" {

mmv1/third_party/terraform/tpgresource/self_link_helpers.go

+11
Original file line numberDiff line numberDiff line change
@@ -170,3 +170,14 @@ func GetRegionFromRegionalSelfLink(selfLink string) string {
170170
}
171171
return selfLink
172172
}
173+
174+
func GetProjectFromRegionalSelfLink(selfLink string) string {
175+
re := regexp.MustCompile("projects/([a-zA-Z0-9-]*)/(?:locations|regions)/[a-zA-Z0-9-]*")
176+
switch {
177+
case re.MatchString(selfLink):
178+
if res := re.FindStringSubmatch(selfLink); len(res) == 2 && res[1] != "" {
179+
return res[1]
180+
}
181+
}
182+
return selfLink
183+
}

mmv1/third_party/terraform/tpgresource/self_link_helpers_test.go

+12
Original file line numberDiff line numberDiff line change
@@ -122,3 +122,15 @@ func TestGetRegionFromRegionalSelfLink(t *testing.T) {
122122
}
123123
}
124124
}
125+
126+
func TestGetProjectFromRegionalSelfLink(t *testing.T) {
127+
cases := map[string]string{
128+
"projects/foo/locations/europe-north1/datasets/bar/operations/foobar": "foo",
129+
"projects/REDACTED/regions/europe-north1/subnetworks/tf-test-net-xbwhsmlfm8": "REDACTED",
130+
}
131+
for input, expected := range cases {
132+
if result := GetProjectFromRegionalSelfLink(input); result != expected {
133+
t.Errorf("expected to get %q from %q, got %q", expected, input, result)
134+
}
135+
}
136+
}

mmv1/third_party/terraform/website/docs/r/compute_instance.html.markdown

+1-1
Original file line numberDiff line numberDiff line change
@@ -372,7 +372,7 @@ is desired, you will need to modify your state file manually using
372372

373373

374374
* `subnetwork_project` - (Optional) The project in which the subnetwork belongs.
375-
If the `subnetwork` is a self_link, this field is ignored in favor of the project
375+
If the `subnetwork` is a self_link, this field is set to the project
376376
defined in the subnetwork self_link. If the `subnetwork` is a name and this
377377
field is not provided, the provider project is used.
378378

0 commit comments

Comments
 (0)