diff --git a/resource_compute_firewall.go b/resource_compute_firewall.go index 355c4808..2dfccb71 100644 --- a/resource_compute_firewall.go +++ b/resource_compute_firewall.go @@ -16,6 +16,7 @@ func resourceComputeFirewall() *schema.Resource { return &schema.Resource{ Create: resourceComputeFirewallCreate, Read: resourceComputeFirewallRead, + Update: resourceComputeFirewallUpdate, Delete: resourceComputeFirewallDelete, Schema: map[string]*schema.Schema{ @@ -101,58 +102,11 @@ func resourceComputeFirewallAllowHash(v interface{}) int { func resourceComputeFirewallCreate(d *schema.ResourceData, meta interface{}) error { config := meta.(*Config) - // Look up the network to attach the firewall to - network, err := config.clientCompute.Networks.Get( - config.Project, d.Get("network").(string)).Do() + firewall, err := resourceFirewall(d, meta) if err != nil { - return fmt.Errorf("Error reading network: %s", err) + return err } - // Build up the list of allowed entries - var allowed []*compute.FirewallAllowed - if v := d.Get("allow").(*schema.Set); v.Len() > 0 { - allowed = make([]*compute.FirewallAllowed, 0, v.Len()) - for _, v := range v.List() { - m := v.(map[string]interface{}) - - var ports []string - if v := m["ports"].(*schema.Set); v.Len() > 0 { - ports = make([]string, v.Len()) - for i, v := range v.List() { - ports[i] = v.(string) - } - } - - allowed = append(allowed, &compute.FirewallAllowed{ - IPProtocol: m["protocol"].(string), - Ports: ports, - }) - } - } - - // Build up the list of sources - var sourceRanges, sourceTags []string - if v := d.Get("source_ranges").(*schema.Set); v.Len() > 0 { - sourceRanges = make([]string, v.Len()) - for i, v := range v.List() { - sourceRanges[i] = v.(string) - } - } - if v := d.Get("source_tags").(*schema.Set); v.Len() > 0 { - sourceTags = make([]string, v.Len()) - for i, v := range v.List() { - sourceTags[i] = v.(string) - } - } - - // Build the firewall parameter - firewall := &compute.Firewall{ - Name: d.Get("name").(string), - Network: network.SelfLink, - Allowed: allowed, - SourceRanges: sourceRanges, - SourceTags: sourceTags, - } op, err := config.clientCompute.Firewalls.Insert( config.Project, firewall).Do() if err != nil { @@ -207,6 +161,43 @@ func resourceComputeFirewallRead(d *schema.ResourceData, meta interface{}) error return nil } +func resourceComputeFirewallUpdate(d *schema.ResourceData, meta interface{}) error { + config := meta.(*Config) + + firewall, err := resourceFirewall(d, meta) + if err != nil { + return err + } + + op, err := config.clientCompute.Firewalls.Update( + config.Project, d.Id(), firewall).Do() + if err != nil { + return fmt.Errorf("Error updating firewall: %s", err) + } + + // Wait for the operation to complete + w := &OperationWaiter{ + Service: config.clientCompute, + Op: op, + Project: config.Project, + Type: OperationWaitGlobal, + } + state := w.Conf() + state.Timeout = 2 * time.Minute + state.MinTimeout = 1 * time.Second + opRaw, err := state.WaitForState() + if err != nil { + return fmt.Errorf("Error waiting for firewall to update: %s", err) + } + op = opRaw.(*compute.Operation) + if op.Error != nil { + // Return the error + return OperationError(*op.Error) + } + + return resourceComputeFirewallRead(d, meta) +} + func resourceComputeFirewallDelete(d *schema.ResourceData, meta interface{}) error { config := meta.(*Config) @@ -240,3 +231,62 @@ func resourceComputeFirewallDelete(d *schema.ResourceData, meta interface{}) err d.SetId("") return nil } + +func resourceFirewall( + d *schema.ResourceData, + meta interface{}) (*compute.Firewall, error) { + config := meta.(*Config) + + // Look up the network to attach the firewall to + network, err := config.clientCompute.Networks.Get( + config.Project, d.Get("network").(string)).Do() + if err != nil { + return nil, fmt.Errorf("Error reading network: %s", err) + } + + // Build up the list of allowed entries + var allowed []*compute.FirewallAllowed + if v := d.Get("allow").(*schema.Set); v.Len() > 0 { + allowed = make([]*compute.FirewallAllowed, 0, v.Len()) + for _, v := range v.List() { + m := v.(map[string]interface{}) + + var ports []string + if v := m["ports"].(*schema.Set); v.Len() > 0 { + ports = make([]string, v.Len()) + for i, v := range v.List() { + ports[i] = v.(string) + } + } + + allowed = append(allowed, &compute.FirewallAllowed{ + IPProtocol: m["protocol"].(string), + Ports: ports, + }) + } + } + + // Build up the list of sources + var sourceRanges, sourceTags []string + if v := d.Get("source_ranges").(*schema.Set); v.Len() > 0 { + sourceRanges = make([]string, v.Len()) + for i, v := range v.List() { + sourceRanges[i] = v.(string) + } + } + if v := d.Get("source_tags").(*schema.Set); v.Len() > 0 { + sourceTags = make([]string, v.Len()) + for i, v := range v.List() { + sourceTags[i] = v.(string) + } + } + + // Build the firewall parameter + return &compute.Firewall{ + Name: d.Get("name").(string), + Network: network.SelfLink, + Allowed: allowed, + SourceRanges: sourceRanges, + SourceTags: sourceTags, + }, nil +} diff --git a/resource_compute_firewall_test.go b/resource_compute_firewall_test.go index 467867f6..a801bd86 100644 --- a/resource_compute_firewall_test.go +++ b/resource_compute_firewall_test.go @@ -28,6 +28,34 @@ func TestAccComputeFirewall_basic(t *testing.T) { }) } +func TestAccComputeFirewall_update(t *testing.T) { + var firewall compute.Firewall + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckComputeFirewallDestroy, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccComputeFirewall_basic, + Check: resource.ComposeTestCheckFunc( + testAccCheckComputeFirewallExists( + "google_compute_firewall.foobar", &firewall), + ), + }, + resource.TestStep{ + Config: testAccComputeFirewall_update, + Check: resource.ComposeTestCheckFunc( + testAccCheckComputeFirewallExists( + "google_compute_firewall.foobar", &firewall), + testAccCheckComputeFirewallPorts( + &firewall, "80-255"), + ), + }, + }, + }) +} + func testAccCheckComputeFirewallDestroy(s *terraform.State) error { config := testAccProvider.Meta().(*Config) @@ -75,6 +103,21 @@ func testAccCheckComputeFirewallExists(n string, firewall *compute.Firewall) res } } +func testAccCheckComputeFirewallPorts( + firewall *compute.Firewall, ports string) resource.TestCheckFunc { + return func(s *terraform.State) error { + if len(firewall.Allowed) == 0 { + return fmt.Errorf("no allowed rules") + } + + if firewall.Allowed[0].Ports[0] != ports { + return fmt.Errorf("bad: %#v", firewall.Allowed[0].Ports) + } + + return nil + } +} + const testAccComputeFirewall_basic = ` resource "google_compute_network" "foobar" { name = "terraform-test" @@ -90,3 +133,20 @@ resource "google_compute_firewall" "foobar" { protocol = "icmp" } }` + +const testAccComputeFirewall_update = ` +resource "google_compute_network" "foobar" { + name = "terraform-test" + ipv4_range = "10.0.0.0/16" +} + +resource "google_compute_firewall" "foobar" { + name = "terraform-test" + network = "${google_compute_network.foobar.name}" + source_tags = ["foo"] + + allow { + protocol = "tcp" + ports = ["80-255"] + } +}`