<commit_before>package softlayer

import (
	"fmt"
	"strconv"

	"github.com/hashicorp/terraform/helper/schema"
	"github.com/softlayer/softlayer-go/datatypes"
	"github.com/softlayer/softlayer-go/services"
	"github.com/softlayer/softlayer-go/session"
	"github.com/softlayer/softlayer-go/sl"
	"log"
	"time"
)

const (
	aclMask = "name,firewallInterfaces[name,firewallContextAccessControlLists]"
)

func resourceSoftLayerFwHardwareDedicatedRules() *schema.Resource {
	return &schema.Resource{
		Create:   resourceSoftLayerFwHardwareDedicatedRulesCreate,
		Read:     resourceSoftLayerFwHardwareDedicatedRulesRead,
		Update:   resourceSoftLayerFwHardwareDedicatedRulesUpdate,
		Delete:   resourceSoftLayerFwHardwareDedicatedRulesDelete,
		Exists:   resourceSoftLayerFwHardwareDedicatedRulesExists,
		Importer: &schema.ResourceImporter{},

		Schema: map[string]*schema.Schema{
			"firewall_id": {
				Type:     schema.TypeInt,
				Required: true,
				ForceNew: true,
			},

			"rules": {
				Type:     schema.TypeList,
				Required: true,
				Elem: &schema.Resource{
					Schema: map[string]*schema.Schema{
						"action": {
							Type:     schema.TypeString,
							Required: true,
						},
						"src_ip_address": {
							Type:     schema.TypeString,
							Required: true,
						},
						"src_ip_cidr": {
							Type:     schema.TypeInt,
							Required: true,
						},
						"dst_ip_address": {
							Type:     schema.TypeString,
							Required: true,
						},
						"dst_ip_cidr": {
							Type:     schema.TypeInt,
							Required: true,
						},
						// ICMP, GRE, AH, and ESP don't require port ranges.
						"dst_port_range_start": {
							Type:     schema.TypeInt,
							Optional: true,
						},
						"dst_port_range_end": {
							Type:     schema.TypeInt,
							Optional: true,
						},
						"protocol": {
							Type:     schema.TypeString,
							Required: true,
						},
						"notes": {
							Type:     schema.TypeString,
							Optional: true,
						},
					},
				},
			},
		},
	}
}

func prepareRules(d *schema.ResourceData) []datatypes.Network_Firewall_Update_Request_Rule {
	ruleList := d.Get("rules").([]interface{})
	rules := make([]datatypes.Network_Firewall_Update_Request_Rule, 0)
	for i, ruleItem := range ruleList {
		ruleMap := ruleItem.(map[string]interface{})
		var rule datatypes.Network_Firewall_Update_Request_Rule
		rule.OrderValue = sl.Int(i + 1)
		rule.Action = sl.String(ruleMap["action"].(string))
		rule.SourceIpAddress = sl.String(ruleMap["src_ip_address"].(string))
		rule.SourceIpCidr = sl.Int(ruleMap["src_ip_cidr"].(int))
		rule.DestinationIpAddress = sl.String(ruleMap["dst_ip_address"].(string))
		rule.DestinationIpCidr = sl.Int(ruleMap["dst_ip_cidr"].(int))

		if ruleMap["dst_port_range_start"] != nil {
			rule.DestinationPortRangeStart = sl.Int(ruleMap["dst_port_range_start"].(int))
		}
		if ruleMap["dst_port_range_end"] != nil {
			rule.DestinationPortRangeEnd = sl.Int(ruleMap["dst_port_range_end"].(int))
		}

		rule.Protocol = sl.String(ruleMap["protocol"].(string))
		if len(ruleMap["notes"].(string)) > 0 {
			rule.Notes = sl.String(ruleMap["notes"].(string))
		}
		rules = append(rules, rule)
	}
	return rules
}

func getFirewallContextAccessControlListId(fwId int, sess *session.Session) (int, error) {
	service := services.GetNetworkVlanFirewallService(sess)
	vlan, err := service.Id(fwId).Mask(aclMask).GetNetworkVlans()

	if err != nil {
		return 0, err
	}

	for _, fwInterface := range vlan[0].FirewallInterfaces {
		if fwInterface.Name != nil &&
			*fwInterface.Name == "outside" &&
			len(fwInterface.FirewallContextAccessControlLists) > 0 &&
			fwInterface.FirewallContextAccessControlLists[0].Id != nil {
			return *fwInterface.FirewallContextAccessControlLists[0].Id, nil
		}
	}
	return 0, fmt.Errorf("No firewallContextAccessControlListId.")
}

