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