Skip to content

Commit

Permalink
Add nat type to nat rule resource
Browse files Browse the repository at this point in the history
Before this change, only NAT64 and USER nat types were supported,
and the value was calculated based on action.
With this change, we need to keep in mind refresh of existing
nat rule resources, hence the new type will be calculated.

Signed-off-by: Anna Khmelnitsky <[email protected]>
  • Loading branch information
annakhm committed Dec 13, 2024
1 parent 35f6088 commit 11b6bfd
Show file tree
Hide file tree
Showing 3 changed files with 139 additions and 39 deletions.
83 changes: 62 additions & 21 deletions nsxt/resource_nsxt_policy_nat_rule.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,13 @@ var policyNATRulePolicyBasedVpnModeTypeValues = []string{
model.PolicyNatRule_POLICY_BASED_VPN_MODE_MATCH,
}

var policyNATRuleTypeValues = []string{
model.PolicyNat_NAT_TYPE_INTERNAL,
model.PolicyNat_NAT_TYPE_USER,
model.PolicyNat_NAT_TYPE_DEFAULT,
model.PolicyNat_NAT_TYPE_NAT64,
}

func resourceNsxtPolicyNATRule() *schema.Resource {
return &schema.Resource{
Create: resourceNsxtPolicyNATRuleCreate,
Expand Down Expand Up @@ -144,6 +151,14 @@ func resourceNsxtPolicyNATRule() *schema.Resource {
Computed: true,
ValidateFunc: validation.StringInSlice(policyNATRulePolicyBasedVpnModeTypeValues, false),
},
"type": {
Type: schema.TypeString,
Description: "NAT Type",
Optional: true,
ForceNew: true,
ValidateFunc: validation.StringInSlice(policyNATRuleTypeValues, false),
Computed: true,
},
},
}
}
Expand Down Expand Up @@ -180,7 +195,8 @@ func resourceNsxtPolicyNATRuleDelete(d *schema.ResourceData, m interface{}) erro
}

