github.com/joshgarnett/terraform@v0.5.4-0.20160219181435-92dc20bb3594/builtin/providers/google/resource_compute_firewall.go (about)

     1  package google
     2  
     3  import (
     4  	"bytes"
     5  	"fmt"
     6  	"log"
     7  	"sort"
     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:      schema.HashString,
    55  						},
    56  					},
    57  				},
    58  				Set: resourceComputeFirewallAllowHash,
    59  			},
    60  
    61  			"source_ranges": &schema.Schema{
    62  				Type:     schema.TypeSet,
    63  				Optional: true,
    64  				Elem:     &schema.Schema{Type: schema.TypeString},
    65  				Set:      schema.HashString,
    66  			},
    67  
    68  			"source_tags": &schema.Schema{
    69  				Type:     schema.TypeSet,
    70  				Optional: true,
    71  				Elem:     &schema.Schema{Type: schema.TypeString},
    72  				Set:      schema.HashString,
    73  			},
    74  
    75  			"target_tags": &schema.Schema{
    76  				Type:     schema.TypeSet,
    77  				Optional: true,
    78  				Elem:     &schema.Schema{Type: schema.TypeString},
    79  				Set:      schema.HashString,
    80  			},
    81  
    82  			"self_link": &schema.Schema{
    83  				Type:     schema.TypeString,
    84  				Computed: true,
    85  			},
    86  		},
    87  	}
    88  }
    89  
    90  func resourceComputeFirewallAllowHash(v interface{}) int {
    91  	var buf bytes.Buffer
    92  	m := v.(map[string]interface{})
    93  	buf.WriteString(fmt.Sprintf("%s-", m["protocol"].(string)))
    94  
    95  	// We need to make sure to sort the strings below so that we always
    96  	// generate the same hash code no matter what is in the set.
    97  	if v, ok := m["ports"]; ok {
    98  		vs := v.(*schema.Set).List()
    99  		s := make([]string, len(vs))
   100  		for i, raw := range vs {
   101  			s[i] = raw.(string)
   102  		}
   103  		sort.Strings(s)
   104  
   105  		for _, v := range s {
   106  			buf.WriteString(fmt.Sprintf("%s-", v))
   107  		}
   108  	}
   109  
   110  	return hashcode.String(buf.String())
   111  }
   112  
   113  func resourceComputeFirewallCreate(d *schema.ResourceData, meta interface{}) error {
   114  	config := meta.(*Config)
   115  
   116  	firewall, err := resourceFirewall(d, meta)
   117  	if err != nil {
   118  		return err
   119  	}
   120  
   121  	op, err := config.clientCompute.Firewalls.Insert(
   122  		config.Project, firewall).Do()
   123  	if err != nil {
   124  		return fmt.Errorf("Error creating firewall: %s", err)
   125  	}
   126  
   127  	// It probably maybe worked, so store the ID now
   128  	d.SetId(firewall.Name)
   129  
   130  	err = computeOperationWaitGlobal(config, op, "Creating Firewall")
   131  	if err != nil {
   132  		return err
   133  	}
   134  
   135  	return resourceComputeFirewallRead(d, meta)
   136  }
   137  
   138  func resourceComputeFirewallRead(d *schema.ResourceData, meta interface{}) error {
   139  	config := meta.(*Config)
   140  
   141  	firewall, err := config.clientCompute.Firewalls.Get(
   142  		config.Project, d.Id()).Do()
   143  	if err != nil {
   144  		if gerr, ok := err.(*googleapi.Error); ok && gerr.Code == 404 {
   145  			// The resource doesn't exist anymore
   146  			log.Printf("[WARN] Removing Firewall %q because it's gone", d.Get("name").(string))
   147  			d.SetId("")
   148  
   149  			return nil
   150  		}
   151  
   152  		return fmt.Errorf("Error reading firewall: %s", err)
   153  	}
   154  
   155  	d.Set("self_link", firewall.SelfLink)
   156  
   157  	return nil
   158  }
   159  
   160  func resourceComputeFirewallUpdate(d *schema.ResourceData, meta interface{}) error {
   161  	config := meta.(*Config)
   162  
   163  	d.Partial(true)
   164  
   165  	firewall, err := resourceFirewall(d, meta)
   166  	if err != nil {
   167  		return err
   168  	}
   169  
   170  	op, err := config.clientCompute.Firewalls.Update(
   171  		config.Project, d.Id(), firewall).Do()
   172  	if err != nil {
   173  		return fmt.Errorf("Error updating firewall: %s", err)
   174  	}
   175  
   176  	err = computeOperationWaitGlobal(config, op, "Updating Firewall")
   177  	if err != nil {
   178  		return err
   179  	}
   180  
   181  	d.Partial(false)
   182  
   183  	return resourceComputeFirewallRead(d, meta)
   184  }
   185  
   186  func resourceComputeFirewallDelete(d *schema.ResourceData, meta interface{}) error {
   187  	config := meta.(*Config)
   188  
   189  	// Delete the firewall
   190  	op, err := config.clientCompute.Firewalls.Delete(
   191  		config.Project, d.Id()).Do()
   192  	if err != nil {
   193  		return fmt.Errorf("Error deleting firewall: %s", err)
   194  	}
   195  
   196  	err = computeOperationWaitGlobal(config, op, "Deleting Firewall")
   197  	if err != nil {
   198  		return err
   199  	}
   200  
   201  	d.SetId("")
   202  	return nil
   203  }
   204  
   205  func resourceFirewall(
   206  	d *schema.ResourceData,
   207  	meta interface{}) (*compute.Firewall, error) {
   208  	config := meta.(*Config)
   209  
   210  	// Look up the network to attach the firewall to
   211  	network, err := config.clientCompute.Networks.Get(
   212  		config.Project, d.Get("network").(string)).Do()
   213  	if err != nil {
   214  		return nil, fmt.Errorf("Error reading network: %s", err)
   215  	}
   216  
   217  	// Build up the list of allowed entries
   218  	var allowed []*compute.FirewallAllowed
   219  	if v := d.Get("allow").(*schema.Set); v.Len() > 0 {
   220  		allowed = make([]*compute.FirewallAllowed, 0, v.Len())
   221  		for _, v := range v.List() {
   222  			m := v.(map[string]interface{})
   223  
   224  			var ports []string
   225  			if v := m["ports"].(*schema.Set); v.Len() > 0 {
   226  				ports = make([]string, v.Len())
   227  				for i, v := range v.List() {
   228  					ports[i] = v.(string)
   229  				}
   230  			}
   231  
   232  			allowed = append(allowed, &compute.FirewallAllowed{
   233  				IPProtocol: m["protocol"].(string),
   234  				Ports:      ports,
   235  			})
   236  		}
   237  	}
   238  
   239  	// Build up the list of sources
   240  	var sourceRanges, sourceTags []string
   241  	if v := d.Get("source_ranges").(*schema.Set); v.Len() > 0 {
   242  		sourceRanges = make([]string, v.Len())
   243  		for i, v := range v.List() {
   244  			sourceRanges[i] = v.(string)
   245  		}
   246  	}
   247  	if v := d.Get("source_tags").(*schema.Set); v.Len() > 0 {
   248  		sourceTags = make([]string, v.Len())
   249  		for i, v := range v.List() {
   250  			sourceTags[i] = v.(string)
   251  		}
   252  	}
   253  
   254  	// Build up the list of targets
   255  	var targetTags []string
   256  	if v := d.Get("target_tags").(*schema.Set); v.Len() > 0 {
   257  		targetTags = make([]string, v.Len())
   258  		for i, v := range v.List() {
   259  			targetTags[i] = v.(string)
   260  		}
   261  	}
   262  
   263  	// Build the firewall parameter
   264  	return &compute.Firewall{
   265  		Name:         d.Get("name").(string),
   266  		Description:  d.Get("description").(string),
   267  		Network:      network.SelfLink,
   268  		Allowed:      allowed,
   269  		SourceRanges: sourceRanges,
   270  		SourceTags:   sourceTags,
   271  		TargetTags:   targetTags,
   272  	}, nil
   273  }