Skip to content

Commit

Permalink
Add rules field to google_compute_router_nat (#6643) (#12815)
Browse files Browse the repository at this point in the history
Signed-off-by: Modular Magician <magic-modules@google.com>

Signed-off-by: Modular Magician <magic-modules@google.com>
  • Loading branch information
modular-magician committed Oct 17, 2022
1 parent caa3f7c commit 5773b00
Show file tree
Hide file tree
Showing 4 changed files with 891 additions and 0 deletions.
3 changes: 3 additions & 0 deletions .changelog/6643.txt
@@ -0,0 +1,3 @@
```release-note:enhancement
compute: added general field `rules` to `google_compute_router_nat`
```
327 changes: 327 additions & 0 deletions google/resource_compute_router_nat.go
Expand Up @@ -23,6 +23,7 @@ import (
"time"

"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/validation"
)

func resourceNameSetFromSelfLinkSet(v interface{}) *schema.Set {
Expand Down Expand Up @@ -111,6 +112,48 @@ func computeRouterNatIPsHash(v interface{}) int {
return schema.HashString(GetResourceNameFromSelfLink(val))
}

func computeRouterNatRulesHash(v interface{}) int {
obj := v.(map[string]interface{})
ruleNumber := obj["rule_number"].(int)

description := obj["description"]
descriptionHash := 0
if description != nil {
descriptionHash = schema.HashString(description.(string))
}

match := obj["match"].(string)

sourceNatActiveIpHash := 0
sourceNatDrainIpHash := 0
if obj["action"] != nil {
actions := obj["action"].([]interface{})
if len(actions) != 0 && actions[0] != nil {
action := actions[0].(map[string]interface{})

sourceNatActiveIps := action["source_nat_active_ips"]
if sourceNatActiveIps != nil {
sourceNatActiveIpSet := sourceNatActiveIps.(*schema.Set)
for _, sourceNatActiveIp := range sourceNatActiveIpSet.List() {
sourceNatActiveIpStr := fmt.Sprintf("source_nat_active_ips-%d", computeRouterNatIPsHash(sourceNatActiveIp.(string)))
sourceNatActiveIpHash += schema.HashString(sourceNatActiveIpStr)
}
}

soureNatDrainIps := action["source_nat_drain_ips"]
if soureNatDrainIps != nil {
soureNatDrainIpSet := soureNatDrainIps.(*schema.Set)
for _, soureNatDrainIp := range soureNatDrainIpSet.List() {
sourceNatDrainIpStr := fmt.Sprintf("source_nat_drain_ips-%d", computeRouterNatIPsHash(soureNatDrainIp.(string)))
sourceNatDrainIpHash += schema.HashString(sourceNatDrainIpStr)
}
}
}
}

return ruleNumber + descriptionHash + schema.HashString(match) + sourceNatActiveIpHash + sourceNatDrainIpHash
}

func resourceComputeRouterNat() *schema.Resource {
return &schema.Resource{
Create: resourceComputeRouterNatCreate,
Expand Down Expand Up @@ -256,6 +299,13 @@ is set to MANUAL_ONLY.`,
DiffSuppressFunc: compareSelfLinkOrResourceName,
Description: `Region where the router and NAT reside.`,
},
"rules": {
Type: schema.TypeSet,
Optional: true,
Description: `A list of rules associated with this NAT.`,
Elem: computeRouterNatRulesSchema(),
Set: computeRouterNatRulesHash,
},
"subnetwork": {
Type: schema.TypeSet,
Optional: true,
Expand Down Expand Up @@ -333,6 +383,77 @@ sourceIpRangesToNat`,
}
}

func computeRouterNatRulesSchema() *schema.Resource {
return &schema.Resource{
Schema: map[string]*schema.Schema{
"match": {
Type: schema.TypeString,
Required: true,
Description: `CEL expression that specifies the match condition that egress traffic from a VM is evaluated against.
If it evaluates to true, the corresponding action is enforced.
The following examples are valid match expressions for public NAT:
"inIpRange(destination.ip, '1.1.0.0/16') || inIpRange(destination.ip, '2.2.0.0/16')"
"destination.ip == '1.1.0.1' || destination.ip == '8.8.8.8'"
The following example is a valid match expression for private NAT:
"nexthop.hub == 'https://networkconnectivity.googleapis.com/v1alpha1/projects/my-project/global/hub/hub-1'"`,
},
"rule_number": {
Type: schema.TypeInt,
Required: true,
ValidateFunc: validation.IntBetween(0, 65000),
Description: `An integer uniquely identifying a rule in the list.
The rule number must be a positive value between 0 and 65000, and must be unique among rules within a NAT.`,
},
"action": {
Type: schema.TypeList,
Computed: true,
Optional: true,
Description: `The action to be enforced for traffic that matches this rule.`,
MaxItems: 1,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"source_nat_active_ips": {
Type: schema.TypeSet,
Optional: true,
Description: `A list of URLs of the IP resources used for this NAT rule.
These IP addresses must be valid static external IP addresses assigned to the project.
This field is used for public NAT.`,
Elem: &schema.Schema{
Type: schema.TypeString,
DiffSuppressFunc: compareSelfLinkOrResourceName,
},
Set: computeRouterNatIPsHash,
},
"source_nat_drain_ips": {
Type: schema.TypeSet,
Optional: true,
Description: `A list of URLs of the IP resources to be drained.
These IPs must be valid static external IPs that have been assigned to the NAT.
These IPs should be used for updating/patching a NAT rule only.
This field is used for public NAT.`,
Elem: &schema.Schema{
Type: schema.TypeString,
DiffSuppressFunc: compareSelfLinkOrResourceName,
},
Set: computeRouterNatIPsHash,
},
},
},
},
"description": {
Type: schema.TypeString,
Optional: true,
Description: `An optional description of this rule.`,
},
},
}
}

