Skip to content

Commit

Permalink
Add Beta support & Beta feature deny to google_compute_firewall (#282)
Browse files Browse the repository at this point in the history
* Add versioned Beta support to google_compute_firewall.

* Add Beta support for deny to google_compute_firewall.

* remove extra line:

* make fmt

* Add missing ForceNew fields.

* Respond to review comments testing functionality + reducing network GET to v1
  • Loading branch information
rileykarson committed Aug 7, 2017
1 parent df30b04 commit 2d0d8bd
Show file tree
Hide file tree
Showing 3 changed files with 270 additions and 38 deletions.
209 changes: 171 additions & 38 deletions google/resource_compute_firewall.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,14 @@ import (

"github.com/hashicorp/terraform/helper/hashcode"
"github.com/hashicorp/terraform/helper/schema"

computeBeta "google.golang.org/api/compute/v0.beta"
"google.golang.org/api/compute/v1"
)

var FirewallBaseApiVersion = v1
var FirewallVersionedFeatures = []Feature{Feature{Version: v0beta, Item: "deny"}}

func resourceComputeFirewall() *schema.Resource {
return &schema.Resource{
Create: resourceComputeFirewallCreate,
Expand All @@ -37,8 +42,9 @@ func resourceComputeFirewall() *schema.Resource {
},

"allow": {
Type: schema.TypeSet,
Required: true,
Type: schema.TypeSet,
Optional: true,
ConflictsWith: []string{"deny"},
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"protocol": {
Expand All @@ -53,7 +59,33 @@ func resourceComputeFirewall() *schema.Resource {
},
},
},
Set: resourceComputeFirewallAllowHash,
Set: resourceComputeFirewallRuleHash,
},

"deny": {
Type: schema.TypeSet,
Optional: true,
ConflictsWith: []string{"allow"},
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"protocol": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
},

"ports": {
Type: schema.TypeList,
Optional: true,
Elem: &schema.Schema{Type: schema.TypeString},
ForceNew: true,
},
},
},
Set: resourceComputeFirewallRuleHash,

// Unlike allow, deny can't be updated upstream
ForceNew: true,
},

"description": {
Expand Down Expand Up @@ -98,7 +130,7 @@ func resourceComputeFirewall() *schema.Resource {
}
}

