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