github.com/vtorhonen/terraform@v0.9.0-beta2.0.20170307220345-5d894e4ffda7/builtin/providers/google/resource_compute_firewall.go (about) 1 package google 2 3 import ( 4 "bytes" 5 "fmt" 6 "log" 7 "sort" 8 "strings" 9 10 "github.com/hashicorp/terraform/helper/hashcode" 11 "github.com/hashicorp/terraform/helper/schema" 12 "google.golang.org/api/compute/v1" 13 "google.golang.org/api/googleapi" 14 ) 15 16 func resourceComputeFirewall() *schema.Resource { 17 return &schema.Resource{ 18 Create: resourceComputeFirewallCreate, 19 Read: resourceComputeFirewallRead, 20 Update: resourceComputeFirewallUpdate, 21 Delete: resourceComputeFirewallDelete, 22 Importer: &schema.ResourceImporter{ 23 State: schema.ImportStatePassthrough, 24 }, 25 SchemaVersion: 1, 26 MigrateState: resourceComputeFirewallMigrateState, 27 28 Schema: map[string]*schema.Schema{ 29 "name": { 30 Type: schema.TypeString, 31 Required: true, 32 ForceNew: true, 33 }, 34 35 "network": { 36 Type: schema.TypeString, 37 Required: true, 38 ForceNew: true, 39 }, 40 41 "allow": { 42 Type: schema.TypeSet, 43 Required: true, 44 Elem: &schema.Resource{ 45 Schema: map[string]*schema.Schema{ 46 "protocol": { 47 Type: schema.TypeString, 48 Required: true, 49 }, 50 51 "ports": { 52 Type: schema.TypeList, 53 Optional: true, 54 Elem: &schema.Schema{Type: schema.TypeString}, 55 }, 56 }, 57 }, 58 Set: resourceComputeFirewallAllowHash, 59 }, 60 61 "description": { 62 Type: schema.TypeString, 63 Optional: true, 64 }, 65 66 "project": { 67 Type: schema.TypeString, 68 Optional: true, 69 ForceNew: true, 70 Computed: true, 71 }, 72 73 "self_link": { 74 Type: schema.TypeString, 75 Computed: true, 76 }, 77 78 "source_ranges": { 79 Type: schema.TypeSet, 80 Optional: true, 81 Elem: &schema.Schema{Type: schema.TypeString}, 82 Set: schema.HashString, 83 }, 84 85 "source_tags": { 86 Type: schema.TypeSet, 87 Optional: true, 88 Elem: &schema.Schema{Type: schema.TypeString}, 89 Set: schema.HashString, 90 }, 91 92 "target_tags": { 93 Type: schema.TypeSet, 94 Optional: true, 95 Elem: &schema.Schema{Type: schema.TypeString}, 96 Set: schema.HashString, 97 }, 98 }, 99 } 100 } 101 102 func resourceComputeFirewallAllowHash(v interface{}) int { 103 var buf bytes.Buffer 104 m := v.(map[string]interface{}) 105 buf.WriteString(fmt.Sprintf("%s-", m["protocol"].(string))) 106 107 // We need to make sure to sort the strings below so that we always 108 // generate the same hash code no matter what is in the set. 109 if v, ok := m["ports"]; ok { 110 s := convertStringArr(v.([]interface{})) 111 sort.Strings(s) 112 113 for _, v := range s { 114 buf.WriteString(fmt.Sprintf("%s-", v)) 115 } 116 } 117 118 return hashcode.String(buf.String()) 119 } 120 121 func resourceComputeFirewallCreate(d *schema.ResourceData, meta interface{}) error { 122 config := meta.(*Config) 123 124 project, err := getProject(d, config) 125 if err != nil { 126 return err 127 } 128 129 firewall, err := resourceFirewall(d, meta) 130 if err != nil { 131 return err 132 } 133 134 op, err := config.clientCompute.Firewalls.Insert( 135 project, firewall).Do() 136 if err != nil { 137 return fmt.Errorf("Error creating firewall: %s", err) 138 } 139 140 // It probably maybe worked, so store the ID now 141 d.SetId(firewall.Name) 142 143 err = computeOperationWaitGlobal(config, op, project, "Creating Firewall") 144 if err != nil { 145 return err 146 } 147 148 return resourceComputeFirewallRead(d, meta) 149 } 150 151 func flattenAllowed(allowed []*compute.FirewallAllowed) []map[string]interface{} { 152 result := make([]map[string]interface{}, 0, len(allowed)) 153 for _, allow := range allowed { 154 allowMap := make(map[string]interface{}) 155 allowMap["protocol"] = allow.IPProtocol 156 allowMap["ports"] = allow.Ports 157 158 result = append(result, allowMap) 159 } 160 return result 161 } 162 163 func resourceComputeFirewallRead(d *schema.ResourceData, meta interface{}) error { 164 config := meta.(*Config) 165 166 project, err := getProject(d, config) 167 if err != nil { 168 return err 169 } 170 171 firewall, err := config.clientCompute.Firewalls.Get( 172 project, d.Id()).Do() 173 if err != nil { 174 if gerr, ok := err.(*googleapi.Error); ok && gerr.Code == 404 { 175 // The resource doesn't exist anymore 176 log.Printf("[WARN] Removing Firewall %q because it's gone", d.Get("name").(string)) 177 d.SetId("") 178 179 return nil 180 } 181 182 return fmt.Errorf("Error reading firewall: %s", err) 183 } 184 185 networkUrl := strings.Split(firewall.Network, "/") 186 d.Set("self_link", firewall.SelfLink) 187 d.Set("name", firewall.Name) 188 d.Set("network", networkUrl[len(networkUrl)-1]) 189 d.Set("description", firewall.Description) 190 d.Set("project", project) 191 d.Set("source_ranges", firewall.SourceRanges) 192 d.Set("source_tags", firewall.SourceTags) 193 d.Set("target_tags", firewall.TargetTags) 194 d.Set("allow", flattenAllowed(firewall.Allowed)) 195 return nil 196 } 197 198 func resourceComputeFirewallUpdate(d *schema.ResourceData, meta interface{}) error { 199 config := meta.(*Config) 200 201 project, err := getProject(d, config) 202 if err != nil { 203 return err 204 } 205 206 d.Partial(true) 207 208 firewall, err := resourceFirewall(d, meta) 209 if err != nil { 210 return err 211 } 212 213 op, err := config.clientCompute.Firewalls.Update( 214 project, d.Id(), firewall).Do() 215 if err != nil { 216 return fmt.Errorf("Error updating firewall: %s", err) 217 } 218 219 err = computeOperationWaitGlobal(config, op, project, "Updating Firewall") 220 if err != nil { 221 return err 222 } 223 224 d.Partial(false) 225 226 return resourceComputeFirewallRead(d, meta) 227 } 228 229 func resourceComputeFirewallDelete(d *schema.ResourceData, meta interface{}) error { 230 config := meta.(*Config) 231 232 project, err := getProject(d, config) 233 if err != nil { 234 return err 235 } 236 237 // Delete the firewall 238 op, err := config.clientCompute.Firewalls.Delete( 239 project, d.Id()).Do() 240 if err != nil { 241 return fmt.Errorf("Error deleting firewall: %s", err) 242 } 243 244 err = computeOperationWaitGlobal(config, op, project, "Deleting Firewall") 245 if err != nil { 246 return err 247 } 248 249 d.SetId("") 250 return nil 251 } 252 253 func resourceFirewall( 254 d *schema.ResourceData, 255 meta interface{}) (*compute.Firewall, error) { 256 config := meta.(*Config) 257 258 project, _ := getProject(d, config) 259 260 // Look up the network to attach the firewall to 261 network, err := config.clientCompute.Networks.Get( 262 project, d.Get("network").(string)).Do() 263 if err != nil { 264 return nil, fmt.Errorf("Error reading network: %s", err) 265 } 266 267 // Build up the list of allowed entries 268 var allowed []*compute.FirewallAllowed 269 if v := d.Get("allow").(*schema.Set); v.Len() > 0 { 270 allowed = make([]*compute.FirewallAllowed, 0, v.Len()) 271 for _, v := range v.List() { 272 m := v.(map[string]interface{}) 273 274 var ports []string 275 if v := convertStringArr(m["ports"].([]interface{})); len(v) > 0 { 276 ports = make([]string, len(v)) 277 for i, v := range v { 278 ports[i] = v 279 } 280 } 281 282 allowed = append(allowed, &compute.FirewallAllowed{ 283 IPProtocol: m["protocol"].(string), 284 Ports: ports, 285 }) 286 } 287 } 288 289 // Build up the list of sources 290 var sourceRanges, sourceTags []string 291 if v := d.Get("source_ranges").(*schema.Set); v.Len() > 0 { 292 sourceRanges = make([]string, v.Len()) 293 for i, v := range v.List() { 294 sourceRanges[i] = v.(string) 295 } 296 } 297 if v := d.Get("source_tags").(*schema.Set); v.Len() > 0 { 298 sourceTags = make([]string, v.Len()) 299 for i, v := range v.List() { 300 sourceTags[i] = v.(string) 301 } 302 } 303 304 // Build up the list of targets 305 var targetTags []string 306 if v := d.Get("target_tags").(*schema.Set); v.Len() > 0 { 307 targetTags = make([]string, v.Len()) 308 for i, v := range v.List() { 309 targetTags[i] = v.(string) 310 } 311 } 312 313 // Build the firewall parameter 314 return &compute.Firewall{ 315 Name: d.Get("name").(string), 316 Description: d.Get("description").(string), 317 Network: network.SelfLink, 318 Allowed: allowed, 319 SourceRanges: sourceRanges, 320 SourceTags: sourceTags, 321 TargetTags: targetTags, 322 }, nil 323 }