Skip to content

Commit 5773b00

Browse files
Add rules field to google_compute_router_nat (#6643) (#12815)
Signed-off-by: Modular Magician <[email protected]> Signed-off-by: Modular Magician <[email protected]>
1 parent caa3f7c commit 5773b00

File tree

4 files changed

+891
-0
lines changed

4 files changed

+891
-0
lines changed

.changelog/6643.txt

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
```release-note:enhancement
2+
compute: added general field `rules` to `google_compute_router_nat`
3+
```

google/resource_compute_router_nat.go

+327
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ import (
2323
"time"
2424

2525
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
26+
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation"
2627
)
2728

2829
func resourceNameSetFromSelfLinkSet(v interface{}) *schema.Set {
@@ -111,6 +112,48 @@ func computeRouterNatIPsHash(v interface{}) int {
111112
return schema.HashString(GetResourceNameFromSelfLink(val))
112113
}
113114

115+
func computeRouterNatRulesHash(v interface{}) int {
116+
obj := v.(map[string]interface{})
117+
ruleNumber := obj["rule_number"].(int)
118+
119+
description := obj["description"]
120+
descriptionHash := 0
121+
if description != nil {
122+
descriptionHash = schema.HashString(description.(string))
123+
}
124+
125+
match := obj["match"].(string)
126+
127+
sourceNatActiveIpHash := 0
128+
sourceNatDrainIpHash := 0
129+
if obj["action"] != nil {
130+
actions := obj["action"].([]interface{})
131+
if len(actions) != 0 && actions[0] != nil {
132+
action := actions[0].(map[string]interface{})
133+
134+
sourceNatActiveIps := action["source_nat_active_ips"]
135+
if sourceNatActiveIps != nil {
136+
sourceNatActiveIpSet := sourceNatActiveIps.(*schema.Set)
137+
for _, sourceNatActiveIp := range sourceNatActiveIpSet.List() {
138+
sourceNatActiveIpStr := fmt.Sprintf("source_nat_active_ips-%d", computeRouterNatIPsHash(sourceNatActiveIp.(string)))
139+
sourceNatActiveIpHash += schema.HashString(sourceNatActiveIpStr)
140+
}
141+
}
142+
143+
soureNatDrainIps := action["source_nat_drain_ips"]
144+
if soureNatDrainIps != nil {
145+
soureNatDrainIpSet := soureNatDrainIps.(*schema.Set)
146+
for _, soureNatDrainIp := range soureNatDrainIpSet.List() {
147+
sourceNatDrainIpStr := fmt.Sprintf("source_nat_drain_ips-%d", computeRouterNatIPsHash(soureNatDrainIp.(string)))
148+
sourceNatDrainIpHash += schema.HashString(sourceNatDrainIpStr)
149+
}
150+
}
151+
}
152+
}
153+
154+
return ruleNumber + descriptionHash + schema.HashString(match) + sourceNatActiveIpHash + sourceNatDrainIpHash
155+
}
156+
114157
func resourceComputeRouterNat() *schema.Resource {
115158
return &schema.Resource{
116159
Create: resourceComputeRouterNatCreate,
@@ -256,6 +299,13 @@ is set to MANUAL_ONLY.`,
256299
DiffSuppressFunc: compareSelfLinkOrResourceName,
257300
Description: `Region where the router and NAT reside.`,
258301
},
302+
"rules": {
303+
Type: schema.TypeSet,
304+
Optional: true,
305+
Description: `A list of rules associated with this NAT.`,
306+
Elem: computeRouterNatRulesSchema(),
307+
Set: computeRouterNatRulesHash,
308+
},
259309
"subnetwork": {
260310
Type: schema.TypeSet,
261311
Optional: true,
@@ -333,6 +383,77 @@ sourceIpRangesToNat`,
333383
}
334384
}
335385

386+
func computeRouterNatRulesSchema() *schema.Resource {
387+
return &schema.Resource{
388+
Schema: map[string]*schema.Schema{
389+
"match": {
390+
Type: schema.TypeString,
391+
Required: true,
392+
Description: `CEL expression that specifies the match condition that egress traffic from a VM is evaluated against.
393+
If it evaluates to true, the corresponding action is enforced.
394+
395+
The following examples are valid match expressions for public NAT:
396+
397+
"inIpRange(destination.ip, '1.1.0.0/16') || inIpRange(destination.ip, '2.2.0.0/16')"
398+
399+
"destination.ip == '1.1.0.1' || destination.ip == '8.8.8.8'"
400+
401+
The following example is a valid match expression for private NAT:
402+
403+
"nexthop.hub == 'https://networkconnectivity.googleapis.com/v1alpha1/projects/my-project/global/hub/hub-1'"`,
404+
},
405+
"rule_number": {
406+
Type: schema.TypeInt,
407+
Required: true,
408+
ValidateFunc: validation.IntBetween(0, 65000),
409+
Description: `An integer uniquely identifying a rule in the list.
410+
The rule number must be a positive value between 0 and 65000, and must be unique among rules within a NAT.`,
411+
},
412+
"action": {
413+
Type: schema.TypeList,
414+
Computed: true,
415+
Optional: true,
416+
Description: `The action to be enforced for traffic that matches this rule.`,
417+
MaxItems: 1,
418+
Elem: &schema.Resource{
419+
Schema: map[string]*schema.Schema{
420+
"source_nat_active_ips": {
421+
Type: schema.TypeSet,
422+
Optional: true,
423+
Description: `A list of URLs of the IP resources used for this NAT rule.
424+
These IP addresses must be valid static external IP addresses assigned to the project.
425+
This field is used for public NAT.`,
426+
Elem: &schema.Schema{
427+
Type: schema.TypeString,
428+
DiffSuppressFunc: compareSelfLinkOrResourceName,
429+
},
430+
Set: computeRouterNatIPsHash,
431+
},
432+
"source_nat_drain_ips": {
433+
Type: schema.TypeSet,
434+
Optional: true,
435+
Description: `A list of URLs of the IP resources to be drained.
436+
These IPs must be valid static external IPs that have been assigned to the NAT.
437+
These IPs should be used for updating/patching a NAT rule only.
438+
This field is used for public NAT.`,
439+
Elem: &schema.Schema{
440+
Type: schema.TypeString,
441+
DiffSuppressFunc: compareSelfLinkOrResourceName,
442+
},
443+
Set: computeRouterNatIPsHash,
444+
},
445+
},
446+
},
447+
},
448+
"description": {
449+
Type: schema.TypeString,
450+
Optional: true,
451+
Description: `An optional description of this rule.`,
452+
},
453+
},
454+
}
455+
}
456+
336457
func resourceComputeRouterNatCreate(d *schema.ResourceData, meta interface{}) error {
337458
config := meta.(*Config)
338459
userAgent, err := generateUserAgentString(d, config.userAgent)
@@ -425,6 +546,12 @@ func resourceComputeRouterNatCreate(d *schema.ResourceData, meta interface{}) er
425546
} else if v, ok := d.GetOkExists("log_config"); ok || !reflect.DeepEqual(v, logConfigProp) {
426547
obj["logConfig"] = logConfigProp
427548
}
549+
rulesProp, err := expandNestedComputeRouterNatRules(d.Get("rules"), d, config)
550+
if err != nil {
551+
return err
552+
} else if v, ok := d.GetOkExists("rules"); ok || !reflect.DeepEqual(v, rulesProp) {
553+
obj["rules"] = rulesProp
554+
}
428555
enableEndpointIndependentMappingProp, err := expandNestedComputeRouterNatEnableEndpointIndependentMapping(d.Get("enable_endpoint_independent_mapping"), d, config)
429556
if err != nil {
430557
return err
@@ -578,6 +705,9 @@ func resourceComputeRouterNatRead(d *schema.ResourceData, meta interface{}) erro
578705
if err := d.Set("log_config", flattenNestedComputeRouterNatLogConfig(res["logConfig"], d, config)); err != nil {
579706
return fmt.Errorf("Error reading RouterNat: %s", err)
580707
}
708+
if err := d.Set("rules", flattenNestedComputeRouterNatRules(res["rules"], d, config)); err != nil {
709+
return fmt.Errorf("Error reading RouterNat: %s", err)
710+
}
581711
if err := d.Set("enable_endpoint_independent_mapping", flattenNestedComputeRouterNatEnableEndpointIndependentMapping(res["enableEndpointIndependentMapping"], d, config)); err != nil {
582712
return fmt.Errorf("Error reading RouterNat: %s", err)
583713
}
@@ -679,6 +809,12 @@ func resourceComputeRouterNatUpdate(d *schema.ResourceData, meta interface{}) er
679809
} else if v, ok := d.GetOkExists("log_config"); ok || !reflect.DeepEqual(v, logConfigProp) {
680810
obj["logConfig"] = logConfigProp
681811
}
812+
rulesProp, err := expandNestedComputeRouterNatRules(d.Get("rules"), d, config)
813+
if err != nil {
814+
return err
815+
} else if v, ok := d.GetOkExists("rules"); ok || !reflect.DeepEqual(v, rulesProp) {
816+
obj["rules"] = rulesProp
817+
}
682818
enableEndpointIndependentMappingProp, err := expandNestedComputeRouterNatEnableEndpointIndependentMapping(d.Get("enable_endpoint_independent_mapping"), d, config)
683819
if err != nil {
684820
return err
@@ -991,6 +1127,81 @@ func flattenNestedComputeRouterNatLogConfigFilter(v interface{}, d *schema.Resou
9911127
return v
9921128
}
9931129

1130+
func flattenNestedComputeRouterNatRules(v interface{}, d *schema.ResourceData, config *Config) interface{} {
1131+
if v == nil {
1132+
return v
1133+
}
1134+
l := v.([]interface{})
1135+
transformed := schema.NewSet(computeRouterNatRulesHash, []interface{}{})
1136+
for _, raw := range l {
1137+
original := raw.(map[string]interface{})
1138+
if len(original) < 1 {
1139+
// Do not include empty json objects coming back from the api
1140+
continue
1141+
}
1142+
transformed.Add(map[string]interface{}{
1143+
"rule_number": flattenNestedComputeRouterNatRulesRuleNumber(original["ruleNumber"], d, config),
1144+
"description": flattenNestedComputeRouterNatRulesDescription(original["description"], d, config),
1145+
"match": flattenNestedComputeRouterNatRulesMatch(original["match"], d, config),
1146+
"action": flattenNestedComputeRouterNatRulesAction(original["action"], d, config),
1147+
})
1148+
}
1149+
return transformed
1150+
}
1151+
func flattenNestedComputeRouterNatRulesRuleNumber(v interface{}, d *schema.ResourceData, config *Config) interface{} {
1152+
// Handles the string fixed64 format
1153+
if strVal, ok := v.(string); ok {
1154+
if intVal, err := stringToFixed64(strVal); err == nil {
1155+
return intVal
1156+
}
1157+
}
1158+
1159+
// number values are represented as float64
1160+
if floatVal, ok := v.(float64); ok {
1161+
intVal := int(floatVal)
1162+
return intVal
1163+
}
1164+
1165+
return v // let terraform core handle it otherwise
1166+
}
1167+
1168+
func flattenNestedComputeRouterNatRulesDescription(v interface{}, d *schema.ResourceData, config *Config) interface{} {
1169+
return v
1170+
}
1171+
1172+
func flattenNestedComputeRouterNatRulesMatch(v interface{}, d *schema.ResourceData, config *Config) interface{} {
1173+
return v
1174+
}
1175+
1176+
func flattenNestedComputeRouterNatRulesAction(v interface{}, d *schema.ResourceData, config *Config) interface{} {
1177+
if v == nil {
1178+
return nil
1179+
}
1180+
original := v.(map[string]interface{})
1181+
if len(original) == 0 {
1182+
return nil
1183+
}
1184+
transformed := make(map[string]interface{})
1185+
transformed["source_nat_active_ips"] =
1186+
flattenNestedComputeRouterNatRulesActionSourceNatActiveIps(original["sourceNatActiveIps"], d, config)
1187+
transformed["source_nat_drain_ips"] =
1188+
flattenNestedComputeRouterNatRulesActionSourceNatDrainIps(original["sourceNatDrainIps"], d, config)
1189+
return []interface{}{transformed}
1190+
}
1191+
func flattenNestedComputeRouterNatRulesActionSourceNatActiveIps(v interface{}, d *schema.ResourceData, config *Config) interface{} {
1192+
if v == nil {
1193+
return v
1194+
}
1195+
return schema.NewSet(computeRouterNatIPsHash, convertStringArrToInterface(convertAndMapStringArr(v.([]interface{}), ConvertSelfLinkToV1)))
1196+
}
1197+
1198+
func flattenNestedComputeRouterNatRulesActionSourceNatDrainIps(v interface{}, d *schema.ResourceData, config *Config) interface{} {
1199+
if v == nil {
1200+
return v
1201+
}
1202+
return schema.NewSet(computeRouterNatIPsHash, convertStringArrToInterface(convertAndMapStringArr(v.([]interface{}), ConvertSelfLinkToV1)))
1203+
}
1204+
9941205
func flattenNestedComputeRouterNatEnableEndpointIndependentMapping(v interface{}, d *schema.ResourceData, config *Config) interface{} {
9951206
return v
9961207
}
@@ -1158,6 +1369,122 @@ func expandNestedComputeRouterNatLogConfigFilter(v interface{}, d TerraformResou
11581369
return v, nil
11591370
}
11601371

1372+
func expandNestedComputeRouterNatRules(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
1373+
v = v.(*schema.Set).List()
1374+
l := v.([]interface{})
1375+
req := make([]interface{}, 0, len(l))
1376+
for _, raw := range l {
1377+
if raw == nil {
1378+
continue
1379+
}
1380+
original := raw.(map[string]interface{})
1381+
transformed := make(map[string]interface{})
1382+
1383+
transformedRuleNumber, err := expandNestedComputeRouterNatRulesRuleNumber(original["rule_number"], d, config)
1384+
if err != nil {
1385+
return nil, err
1386+
} else {
1387+
transformed["ruleNumber"] = transformedRuleNumber
1388+
}
1389+
1390+
transformedDescription, err := expandNestedComputeRouterNatRulesDescription(original["description"], d, config)
1391+
if err != nil {
1392+
return nil, err
1393+
} else if val := reflect.ValueOf(transformedDescription); val.IsValid() && !isEmptyValue(val) {
1394+
transformed["description"] = transformedDescription
1395+
}
1396+
1397+
transformedMatch, err := expandNestedComputeRouterNatRulesMatch(original["match"], d, config)
1398+
if err != nil {
1399+
return nil, err
1400+
} else if val := reflect.ValueOf(transformedMatch); val.IsValid() && !isEmptyValue(val) {
1401+
transformed["match"] = transformedMatch
1402+
}
1403+
1404+
transformedAction, err := expandNestedComputeRouterNatRulesAction(original["action"], d, config)
1405+
if err != nil {
1406+
return nil, err
1407+
} else if val := reflect.ValueOf(transformedAction); val.IsValid() && !isEmptyValue(val) {
1408+
transformed["action"] = transformedAction
1409+
}
1410+
1411+
req = append(req, transformed)
1412+
}
1413+
return req, nil
1414+
}
1415+
1416+
func expandNestedComputeRouterNatRulesRuleNumber(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
1417+
return v, nil
1418+
}
1419+
1420+
func expandNestedComputeRouterNatRulesDescription(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
1421+
return v, nil
1422+
}
1423+
1424+
func expandNestedComputeRouterNatRulesMatch(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
1425+
return v, nil
1426+
}
1427+
1428+
func expandNestedComputeRouterNatRulesAction(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
1429+
l := v.([]interface{})
1430+
if len(l) == 0 || l[0] == nil {
1431+
return nil, nil
1432+
}
1433+
raw := l[0]
1434+
original := raw.(map[string]interface{})
1435+
transformed := make(map[string]interface{})
1436+
1437+
transformedSourceNatActiveIps, err := expandNestedComputeRouterNatRulesActionSourceNatActiveIps(original["source_nat_active_ips"], d, config)
1438+
if err != nil {
1439+
return nil, err
1440+
} else if val := reflect.ValueOf(transformedSourceNatActiveIps); val.IsValid() && !isEmptyValue(val) {
1441+
transformed["sourceNatActiveIps"] = transformedSourceNatActiveIps
1442+
}
1443+
1444+
transformedSourceNatDrainIps, err := expandNestedComputeRouterNatRulesActionSourceNatDrainIps(original["source_nat_drain_ips"], d, config)
1445+
if err != nil {
1446+
return nil, err
1447+
} else if val := reflect.ValueOf(transformedSourceNatDrainIps); val.IsValid() && !isEmptyValue(val) {
1448+
transformed["sourceNatDrainIps"] = transformedSourceNatDrainIps
1449+
}
1450+
1451+
return transformed, nil
1452+
}
1453+
1454+
func expandNestedComputeRouterNatRulesActionSourceNatActiveIps(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
1455+
v = v.(*schema.Set).List()
1456+
l := v.([]interface{})
1457+
req := make([]interface{}, 0, len(l))
1458+
for _, raw := range l {
1459+
if raw == nil {
1460+
return nil, fmt.Errorf("Invalid value for source_nat_active_ips: nil")
1461+
}
1462+
f, err := parseRegionalFieldValue("addresses", raw.(string), "project", "region", "zone", d, config, true)
1463+
if err != nil {
1464+
return nil, fmt.Errorf("Invalid value for source_nat_active_ips: %s", err)
1465+
}
1466+
req = append(req, f.RelativeLink())
1467+
}
1468+
return req, nil
1469+
}
1470+
1471+
func expandNestedComputeRouterNatRulesActionSourceNatDrainIps(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
1472+
v = v.(*schema.Set).List()
1473+
l := v.([]interface{})
1474+
req := make([]interface{}, 0, len(l))
1475+
for _, raw := range l {
1476+
if raw == nil {
1477+
return nil, fmt.Errorf("Invalid value for source_nat_drain_ips: nil")
1478+
}
1479+
f, err := parseRegionalFieldValue("addresses", raw.(string), "project", "region", "zone", d, config, true)
1480+
if err != nil {
1481+
return nil, fmt.Errorf("Invalid value for source_nat_drain_ips: %s", err)
1482+
}
1483+
req = append(req, f.RelativeLink())
1484+
}
1485+
return req, nil
1486+
}
1487+
11611488
func expandNestedComputeRouterNatEnableEndpointIndependentMapping(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
11621489
return v, nil
11631490
}

0 commit comments

Comments
 (0)