Skip to content

Commit

Permalink
adding validation while setting empty active ranges (#9125)
Browse files Browse the repository at this point in the history
  • Loading branch information
felipegc authored Oct 9, 2023
1 parent 1bb8a70 commit c904e61
Show file tree
Hide file tree
Showing 3 changed files with 169 additions and 0 deletions.
2 changes: 2 additions & 0 deletions mmv1/products/compute/RouterNat.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,8 @@ examples:
spoke_name: 'my-spoke'
custom_code: !ruby/object:Provider::Terraform::CustomCode
constants: 'templates/terraform/constants/router_nat.go.erb'
pre_create: 'templates/terraform/constants/router_nat_validate_action_active_range.go.erb'
pre_update: 'templates/terraform/constants/router_nat_validate_action_active_range.go.erb'
custom_diff: [
'resourceComputeRouterNatDrainNatIpsCustomDiff',
]
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<% unless version == 'ga' -%>
// validates if the field action.source_nat_active_ranges is filled when the type is PRIVATE.
natType := d.Get("type").(string)
if natType == "PRIVATE" {
rules := d.Get("rules").(*schema.Set)
for _, rule := range rules.List() {
objRule := rule.(map[string]interface{})
actions := objRule["action"].([]interface{})

containAction := len(actions) != 0 && actions[0] != nil
containActiveRange := true

if containAction {
action := actions[0].(map[string]interface{})
sourceNatActiveRanges := action["source_nat_active_ranges"]
if sourceNatActiveRanges != nil {
sourceNatActiveRangesSet := sourceNatActiveRanges.(*schema.Set)
if len(sourceNatActiveRangesSet.List()) == 0 {
containActiveRange = false
}
}
}

if !containAction || !containActiveRange {
return fmt.Errorf("The rule for PRIVATE nat type must contain an action with source_nat_active_ranges set")
}
}
}
<% end -%>
Original file line number Diff line number Diff line change
Expand Up @@ -533,6 +533,86 @@ func TestAccComputeRouterNat_withPrivateNatAndRules(t *testing.T) {
},
})
}

func TestAccComputeRouterNat_withPrivateNatAndEmptyAction(t *testing.T) {
t.Parallel()

testId := acctest.RandString(t, 10)
routerName := fmt.Sprintf("tf-test-router-private-nat-%s", testId)
hubName := fmt.Sprintf("%s-hub", routerName)
pEnv := envvar.GetTestProjectFromEnv()
ruleDescription := acctest.RandString(t, 10)
match := fmt.Sprintf("nexthop.hub == '//networkconnectivity.googleapis.com/projects/%s/locations/global/hubs/%s'", pEnv, hubName)
activeRangesNetworkOne := "google_compute_subnetwork.subnet1.self_link"
drainRangesEmpty := ""

acctest.VcrTest(t, resource.TestCase{
PreCheck: func() { acctest.AccTestPreCheck(t) },
ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t),
CheckDestroy: testAccCheckComputeRouterNatDestroyProducer(t),
Steps: []resource.TestStep{
// (ERROR): Creation with empty action should fail
{
Config: testAccComputeRouterNatRulesBasic_privateNatWithRuleAndEmptyAction(routerName, hubName, 100, ruleDescription, match),
ExpectError: regexp.MustCompile("The rule for PRIVATE nat type must contain an action with source_nat_active_ranges set"),
},
// Create NAT with action and active ranges set
{
Config: testAccComputeRouterNatRulesBasic_privateNatWithRuleAndActiveDrainRange(routerName, hubName, 100, ruleDescription, match, activeRangesNetworkOne, drainRangesEmpty),
},
{
ResourceName: "google_compute_router_nat.foobar",
ImportState: true,
ImportStateVerify: true,
},
// (ERROR) - Updating the rule by removing the action should fail
{
Config: testAccComputeRouterNatRulesBasic_privateNatWithRuleAndEmptyAction(routerName, hubName, 100, ruleDescription, match),
ExpectError: regexp.MustCompile("The rule for PRIVATE nat type must contain an action with source_nat_active_ranges set"),
},
},
})
}

