github.com/danp/terraform@v0.9.5-0.20170426144147-39d740081351/builtin/providers/oneandone/resource_oneandone_firewall_policy.go (about)

     1  package oneandone
     2  
     3  import (
     4  	"github.com/1and1/oneandone-cloudserver-sdk-go"
     5  	"github.com/hashicorp/terraform/helper/schema"
     6  	"github.com/hashicorp/terraform/helper/validation"
     7  	"strings"
     8  )
     9  
    10  func resourceOneandOneFirewallPolicy() *schema.Resource {
    11  	return &schema.Resource{
    12  
    13  		Create: resourceOneandOneFirewallCreate,
    14  		Read:   resourceOneandOneFirewallRead,
    15  		Update: resourceOneandOneFirewallUpdate,
    16  		Delete: resourceOneandOneFirewallDelete,
    17  		Schema: map[string]*schema.Schema{
    18  			"name": {
    19  				Type:     schema.TypeString,
    20  				Required: true,
    21  			},
    22  			"description": {
    23  				Type:     schema.TypeString,
    24  				Optional: true,
    25  			},
    26  			"rules": {
    27  				Type: schema.TypeList,
    28  				Elem: &schema.Resource{
    29  					Schema: map[string]*schema.Schema{
    30  						"protocol": {
    31  							Type:     schema.TypeString,
    32  							Required: true,
    33  						},
    34  						"port_from": {
    35  							Type:         schema.TypeInt,
    36  							Optional:     true,
    37  							ValidateFunc: validation.IntBetween(1, 65535),
    38  						},
    39  						"port_to": {
    40  							Type:         schema.TypeInt,
    41  							Optional:     true,
    42  							ValidateFunc: validation.IntBetween(1, 65535),
    43  						},
    44  						"source_ip": {
    45  							Type:     schema.TypeString,
    46  							Optional: true,
    47  						},
    48  						"id": {
    49  							Type:     schema.TypeString,
    50  							Computed: true,
    51  						},
    52  					},
    53  				},
    54  				Required: true,
    55  			},
    56  		},
    57  	}
    58  }
    59  
    60  func resourceOneandOneFirewallCreate(d *schema.ResourceData, meta interface{}) error {
    61  	config := meta.(*Config)
    62  
    63  	req := oneandone.FirewallPolicyRequest{
    64  		Name: d.Get("name").(string),
    65  	}
    66  
    67  	if desc, ok := d.GetOk("description"); ok {
    68  		req.Description = desc.(string)
    69  	}
    70  
    71  	req.Rules = getRules(d)
    72  
    73  	fw_id, fw, err := config.API.CreateFirewallPolicy(&req)
    74  	if err != nil {
    75  		return err
    76  	}
    77  
    78  	err = config.API.WaitForState(fw, "ACTIVE", 10, config.Retries)
    79  	if err != nil {
    80  		return err
    81  	}
    82  
    83  	d.SetId(fw_id)
    84  
    85  	if err != nil {
    86  		return err
    87  	}
    88  
    89  	return resourceOneandOneFirewallRead(d, meta)
    90  }
    91  
    92  func resourceOneandOneFirewallUpdate(d *schema.ResourceData, meta interface{}) error {
    93  	config := meta.(*Config)
    94  	if d.HasChange("name") || d.HasChange("description") {
    95  		fw, err := config.API.UpdateFirewallPolicy(d.Id(), d.Get("name").(string), d.Get("description").(string))
    96  		if err != nil {
    97  			return err
    98  		}
    99  		err = config.API.WaitForState(fw, "ACTIVE", 10, config.Retries)
   100  		if err != nil {
   101  			return err
   102  		}
   103  	}
   104  
   105  	if d.HasChange("rules") {
   106  		oldR, newR := d.GetChange("rules")
   107  		oldValues := oldR.([]interface{})
   108  		newValues := newR.([]interface{})
   109  		if len(oldValues) > len(newValues) {
   110  			diff := difference(oldValues, newValues)
   111  			for _, old := range diff {
   112  				o := old.(map[string]interface{})
   113  				if o["id"] != nil {
   114  					old_id := o["id"].(string)
   115  					fw, err := config.API.DeleteFirewallPolicyRule(d.Id(), old_id)
   116  					if err != nil {
   117  						return err
   118  					}
   119  
   120  					err = config.API.WaitForState(fw, "ACTIVE", 10, config.Retries)
   121  					if err != nil {
   122  						return err
   123  					}
   124  				}
   125  			}
   126  		} else {
   127  			var rules []oneandone.FirewallPolicyRule
   128  
   129  			for _, raw := range newValues {
   130  				rl := raw.(map[string]interface{})
   131  
   132  				if rl["id"].(string) == "" {
   133  					rule := oneandone.FirewallPolicyRule{
   134  						Protocol: rl["protocol"].(string),
   135  					}
   136  
   137  					if rl["port_from"] != nil {
   138  						rule.PortFrom = oneandone.Int2Pointer(rl["port_from"].(int))
   139  					}
   140  					if rl["port_to"] != nil {
   141  						rule.PortTo = oneandone.Int2Pointer(rl["port_to"].(int))
   142  					}
   143  
   144  					if rl["source_ip"] != nil {
   145  						rule.SourceIp = rl["source_ip"].(string)
   146  					}
   147  
   148  					rules = append(rules, rule)
   149  				}
   150  			}
   151  
   152  			if len(rules) > 0 {
   153  				fw, err := config.API.AddFirewallPolicyRules(d.Id(), rules)
   154  				if err != nil {
   155  					return err
   156  				}
   157  
   158  				err = config.API.WaitForState(fw, "ACTIVE", 10, config.Retries)
   159  			}
   160  		}
   161  	}
   162  
   163  	return resourceOneandOneFirewallRead(d, meta)
   164  }
   165  
   166  func resourceOneandOneFirewallRead(d *schema.ResourceData, meta interface{}) error {
   167  	config := meta.(*Config)
   168  
   169  	fw, err := config.API.GetFirewallPolicy(d.Id())
   170  	if err != nil {
   171  		if strings.Contains(err.Error(), "404") {
   172  			d.SetId("")
   173  			return nil
   174  		}
   175  		return err
   176  	}
   177  
   178  	d.Set("rules", readRules(d, fw.Rules))
   179  	d.Set("description", fw.Description)
   180  
   181  	return nil
   182  }
   183  
   184  func resourceOneandOneFirewallDelete(d *schema.ResourceData, meta interface{}) error {
   185  	config := meta.(*Config)
   186  
   187  	fp, err := config.API.DeleteFirewallPolicy(d.Id())
   188  	if err != nil {
   189  		return err
   190  	}
   191  
   192  	err = config.API.WaitUntilDeleted(fp)
   193  	if err != nil {
   194  		return err
   195  	}
   196  
   197  	return nil
   198  }
   199  
   200  func readRules(d *schema.ResourceData, rules []oneandone.FirewallPolicyRule) interface{} {
   201  	rawRules := d.Get("rules").([]interface{})
   202  	counter := 0
   203  	for _, rR := range rawRules {
   204  		if len(rules) > counter {
   205  			rawMap := rR.(map[string]interface{})
   206  			rawMap["id"] = rules[counter].Id
   207  			if rules[counter].SourceIp != "0.0.0.0" {
   208  				rawMap["source_ip"] = rules[counter].SourceIp
   209  			}
   210  		}
   211  		counter++
   212  	}
   213  
   214  	return rawRules
   215  }
   216  
   217  func getRules(d *schema.ResourceData) []oneandone.FirewallPolicyRule {
   218  	var rules []oneandone.FirewallPolicyRule
   219  
   220  	if raw, ok := d.GetOk("rules"); ok {
   221  		rawRules := raw.([]interface{})
   222  
   223  		for _, raw := range rawRules {
   224  			rl := raw.(map[string]interface{})
   225  			rule := oneandone.FirewallPolicyRule{
   226  				Protocol: rl["protocol"].(string),
   227  			}
   228  
   229  			if rl["port_from"] != nil {
   230  				rule.PortFrom = oneandone.Int2Pointer(rl["port_from"].(int))
   231  			}
   232  			if rl["port_to"] != nil {
   233  				rule.PortTo = oneandone.Int2Pointer(rl["port_to"].(int))
   234  			}
   235  
   236  			if rl["source_ip"] != nil {
   237  				rule.SourceIp = rl["source_ip"].(string)
   238  			}
   239  
   240  			rules = append(rules, rule)
   241  		}
   242  	}
   243  	return rules
   244  }
   245  
   246  func difference(oldV, newV []interface{}) (toreturn []interface{}) {
   247  	var (
   248  		lenMin  int
   249  		longest []interface{}
   250  	)
   251  	// Determine the shortest length and the longest slice
   252  	if len(oldV) < len(newV) {
   253  		lenMin = len(oldV)
   254  		longest = newV
   255  	} else {
   256  		lenMin = len(newV)
   257  		longest = oldV
   258  	}
   259  	// compare common indeces
   260  	for i := 0; i < lenMin; i++ {
   261  		if oldV[i] == nil || newV[i] == nil {
   262  			continue
   263  		}
   264  		if oldV[i].(map[string]interface{})["id"] != newV[i].(map[string]interface{})["id"] {
   265  			toreturn = append(toreturn, newV) //out += fmt.Sprintf("=>\t%s\t%s\n", oldV[i], newV[i])
   266  		}
   267  	}
   268  	// add indeces not in common
   269  	for _, v := range longest[lenMin:] {
   270  		//out += fmt.Sprintf("=>\t%s\n", v)
   271  		toreturn = append(toreturn, v)
   272  	}
   273  	return toreturn
   274  }