func resourceComputeFirewallAllowHash(v interface{}) int {
func resourceComputeFirewallRuleHash(v interface{}) int {
var buf bytes.Buffer
m := v.(map[string]interface{})
buf.WriteString(fmt.Sprintf("%s-", m["protocol"].(string)))
Expand All @@ -118,36 +150,57 @@ func resourceComputeFirewallAllowHash(v interface{}) int {
}

func resourceComputeFirewallCreate(d *schema.ResourceData, meta interface{}) error {
computeApiVersion := getComputeApiVersion(d, FirewallBaseApiVersion, FirewallVersionedFeatures)
config := meta.(*Config)

project, err := getProject(d, config)
if err != nil {
return err
}

firewall, err := resourceFirewall(d, meta)
firewall, err := resourceFirewall(d, meta, computeApiVersion)
if err != nil {
return err
}

op, err := config.clientCompute.Firewalls.Insert(
project, firewall).Do()
if err != nil {
return fmt.Errorf("Error creating firewall: %s", err)
var op interface{}
switch computeApiVersion {
case v1:
firewallV1 := &compute.Firewall{}
err := Convert(firewall, firewallV1)
if err != nil {
return err
}

op, err = config.clientCompute.Firewalls.Insert(project, firewallV1).Do()
if err != nil {
return fmt.Errorf("Error creating firewall: %s", err)
}
case v0beta:
firewallV0Beta := &computeBeta.Firewall{}
err := Convert(firewall, firewallV0Beta)
if err != nil {
return err
}

op, err = config.clientComputeBeta.Firewalls.Insert(project, firewallV0Beta).Do()
if err != nil {
return fmt.Errorf("Error creating firewall: %s", err)
}
}

// It probably maybe worked, so store the ID now
d.SetId(firewall.Name)

err = computeOperationWait(config, op, project, "Creating Firewall")
err = computeSharedOperationWait(config, op, project, "Creating Firewall")
if err != nil {
return err
}

return resourceComputeFirewallRead(d, meta)
}

func flattenAllowed(allowed []*compute.FirewallAllowed) []map[string]interface{} {
func flattenAllowed(allowed []*computeBeta.FirewallAllowed) []map[string]interface{} {
result := make([]map[string]interface{}, 0, len(allowed))
for _, allow := range allowed {
allowMap := make(map[string]interface{})
Expand All @@ -159,22 +212,53 @@ func flattenAllowed(allowed []*compute.FirewallAllowed) []map[string]interface{}
return result
}

func flattenDenied(denied []*computeBeta.FirewallDenied) []map[string]interface{} {
result := make([]map[string]interface{}, 0, len(denied))
for _, deny := range denied {
denyMap := make(map[string]interface{})
denyMap["protocol"] = deny.IPProtocol
denyMap["ports"] = deny.Ports

result = append(result, denyMap)
}
return result
}

func resourceComputeFirewallRead(d *schema.ResourceData, meta interface{}) error {
computeApiVersion := getComputeApiVersion(d, FirewallBaseApiVersion, FirewallVersionedFeatures)
config := meta.(*Config)

project, err := getProject(d, config)
if err != nil {
return err
}

firewall, err := config.clientCompute.Firewalls.Get(
project, d.Id()).Do()
if err != nil {
return handleNotFoundError(err, d, fmt.Sprintf("Firewall %q", d.Get("name").(string)))
firewall := &computeBeta.Firewall{}
switch computeApiVersion {
case v1:
firewallV1, err := config.clientCompute.Firewalls.Get(project, d.Id()).Do()
if err != nil {
return handleNotFoundError(err, d, fmt.Sprintf("Firewall %q", d.Get("name").(string)))
}

err = Convert(firewallV1, firewall)
if err != nil {
return err
}
case v0beta:
firewallV0Beta, err := config.clientComputeBeta.Firewalls.Get(project, d.Id()).Do()
if err != nil {
return handleNotFoundError(err, d, fmt.Sprintf("Firewall %q", d.Get("name").(string)))
}

err = Convert(firewallV0Beta, firewall)
if err != nil {
return err
}
}

networkUrl := strings.Split(firewall.Network, "/")
d.Set("self_link", firewall.SelfLink)
d.Set("self_link", ConvertSelfLinkToV1(firewall.SelfLink))
d.Set("name", firewall.Name)
d.Set("network", networkUrl[len(networkUrl)-1])
d.Set("description", firewall.Description)
Expand All @@ -183,10 +267,12 @@ func resourceComputeFirewallRead(d *schema.ResourceData, meta interface{}) error
d.Set("source_tags", firewall.SourceTags)
d.Set("target_tags", firewall.TargetTags)
d.Set("allow", flattenAllowed(firewall.Allowed))
d.Set("deny", flattenDenied(firewall.Denied))
return nil
}

func resourceComputeFirewallUpdate(d *schema.ResourceData, meta interface{}) error {
computeApiVersion := getComputeApiVersionUpdate(d, FirewallBaseApiVersion, FirewallVersionedFeatures, []Feature{})
config := meta.(*Config)

project, err := getProject(d, config)
Expand All @@ -196,18 +282,38 @@ func resourceComputeFirewallUpdate(d *schema.ResourceData, meta interface{}) err

d.Partial(true)

firewall, err := resourceFirewall(d, meta)
firewall, err := resourceFirewall(d, meta, computeApiVersion)
if err != nil {
return err
}

op, err := config.clientCompute.Firewalls.Update(
project, d.Id(), firewall).Do()
if err != nil {
return fmt.Errorf("Error updating firewall: %s", err)
var op interface{}
switch computeApiVersion {
case v1:
firewallV1 := &compute.Firewall{}
err := Convert(firewall, firewallV1)
if err != nil {
return err
}

op, err = config.clientCompute.Firewalls.Update(project, d.Id(), firewallV1).Do()
if err != nil {
return fmt.Errorf("Error updating firewall: %s", err)
}
case v0beta:
firewallV0Beta := &computeBeta.Firewall{}
err := Convert(firewall, firewallV0Beta)
if err != nil {
return err
}

op, err = config.clientComputeBeta.Firewalls.Update(project, d.Id(), firewallV0Beta).Do()
if err != nil {
return fmt.Errorf("Error updating firewall: %s", err)
}
}

err = computeOperationWait(config, op, project, "Updating Firewall")
err = computeSharedOperationWait(config, op, project, "Updating Firewall")
if err != nil {
return err
}
Expand All @@ -218,6 +324,7 @@ func resourceComputeFirewallUpdate(d *schema.ResourceData, meta interface{}) err
}

func resourceComputeFirewallDelete(d *schema.ResourceData, meta interface{}) error {
computeApiVersion := getComputeApiVersion(d, FirewallBaseApiVersion, FirewallVersionedFeatures)
config := meta.(*Config)

project, err := getProject(d, config)
Expand All @@ -226,13 +333,21 @@ func resourceComputeFirewallDelete(d *schema.ResourceData, meta interface{}) err
}

// Delete the firewall
op, err := config.clientCompute.Firewalls.Delete(
project, d.Id()).Do()
if err != nil {
return fmt.Errorf("Error deleting firewall: %s", err)
var op interface{}
switch computeApiVersion {
case v1:
op, err = config.clientCompute.Firewalls.Delete(project, d.Id()).Do()
if err != nil {
return fmt.Errorf("Error deleting firewall: %s", err)
}
case v0beta:
op, err = config.clientComputeBeta.Firewalls.Delete(project, d.Id()).Do()
if err != nil {
return fmt.Errorf("Error deleting firewall: %s", err)
}
}

err = computeOperationWait(config, op, project, "Deleting Firewall")
err = computeSharedOperationWait(config, op, project, "Deleting Firewall")
if err != nil {
return err
}
Expand All @@ -241,24 +356,41 @@ func resourceComputeFirewallDelete(d *schema.ResourceData, meta interface{}) err
return nil
}

func resourceFirewall(
d *schema.ResourceData,
meta interface{}) (*compute.Firewall, error) {
func resourceFirewall(d *schema.ResourceData, meta interface{}, computeApiVersion ComputeApiVersion) (*computeBeta.Firewall, error) {
config := meta.(*Config)

project, _ := getProject(d, config)

// Look up the network to attach the firewall to
network, err := config.clientCompute.Networks.Get(
project, d.Get("network").(string)).Do()
network, err := config.clientCompute.Networks.Get(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
var allowed []*computeBeta.FirewallAllowed
if v := d.Get("allow").(*schema.Set); v.Len() > 0 {
allowed = make([]*compute.FirewallAllowed, 0, v.Len())
allowed = make([]*computeBeta.FirewallAllowed, 0, v.Len())
for _, v := range v.List() {
m := v.(map[string]interface{})

var ports []string
if v := convertStringArr(m["ports"].([]interface{})); len(v) > 0 {
ports = make([]string, len(v))
for i, v := range v {
ports[i] = v
}
}

allowed = append(allowed, &computeBeta.FirewallAllowed{
IPProtocol: m["protocol"].(string),
Ports: ports,
})
}
}

// Build up the list of denied entries
var denied []*computeBeta.FirewallDenied
if v := d.Get("deny").(*schema.Set); v.Len() > 0 {
denied = make([]*computeBeta.FirewallDenied, 0, v.Len())
for _, v := range v.List() {
m := v.(map[string]interface{})

Expand All @@ -270,7 +402,7 @@ func resourceFirewall(
}
}

allowed = append(allowed, &compute.FirewallAllowed{
denied = append(denied, &computeBeta.FirewallDenied{
IPProtocol: m["protocol"].(string),
Ports: ports,
})
Expand Down Expand Up @@ -302,11 +434,12 @@ func resourceFirewall(
}

// Build the firewall parameter
return &compute.Firewall{
return &computeBeta.Firewall{
Name: d.Get("name").(string),
Description: d.Get("description").(string),
Network: network.SelfLink,
Allowed: allowed,
Denied: denied,
SourceRanges: sourceRanges,
SourceTags: sourceTags,
TargetTags: targetTags,
Expand Down
Loading

0 comments on commit 2d0d8bd

Please sign in to comment.