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 }