func resourceComputeRouterNatCreate(d *schema.ResourceData, meta interface{}) error {
config := meta.(*Config)
userAgent, err := generateUserAgentString(d, config.userAgent)
Expand Down Expand Up @@ -425,6 +546,12 @@ func resourceComputeRouterNatCreate(d *schema.ResourceData, meta interface{}) er
} else if v, ok := d.GetOkExists("log_config"); ok || !reflect.DeepEqual(v, logConfigProp) {
obj["logConfig"] = logConfigProp
}
rulesProp, err := expandNestedComputeRouterNatRules(d.Get("rules"), d, config)
if err != nil {
return err
} else if v, ok := d.GetOkExists("rules"); ok || !reflect.DeepEqual(v, rulesProp) {
obj["rules"] = rulesProp
}
enableEndpointIndependentMappingProp, err := expandNestedComputeRouterNatEnableEndpointIndependentMapping(d.Get("enable_endpoint_independent_mapping"), d, config)
if err != nil {
return err
Expand Down Expand Up @@ -578,6 +705,9 @@ func resourceComputeRouterNatRead(d *schema.ResourceData, meta interface{}) erro
if err := d.Set("log_config", flattenNestedComputeRouterNatLogConfig(res["logConfig"], d, config)); err != nil {
return fmt.Errorf("Error reading RouterNat: %s", err)
}
if err := d.Set("rules", flattenNestedComputeRouterNatRules(res["rules"], d, config)); err != nil {
return fmt.Errorf("Error reading RouterNat: %s", err)
}
if err := d.Set("enable_endpoint_independent_mapping", flattenNestedComputeRouterNatEnableEndpointIndependentMapping(res["enableEndpointIndependentMapping"], d, config)); err != nil {
return fmt.Errorf("Error reading RouterNat: %s", err)
}
Expand Down Expand Up @@ -679,6 +809,12 @@ func resourceComputeRouterNatUpdate(d *schema.ResourceData, meta interface{}) er
} else if v, ok := d.GetOkExists("log_config"); ok || !reflect.DeepEqual(v, logConfigProp) {
obj["logConfig"] = logConfigProp
}
rulesProp, err := expandNestedComputeRouterNatRules(d.Get("rules"), d, config)
if err != nil {
return err
} else if v, ok := d.GetOkExists("rules"); ok || !reflect.DeepEqual(v, rulesProp) {
obj["rules"] = rulesProp
}
enableEndpointIndependentMappingProp, err := expandNestedComputeRouterNatEnableEndpointIndependentMapping(d.Get("enable_endpoint_independent_mapping"), d, config)
if err != nil {
return err
Expand Down Expand Up @@ -991,6 +1127,81 @@ func flattenNestedComputeRouterNatLogConfigFilter(v interface{}, d *schema.Resou
return v
}

func flattenNestedComputeRouterNatRules(v interface{}, d *schema.ResourceData, config *Config) interface{} {
if v == nil {
return v
}
l := v.([]interface{})
transformed := schema.NewSet(computeRouterNatRulesHash, []interface{}{})
for _, raw := range l {
original := raw.(map[string]interface{})
if len(original) < 1 {
// Do not include empty json objects coming back from the api
continue
}
transformed.Add(map[string]interface{}{
"rule_number": flattenNestedComputeRouterNatRulesRuleNumber(original["ruleNumber"], d, config),
"description": flattenNestedComputeRouterNatRulesDescription(original["description"], d, config),
"match": flattenNestedComputeRouterNatRulesMatch(original["match"], d, config),
"action": flattenNestedComputeRouterNatRulesAction(original["action"], d, config),
})
}
return transformed
}
func flattenNestedComputeRouterNatRulesRuleNumber(v interface{}, d *schema.ResourceData, config *Config) interface{} {
// Handles the string fixed64 format
if strVal, ok := v.(string); ok {
if intVal, err := stringToFixed64(strVal); err == nil {
return intVal
}
}

// number values are represented as float64
if floatVal, ok := v.(float64); ok {
intVal := int(floatVal)
return intVal
}

return v // let terraform core handle it otherwise
}

func flattenNestedComputeRouterNatRulesDescription(v interface{}, d *schema.ResourceData, config *Config) interface{} {
return v
}

func flattenNestedComputeRouterNatRulesMatch(v interface{}, d *schema.ResourceData, config *Config) interface{} {
return v
}

func flattenNestedComputeRouterNatRulesAction(v interface{}, d *schema.ResourceData, config *Config) interface{} {
if v == nil {
return nil
}
original := v.(map[string]interface{})
if len(original) == 0 {
return nil
}
transformed := make(map[string]interface{})
transformed["source_nat_active_ips"] =
flattenNestedComputeRouterNatRulesActionSourceNatActiveIps(original["sourceNatActiveIps"], d, config)
transformed["source_nat_drain_ips"] =
flattenNestedComputeRouterNatRulesActionSourceNatDrainIps(original["sourceNatDrainIps"], d, config)
return []interface{}{transformed}
}
func flattenNestedComputeRouterNatRulesActionSourceNatActiveIps(v interface{}, d *schema.ResourceData, config *Config) interface{} {
if v == nil {
return v
}
return schema.NewSet(computeRouterNatIPsHash, convertStringArrToInterface(convertAndMapStringArr(v.([]interface{}), ConvertSelfLinkToV1)))
}

func flattenNestedComputeRouterNatRulesActionSourceNatDrainIps(v interface{}, d *schema.ResourceData, config *Config) interface{} {
if v == nil {
return v
}
return schema.NewSet(computeRouterNatIPsHash, convertStringArrToInterface(convertAndMapStringArr(v.([]interface{}), ConvertSelfLinkToV1)))
}

func flattenNestedComputeRouterNatEnableEndpointIndependentMapping(v interface{}, d *schema.ResourceData, config *Config) interface{} {
return v
}
Expand Down Expand Up @@ -1158,6 +1369,122 @@ func expandNestedComputeRouterNatLogConfigFilter(v interface{}, d TerraformResou
return v, nil
}

func expandNestedComputeRouterNatRules(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
v = v.(*schema.Set).List()
l := v.([]interface{})
req := make([]interface{}, 0, len(l))
for _, raw := range l {
if raw == nil {
continue
}
original := raw.(map[string]interface{})
transformed := make(map[string]interface{})

transformedRuleNumber, err := expandNestedComputeRouterNatRulesRuleNumber(original["rule_number"], d, config)
if err != nil {
return nil, err
} else {
transformed["ruleNumber"] = transformedRuleNumber
}

transformedDescription, err := expandNestedComputeRouterNatRulesDescription(original["description"], d, config)
if err != nil {
return nil, err
} else if val := reflect.ValueOf(transformedDescription); val.IsValid() && !isEmptyValue(val) {
transformed["description"] = transformedDescription
}

transformedMatch, err := expandNestedComputeRouterNatRulesMatch(original["match"], d, config)
if err != nil {
return nil, err
} else if val := reflect.ValueOf(transformedMatch); val.IsValid() && !isEmptyValue(val) {
transformed["match"] = transformedMatch
}

transformedAction, err := expandNestedComputeRouterNatRulesAction(original["action"], d, config)
if err != nil {
return nil, err
} else if val := reflect.ValueOf(transformedAction); val.IsValid() && !isEmptyValue(val) {
transformed["action"] = transformedAction
}

req = append(req, transformed)
}
return req, nil
}

func expandNestedComputeRouterNatRulesRuleNumber(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
return v, nil
}

func expandNestedComputeRouterNatRulesDescription(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
return v, nil
}

func expandNestedComputeRouterNatRulesMatch(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
return v, nil
}

func expandNestedComputeRouterNatRulesAction(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
l := v.([]interface{})
if len(l) == 0 || l[0] == nil {
return nil, nil
}
raw := l[0]
original := raw.(map[string]interface{})
transformed := make(map[string]interface{})

transformedSourceNatActiveIps, err := expandNestedComputeRouterNatRulesActionSourceNatActiveIps(original["source_nat_active_ips"], d, config)
if err != nil {
return nil, err
} else if val := reflect.ValueOf(transformedSourceNatActiveIps); val.IsValid() && !isEmptyValue(val) {
transformed["sourceNatActiveIps"] = transformedSourceNatActiveIps
}

transformedSourceNatDrainIps, err := expandNestedComputeRouterNatRulesActionSourceNatDrainIps(original["source_nat_drain_ips"], d, config)
if err != nil {
return nil, err
} else if val := reflect.ValueOf(transformedSourceNatDrainIps); val.IsValid() && !isEmptyValue(val) {
transformed["sourceNatDrainIps"] = transformedSourceNatDrainIps
}

return transformed, nil
}

func expandNestedComputeRouterNatRulesActionSourceNatActiveIps(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
v = v.(*schema.Set).List()
l := v.([]interface{})
req := make([]interface{}, 0, len(l))
for _, raw := range l {
if raw == nil {
return nil, fmt.Errorf("Invalid value for source_nat_active_ips: nil")
}
f, err := parseRegionalFieldValue("addresses", raw.(string), "project", "region", "zone", d, config, true)
if err != nil {
return nil, fmt.Errorf("Invalid value for source_nat_active_ips: %s", err)
}
req = append(req, f.RelativeLink())
}
return req, nil
}

func expandNestedComputeRouterNatRulesActionSourceNatDrainIps(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
v = v.(*schema.Set).List()
l := v.([]interface{})
req := make([]interface{}, 0, len(l))
for _, raw := range l {
if raw == nil {
return nil, fmt.Errorf("Invalid value for source_nat_drain_ips: nil")
}
f, err := parseRegionalFieldValue("addresses", raw.(string), "project", "region", "zone", d, config, true)
if err != nil {
return nil, fmt.Errorf("Invalid value for source_nat_drain_ips: %s", err)
}
req = append(req, f.RelativeLink())
}
return req, nil
}

func expandNestedComputeRouterNatEnableEndpointIndependentMapping(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
return v, nil
}
Expand Down

0 comments on commit 5773b00

Please sign in to comment.