action := d.Get("action").(string)
natType := getNatTypeByAction(action)
natType := d.Get("type").(string)
natType = getNatTypeByAction(natType, action)
err := deleteNsxtPolicyNATRule(context, getPolicyConnector(m), gwID, isT0, natType, id)
if err != nil {
return handleDeleteError("NAT Rule", id, err)
Expand All @@ -204,8 +220,7 @@ func getNsxtPolicyNATRuleByID(sessionContext utl.SessionContext, connector clien
return client.Get(gwID, natType, ruleID)
}

func patchNsxtPolicyNATRule(sessionContext utl.SessionContext, connector client.Connector, gwID string, rule model.PolicyNatRule, isT0 bool) error {
natType := getNatTypeByAction(*rule.Action)
func patchNsxtPolicyNATRule(sessionContext utl.SessionContext, connector client.Connector, gwID string, rule model.PolicyNatRule, isT0 bool, natType string) error {
_, err := getTranslatedNetworks(rule)
if err != nil {
return err
Expand All @@ -231,12 +246,15 @@ func patchNsxtPolicyNATRule(sessionContext utl.SessionContext, connector client.
return client.Patch(gwID, natType, *rule.Id, rule)
}

func getNatTypeByAction(action string) string {
func getNatTypeByAction(natType string, action string) string {
if action == model.PolicyNatRule_ACTION_NAT64 {
return model.PolicyNat_NAT_TYPE_NAT64
}
if natType == "" {
return model.PolicyNat_NAT_TYPE_USER
}

return model.PolicyNat_NAT_TYPE_USER
return natType
}

func translatedNetworksNeeded(action string) bool {
Expand Down Expand Up @@ -284,8 +302,14 @@ func resourceNsxtPolicyNATRuleRead(d *schema.ResourceData, m interface{}) error
return handleMultitenancyTier0Error()
}

action := d.Get("action").(string)
natType := getNatTypeByAction(action)
natType := d.Get("type").(string)
if natType == "" {
// This can happen when provider was upgraded and we're refreshing an existing resource
// This is not an import case, so action should be set
action := d.Get("action").(string)
natType = getNatTypeByAction(natType, action)
d.Set("type", natType)
}
obj, err := getNsxtPolicyNATRuleByID(context, connector, gwID, isT0, natType, id)
if err != nil {
return handleReadError(d, "NAT Rule", id, err)
Expand Down Expand Up @@ -322,12 +346,30 @@ func resourceNsxtPolicyNATRuleRead(d *schema.ResourceData, m interface{}) error
return nil
}

func validateNatTypeAction(action string, natType string) error {
if action == model.PolicyNatRule_ACTION_NAT64 && (natType != "" && natType != model.PolicyNat_NAT_TYPE_NAT64) {
return fmt.Errorf("Rules with NAT64 action must have NAT64 nat type")
}

if natType == model.PolicyNat_NAT_TYPE_NAT64 && action != model.PolicyNatRule_ACTION_NAT64 {
return fmt.Errorf("Rules with type NAT64 action must have NAT64 action")
}
return nil
}

func resourceNsxtPolicyNATRuleCreate(d *schema.ResourceData, m interface{}) error {
connector := getPolicyConnector(m)

gwPolicyPath := d.Get("gateway_path").(string)
action := d.Get("action").(string)
natType := getNatTypeByAction(action)
natType := d.Get("type").(string)
if err := validateNatTypeAction(action, natType); err != nil {
return err
}
// nat type attribute was introduced as explicit attribute when existing deployments
// were calculating it based on action
// for backward compatibility, we allow the type to be overridden by NAT64 action
natType = getNatTypeByAction(natType, action)
isT0, gwID := parseGatewayPolicyPath(gwPolicyPath)
if gwID == "" {
return fmt.Errorf("gateway_path is not valid")
Expand Down Expand Up @@ -394,13 +436,15 @@ func resourceNsxtPolicyNATRuleCreate(d *schema.ResourceData, m interface{}) erro

log.Printf("[INFO] Creating NAT Rule with ID %s", id)

err := patchNsxtPolicyNATRule(getSessionContext(d, m), connector, gwID, ruleStruct, isT0)
err := patchNsxtPolicyNATRule(getSessionContext(d, m), connector, gwID, ruleStruct, isT0, natType)
if err != nil {
return handleCreateError("NAT Rule", id, err)
}

d.SetId(id)
d.Set("nsx_id", id)
// In case nat type was not specified or got overridden by action
d.Set("type", natType)

return resourceNsxtPolicyNATRuleRead(d, m)
}
Expand All @@ -426,6 +470,11 @@ func resourceNsxtPolicyNATRuleUpdate(d *schema.ResourceData, m interface{}) erro
displayName := d.Get("display_name").(string)
description := d.Get("description").(string)
action := d.Get("action").(string)
natType := d.Get("type").(string)
if err := validateNatTypeAction(action, natType); err != nil {
return err
}
natType = getNatTypeByAction(natType, action)
enabled := d.Get("enabled").(bool)
logging := d.Get("logging").(bool)
priority := int64(d.Get("rule_priority").(int))
Expand Down Expand Up @@ -467,7 +516,7 @@ func resourceNsxtPolicyNATRuleUpdate(d *schema.ResourceData, m interface{}) erro
}

log.Printf("[INFO] Updating NAT Rule with ID %s", id)
err := patchNsxtPolicyNATRule(context, connector, gwID, ruleStruct, isT0)
err := patchNsxtPolicyNATRule(context, connector, gwID, ruleStruct, isT0, natType)
if err != nil {
return handleUpdateError("NAT Rule", id, err)
}
Expand All @@ -492,24 +541,16 @@ func resourceNsxtPolicyNATRuleImport(d *schema.ResourceData, m interface{}) ([]*
if err != nil {
return nil, err
}
if natType == model.PolicyNat_NAT_TYPE_USER {
// Value will be overwritten by resourceNsxtPolicyNATRuleRead()
d.Set("action", model.PolicyNatRule_ACTION_DNAT)
} else {
d.Set("action", model.PolicyNatRule_ACTION_NAT64)
}
d.Set("type", natType)
return rd, nil
} else if !errors.Is(err, ErrNotAPolicyPath) {
return rd, err
}
if len(s) < 2 || len(s) > 3 {
return nil, fmt.Errorf("Please provide <gateway-id>/<nat-rule-id>/[nat-type] as an input")
}
if len(s) == 3 {
// take care of NAT64 nat-type via action
if s[2] == model.PolicyNat_NAT_TYPE_NAT64 {
d.Set("action", model.PolicyNatRule_ACTION_NAT64)
}
if len(s) < 3 {
d.Set("type", model.PolicyNat_NAT_TYPE_USER)
}

gwID := s[0]
Expand Down
Loading

0 comments on commit 11b6bfd

Please sign in to comment.