func TestAccComputeRouterNat_withPrivateNatAndEmptyActionActiveRanges(t *testing.T) {
t.Parallel()

testId := acctest.RandString(t, 10)
routerName := fmt.Sprintf("tf-test-router-private-nat-%s", testId)
hubName := fmt.Sprintf("%s-hub", routerName)
pEnv := envvar.GetTestProjectFromEnv()
ruleDescription := acctest.RandString(t, 10)
match := fmt.Sprintf("nexthop.hub == '//networkconnectivity.googleapis.com/projects/%s/locations/global/hubs/%s'", pEnv, hubName)
activeRangesNetworkOne := "google_compute_subnetwork.subnet1.self_link"
drainRangesEmpty := ""

acctest.VcrTest(t, resource.TestCase{
PreCheck: func() { acctest.AccTestPreCheck(t) },
ProtoV5ProviderFactories: acctest.ProtoV5ProviderFactories(t),
CheckDestroy: testAccCheckComputeRouterNatDestroyProducer(t),
Steps: []resource.TestStep{
// (ERROR): Creation with empty action active ranges should fail
{
Config: testAccComputeRouterNatRulesBasic_privateNatWithRuleAndEmptyActionActiveRanges(routerName, hubName, 100, ruleDescription, match),
ExpectError: regexp.MustCompile("The rule for PRIVATE nat type must contain an action with source_nat_active_ranges set"),
},
// Create NAT with action and active ranges set
{
Config: testAccComputeRouterNatRulesBasic_privateNatWithRuleAndActiveDrainRange(routerName, hubName, 100, ruleDescription, match, activeRangesNetworkOne, drainRangesEmpty),
},
{
ResourceName: "google_compute_router_nat.foobar",
ImportState: true,
ImportStateVerify: true,
},
// (ERROR) - Updating the rule by erasing the action active ranges should fail
{
Config: testAccComputeRouterNatRulesBasic_privateNatWithRuleAndEmptyActionActiveRanges(routerName, hubName, 100, ruleDescription, match),
ExpectError: regexp.MustCompile("The rule for PRIVATE nat type must contain an action with source_nat_active_ranges set"),
},
},
})
}
<% end -%>

func testAccCheckComputeRouterNatDestroyProducer(t *testing.T) func(s *terraform.State) error {
Expand Down Expand Up @@ -1655,4 +1735,62 @@ resource "google_compute_router_nat" "foobar" {
`, testAccComputeRouterNatBaseResourcesWithPrivateNatSubnetworks(routerName, hubName), routerName, ruleNumber, ruleDescription, match, activeRanges, drainRanges)
}

func testAccComputeRouterNatRulesBasic_privateNatWithRuleAndEmptyAction(routerName, hubName string, ruleNumber int, ruleDescription, match string) string {
return fmt.Sprintf(`
%s

resource "google_compute_router_nat" "foobar" {
name = "%s"
router = google_compute_router.foobar.name
region = google_compute_router.foobar.region
source_subnetwork_ip_ranges_to_nat = "LIST_OF_SUBNETWORKS"
type = "PRIVATE"
enable_dynamic_port_allocation = false
enable_endpoint_independent_mapping = false
min_ports_per_vm = 32
subnetwork {
name = google_compute_subnetwork.subnet1.id
source_ip_ranges_to_nat = ["ALL_IP_RANGES"]
}

rules {
rule_number = %d
description = "%s"
match = "%s"
# action is missing
}
}
`, testAccComputeRouterNatBaseResourcesWithPrivateNatSubnetworks(routerName, hubName), routerName, ruleNumber, ruleDescription, match)
}

func testAccComputeRouterNatRulesBasic_privateNatWithRuleAndEmptyActionActiveRanges(routerName, hubName string, ruleNumber int, ruleDescription, match string) string {
return fmt.Sprintf(`
%s

resource "google_compute_router_nat" "foobar" {
name = "%s"
router = google_compute_router.foobar.name
region = google_compute_router.foobar.region
source_subnetwork_ip_ranges_to_nat = "LIST_OF_SUBNETWORKS"
type = "PRIVATE"
enable_dynamic_port_allocation = false
enable_endpoint_independent_mapping = false
min_ports_per_vm = 32
subnetwork {
name = google_compute_subnetwork.subnet1.id
source_ip_ranges_to_nat = ["ALL_IP_RANGES"]
}

rules {
rule_number = %d
description = "%s"
match = "%s"
action {
source_nat_active_ranges = []
}
}
}
`, testAccComputeRouterNatBaseResourcesWithPrivateNatSubnetworks(routerName, hubName), routerName, ruleNumber, ruleDescription, match)
}

<% end -%>

0 comments on commit c904e61

Please sign in to comment.