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