github.com/armen/terraform@v0.5.2-0.20150529052519-caa8117a08f1/builtin/providers/google/resource_compute_firewall.go (about) 1 package google 2 3 import ( 4 "bytes" 5 "fmt" 6 "sort" 7 "time" 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 // Wait for the operation to complete 139 w := &OperationWaiter{ 140 Service: config.clientCompute, 141 Op: op, 142 Project: config.Project, 143 Type: OperationWaitGlobal, 144 } 145 state := w.Conf() 146 state.Timeout = 2 * time.Minute 147 state.MinTimeout = 1 * time.Second 148 opRaw, err := state.WaitForState() 149 if err != nil { 150 return fmt.Errorf("Error waiting for firewall to create: %s", err) 151 } 152 op = opRaw.(*compute.Operation) 153 if op.Error != nil { 154 // The resource didn't actually create 155 d.SetId("") 156 157 // Return the error 158 return OperationError(*op.Error) 159 } 160 161 return resourceComputeFirewallRead(d, meta) 162 } 163 164 func resourceComputeFirewallRead(d *schema.ResourceData, meta interface{}) error { 165 config := meta.(*Config) 166 167 firewall, err := config.clientCompute.Firewalls.Get( 168 config.Project, d.Id()).Do() 169 if err != nil { 170 if gerr, ok := err.(*googleapi.Error); ok && gerr.Code == 404 { 171 // The resource doesn't exist anymore 172 d.SetId("") 173 174 return nil 175 } 176 177 return fmt.Errorf("Error reading firewall: %s", err) 178 } 179 180 d.Set("self_link", firewall.SelfLink) 181 182 return nil 183 } 184 185 func resourceComputeFirewallUpdate(d *schema.ResourceData, meta interface{}) error { 186 config := meta.(*Config) 187 188 d.Partial(true) 189 190 firewall, err := resourceFirewall(d, meta) 191 if err != nil { 192 return err 193 } 194 195 op, err := config.clientCompute.Firewalls.Update( 196 config.Project, d.Id(), firewall).Do() 197 if err != nil { 198 return fmt.Errorf("Error updating firewall: %s", err) 199 } 200 201 // Wait for the operation to complete 202 w := &OperationWaiter{ 203 Service: config.clientCompute, 204 Op: op, 205 Project: config.Project, 206 Type: OperationWaitGlobal, 207 } 208 state := w.Conf() 209 state.Timeout = 2 * time.Minute 210 state.MinTimeout = 1 * time.Second 211 opRaw, err := state.WaitForState() 212 if err != nil { 213 return fmt.Errorf("Error waiting for firewall to update: %s", err) 214 } 215 op = opRaw.(*compute.Operation) 216 if op.Error != nil { 217 // Return the error 218 return OperationError(*op.Error) 219 } 220 221 d.Partial(false) 222 223 return resourceComputeFirewallRead(d, meta) 224 } 225 226 func resourceComputeFirewallDelete(d *schema.ResourceData, meta interface{}) error { 227 config := meta.(*Config) 228 229 // Delete the firewall 230 op, err := config.clientCompute.Firewalls.Delete( 231 config.Project, d.Id()).Do() 232 if err != nil { 233 return fmt.Errorf("Error deleting firewall: %s", err) 234 } 235 236 // Wait for the operation to complete 237 w := &OperationWaiter{ 238 Service: config.clientCompute, 239 Op: op, 240 Project: config.Project, 241 Type: OperationWaitGlobal, 242 } 243 state := w.Conf() 244 state.Timeout = 2 * time.Minute 245 state.MinTimeout = 1 * time.Second 246 opRaw, err := state.WaitForState() 247 if err != nil { 248 return fmt.Errorf("Error waiting for firewall to delete: %s", err) 249 } 250 op = opRaw.(*compute.Operation) 251 if op.Error != nil { 252 // Return the error 253 return OperationError(*op.Error) 254 } 255 256 d.SetId("") 257 return nil 258 } 259 260 func resourceFirewall( 261 d *schema.ResourceData, 262 meta interface{}) (*compute.Firewall, error) { 263 config := meta.(*Config) 264 265 // Look up the network to attach the firewall to 266 network, err := config.clientCompute.Networks.Get( 267 config.Project, d.Get("network").(string)).Do() 268 if err != nil { 269 return nil, fmt.Errorf("Error reading network: %s", err) 270 } 271 272 // Build up the list of allowed entries 273 var allowed []*compute.FirewallAllowed 274 if v := d.Get("allow").(*schema.Set); v.Len() > 0 { 275 allowed = make([]*compute.FirewallAllowed, 0, v.Len()) 276 for _, v := range v.List() { 277 m := v.(map[string]interface{}) 278 279 var ports []string 280 if v := m["ports"].(*schema.Set); v.Len() > 0 { 281 ports = make([]string, v.Len()) 282 for i, v := range v.List() { 283 ports[i] = v.(string) 284 } 285 } 286 287 allowed = append(allowed, &compute.FirewallAllowed{ 288 IPProtocol: m["protocol"].(string), 289 Ports: ports, 290 }) 291 } 292 } 293 294 // Build up the list of sources 295 var sourceRanges, sourceTags []string 296 if v := d.Get("source_ranges").(*schema.Set); v.Len() > 0 { 297 sourceRanges = make([]string, v.Len()) 298 for i, v := range v.List() { 299 sourceRanges[i] = v.(string) 300 } 301 } 302 if v := d.Get("source_tags").(*schema.Set); v.Len() > 0 { 303 sourceTags = make([]string, v.Len()) 304 for i, v := range v.List() { 305 sourceTags[i] = v.(string) 306 } 307 } 308 309 // Build up the list of targets 310 var targetTags []string 311 if v := d.Get("target_tags").(*schema.Set); v.Len() > 0 { 312 targetTags = make([]string, v.Len()) 313 for i, v := range v.List() { 314 targetTags[i] = v.(string) 315 } 316 } 317 318 // Build the firewall parameter 319 return &compute.Firewall{ 320 Name: d.Get("name").(string), 321 Description: d.Get("description").(string), 322 Network: network.SelfLink, 323 Allowed: allowed, 324 SourceRanges: sourceRanges, 325 SourceTags: sourceTags, 326 TargetTags: targetTags, 327 }, nil 328 }