github.com/andresvia/terraform@v0.6.15-0.20160412045437-d51c75946785/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  			"network": &schema.Schema{
    30  				Type:     schema.TypeString,
    31  				Required: true,
    32  				ForceNew: true,
    33  			},
    34  
    35  			"allow": &schema.Schema{
    36  				Type:     schema.TypeSet,
    37  				Required: true,
    38  				Elem: &schema.Resource{
    39  					Schema: map[string]*schema.Schema{
    40  						"protocol": &schema.Schema{
    41  							Type:     schema.TypeString,
    42  							Required: true,
    43  						},
    44  
    45  						"ports": &schema.Schema{
    46  							Type:     schema.TypeSet,
    47  							Optional: true,
    48  							Elem:     &schema.Schema{Type: schema.TypeString},
    49  							Set:      schema.HashString,
    50  						},
    51  					},
    52  				},
    53  				Set: resourceComputeFirewallAllowHash,
    54  			},
    55  
    56  			"description": &schema.Schema{
    57  				Type:     schema.TypeString,
    58  				Optional: true,
    59  			},
    60  
    61  			"project": &schema.Schema{
    62  				Type:     schema.TypeString,
    63  				Optional: true,
    64  				ForceNew: true,
    65  			},
    66  
    67  			"self_link": &schema.Schema{
    68  				Type:     schema.TypeString,
    69  				Computed: true,
    70  			},
    71  
    72  			"source_ranges": &schema.Schema{
    73  				Type:     schema.TypeSet,
    74  				Optional: true,
    75  				Elem:     &schema.Schema{Type: schema.TypeString},
    76  				Set:      schema.HashString,
    77  			},
    78  
    79  			"source_tags": &schema.Schema{
    80  				Type:     schema.TypeSet,
    81  				Optional: true,
    82  				Elem:     &schema.Schema{Type: schema.TypeString},
    83  				Set:      schema.HashString,
    84  			},
    85  
    86  			"target_tags": &schema.Schema{
    87  				Type:     schema.TypeSet,
    88  				Optional: true,
    89  				Elem:     &schema.Schema{Type: schema.TypeString},
    90  				Set:      schema.HashString,
    91  			},
    92  		},
    93  	}
    94  }
    95  
    96  func resourceComputeFirewallAllowHash(v interface{}) int {
    97  	var buf bytes.Buffer
    98  	m := v.(map[string]interface{})
    99  	buf.WriteString(fmt.Sprintf("%s-", m["protocol"].(string)))
   100  
   101  	// We need to make sure to sort the strings below so that we always
   102  	// generate the same hash code no matter what is in the set.
   103  	if v, ok := m["ports"]; ok {
   104  		vs := v.(*schema.Set).List()
   105  		s := make([]string, len(vs))
   106  		for i, raw := range vs {
   107  			s[i] = raw.(string)
   108  		}
   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, "Creating Firewall")
   142  	if err != nil {
   143  		return err
   144  	}
   145  
   146  	return resourceComputeFirewallRead(d, meta)
   147  }
   148  
   149  func resourceComputeFirewallRead(d *schema.ResourceData, meta interface{}) error {
   150  	config := meta.(*Config)
   151  
   152  	project, err := getProject(d, config)
   153  	if err != nil {
   154  		return err
   155  	}
   156  
   157  	firewall, err := config.clientCompute.Firewalls.Get(
   158  		project, d.Id()).Do()
   159  	if err != nil {
   160  		if gerr, ok := err.(*googleapi.Error); ok && gerr.Code == 404 {
   161  			// The resource doesn't exist anymore
   162  			log.Printf("[WARN] Removing Firewall %q because it's gone", d.Get("name").(string))
   163  			d.SetId("")
   164  
   165  			return nil
   166  		}
   167  
   168  		return fmt.Errorf("Error reading firewall: %s", err)
   169  	}
   170  
   171  	d.Set("self_link", firewall.SelfLink)
   172  
   173  	return nil
   174  }
   175  
   176  func resourceComputeFirewallUpdate(d *schema.ResourceData, meta interface{}) error {
   177  	config := meta.(*Config)
   178  
   179  	project, err := getProject(d, config)
   180  	if err != nil {
   181  		return err
   182  	}
   183  
   184  	d.Partial(true)
   185  
   186  	firewall, err := resourceFirewall(d, meta)
   187  	if err != nil {
   188  		return err
   189  	}
   190  
   191  	op, err := config.clientCompute.Firewalls.Update(
   192  		project, d.Id(), firewall).Do()
   193  	if err != nil {
   194  		return fmt.Errorf("Error updating firewall: %s", err)
   195  	}
   196  
   197  	err = computeOperationWaitGlobal(config, op, "Updating Firewall")
   198  	if err != nil {
   199  		return err
   200  	}
   201  
   202  	d.Partial(false)
   203  
   204  	return resourceComputeFirewallRead(d, meta)
   205  }
   206  
   207  func resourceComputeFirewallDelete(d *schema.ResourceData, meta interface{}) error {
   208  	config := meta.(*Config)
   209  
   210  	project, err := getProject(d, config)
   211  	if err != nil {
   212  		return err
   213  	}
   214  
   215  	// Delete the firewall
   216  	op, err := config.clientCompute.Firewalls.Delete(
   217  		project, d.Id()).Do()
   218  	if err != nil {
   219  		return fmt.Errorf("Error deleting firewall: %s", err)
   220  	}
   221  
   222  	err = computeOperationWaitGlobal(config, op, "Deleting Firewall")
   223  	if err != nil {
   224  		return err
   225  	}
   226  
   227  	d.SetId("")
   228  	return nil
   229  }
   230  
   231  func resourceFirewall(
   232  	d *schema.ResourceData,
   233  	meta interface{}) (*compute.Firewall, error) {
   234  	config := meta.(*Config)
   235  
   236  	project, _ := getProject(d, config)
   237  
   238  	// Look up the network to attach the firewall to
   239  	network, err := config.clientCompute.Networks.Get(
   240  		project, d.Get("network").(string)).Do()
   241  	if err != nil {
   242  		return nil, fmt.Errorf("Error reading network: %s", err)
   243  	}
   244  
   245  	// Build up the list of allowed entries
   246  	var allowed []*compute.FirewallAllowed
   247  	if v := d.Get("allow").(*schema.Set); v.Len() > 0 {
   248  		allowed = make([]*compute.FirewallAllowed, 0, v.Len())
   249  		for _, v := range v.List() {
   250  			m := v.(map[string]interface{})
   251  
   252  			var ports []string
   253  			if v := m["ports"].(*schema.Set); v.Len() > 0 {
   254  				ports = make([]string, v.Len())
   255  				for i, v := range v.List() {
   256  					ports[i] = v.(string)
   257  				}
   258  			}
   259  
   260  			allowed = append(allowed, &compute.FirewallAllowed{
   261  				IPProtocol: m["protocol"].(string),
   262  				Ports:      ports,
   263  			})
   264  		}
   265  	}
   266  
   267  	// Build up the list of sources
   268  	var sourceRanges, sourceTags []string
   269  	if v := d.Get("source_ranges").(*schema.Set); v.Len() > 0 {
   270  		sourceRanges = make([]string, v.Len())
   271  		for i, v := range v.List() {
   272  			sourceRanges[i] = v.(string)
   273  		}
   274  	}
   275  	if v := d.Get("source_tags").(*schema.Set); v.Len() > 0 {
   276  		sourceTags = make([]string, v.Len())
   277  		for i, v := range v.List() {
   278  			sourceTags[i] = v.(string)
   279  		}
   280  	}
   281  
   282  	// Build up the list of targets
   283  	var targetTags []string
   284  	if v := d.Get("target_tags").(*schema.Set); v.Len() > 0 {
   285  		targetTags = make([]string, v.Len())
   286  		for i, v := range v.List() {
   287  			targetTags[i] = v.(string)
   288  		}
   289  	}
   290  
   291  	// Build the firewall parameter
   292  	return &compute.Firewall{
   293  		Name:         d.Get("name").(string),
   294  		Description:  d.Get("description").(string),
   295  		Network:      network.SelfLink,
   296  		Allowed:      allowed,
   297  		SourceRanges: sourceRanges,
   298  		SourceTags:   sourceTags,
   299  		TargetTags:   targetTags,
   300  	}, nil
   301  }