func resourceSoftLayerFwHardwareDedicatedRulesCreate(d *schema.ResourceData, meta interface{}) error {
	sess := meta.(ProviderConfig).SoftLayerSession()
	fwId := d.Get("firewall_id").(int)
	rules := prepareRules(d)<commit_msg>IPv6 support for firewall rules<commit_after>package softlayer

import (
	"fmt"
	"net"
	"strconv"
	"strings"

	"github.com/hashicorp/terraform/helper/schema"
	"github.com/softlayer/softlayer-go/datatypes"
	"github.com/softlayer/softlayer-go/services"
	"github.com/softlayer/softlayer-go/session"
	"github.com/softlayer/softlayer-go/sl"
	"log"
	"time"
)

const (
	aclMask = "name,firewallInterfaces[name,firewallContextAccessControlLists]"
)

func resourceSoftLayerFwHardwareDedicatedRules() *schema.Resource {
	return &schema.Resource{
		Create:   resourceSoftLayerFwHardwareDedicatedRulesCreate,
		Read:     resourceSoftLayerFwHardwareDedicatedRulesRead,
		Update:   resourceSoftLayerFwHardwareDedicatedRulesUpdate,
		Delete:   resourceSoftLayerFwHardwareDedicatedRulesDelete,
		Exists:   resourceSoftLayerFwHardwareDedicatedRulesExists,
		Importer: &schema.ResourceImporter{},

		Schema: map[string]*schema.Schema{
			"firewall_id": {
				Type:     schema.TypeInt,
				Required: true,
				ForceNew: true,
			},

			"rules": {
				Type:     schema.TypeList,
				Required: true,
				Elem: &schema.Resource{
					Schema: map[string]*schema.Schema{
						"action": {
							Type:     schema.TypeString,
							Required: true,
						},
						"src_ip_address": {
							Type:     schema.TypeString,
							Required: true,
							DiffSuppressFunc: func(k, o, n string, d *schema.ResourceData) bool {
								newSrcIpAddress := net.ParseIP(n)
								return newSrcIpAddress != nil && (newSrcIpAddress.String() == net.ParseIP(o).String())
							},
						},
						"src_ip_cidr": {
							Type:     schema.TypeInt,
							Required: true,
						},
						"dst_ip_address": {
							Type:     schema.TypeString,
							Required: true,
							DiffSuppressFunc: func(k, o, n string, d *schema.ResourceData) bool {
								newDstIpAddress := net.ParseIP(n)
								return newDstIpAddress != nil && (newDstIpAddress.String() == net.ParseIP(o).String())
							},
						},
						"dst_ip_cidr": {
							Type:     schema.TypeInt,
							Required: true,
						},
						// ICMP, GRE, AH, and ESP don't require port ranges.
						"dst_port_range_start": {
							Type:     schema.TypeInt,
							Optional: true,
						},
						"dst_port_range_end": {
							Type:     schema.TypeInt,
							Optional: true,
						},
						"protocol": {
							Type:     schema.TypeString,
							Required: true,
						},
						"notes": {
							Type:     schema.TypeString,
							Optional: true,
						},
					},
				},
			},
		},
	}
}

func prepareRules(d *schema.ResourceData) []datatypes.Network_Firewall_Update_Request_Rule {
	ruleList := d.Get("rules").([]interface{})
	rules := make([]datatypes.Network_Firewall_Update_Request_Rule, 0)
	for i, ruleItem := range ruleList {
		ruleMap := ruleItem.(map[string]interface{})
		var rule datatypes.Network_Firewall_Update_Request_Rule
		rule.OrderValue = sl.Int(i + 1)
		rule.Action = sl.String(ruleMap["action"].(string))
		rule.SourceIpAddress = sl.String(ruleMap["src_ip_address"].(string))
		rule.SourceIpCidr = sl.Int(ruleMap["src_ip_cidr"].(int))
		rule.DestinationIpAddress = sl.String(ruleMap["dst_ip_address"].(string))
		rule.DestinationIpCidr = sl.Int(ruleMap["dst_ip_cidr"].(int))

		if ruleMap["dst_port_range_start"] != nil {
			rule.DestinationPortRangeStart = sl.Int(ruleMap["dst_port_range_start"].(int))
		}
		if ruleMap["dst_port_range_end"] != nil {
			rule.DestinationPortRangeEnd = sl.Int(ruleMap["dst_port_range_end"].(int))
		}

		rule.Protocol = sl.String(ruleMap["protocol"].(string))
		if len(ruleMap["notes"].(string)) > 0 {
			rule.Notes = sl.String(ruleMap["notes"].(string))
		}

		if strings.Contains(*rule.SourceIpAddress, ":") || strings.Contains(*rule.DestinationIpAddress, ":") {
			rule.Version = sl.Int(6)
		}
		rules = append(rules, rule)
	}
	return rules
}

func getFirewallContextAccessControlListId(fwId int, sess *session.Session) (int, error) {
	service := services.GetNetworkVlanFirewallService(sess)
	vlan, err := service.Id(fwId).Mask(aclMask).GetNetworkVlans()

	if err != nil {
		return 0, err
	}

	for _, fwInterface := range vlan[0].FirewallInterfaces {
		if fwInterface.Name != nil &&
			*fwInterface.Name == "outside" &&
			len(fwInterface.FirewallContextAccessControlLists) > 0 &&
			fwInterface.FirewallContextAccessControlLists[0].Id != nil {
			return *fwInterface.FirewallContextAccessControlLists[0].Id, nil
		}
	}
	return 0, fmt.Errorf("No firewallContextAccessControlListId.")
}

func resourceSoftLayerFwHardwareDedicatedRulesCreate(d *schema.ResourceData, meta interface{}) error {
	sess := meta.(ProviderConfig).SoftLayerSession()
	fwId := d.Get("firewall_id").(int)
	rules := prepareRules(d)
{'fraction_non_alphanumeric': 0.1343814551296764, 'fraction_numerical': 0.0022951572182694515, 'mean_word_length': 3.685483870967742, 'pattern_counts': {'":': 24, '<': 3, '<?xml version=': 0, '>': 7, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6538956', 'n_tokens_mistral': 3576, 'n_tokens_neox': 2933, 'n_words': 456}