github.com/chalford/terraform@v0.3.7-0.20150113080010-a78c69a8c81f/builtin/providers/google/resource_compute_firewall.go (about)

     1  package google
     2  
     3  import (
     4  	"bytes"
     5  	"fmt"
     6  	"sort"
     7  	"time"
     8  
     9  	"code.google.com/p/google-api-go-client/compute/v1"
    10  	"code.google.com/p/google-api-go-client/googleapi"
    11  	"github.com/hashicorp/terraform/helper/hashcode"
    12  	"github.com/hashicorp/terraform/helper/schema"
    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: func(v interface{}) int {
    50  								return hashcode.String(v.(string))
    51  							},
    52  						},
    53  					},
    54  				},
    55  				Set: resourceComputeFirewallAllowHash,
    56  			},
    57  
    58  			"source_ranges": &schema.Schema{
    59  				Type:     schema.TypeSet,
    60  				Optional: true,
    61  				Elem:     &schema.Schema{Type: schema.TypeString},
    62  				Set: func(v interface{}) int {
    63  					return hashcode.String(v.(string))
    64  				},
    65  			},
    66  
    67  			"source_tags": &schema.Schema{
    68  				Type:     schema.TypeSet,
    69  				Optional: true,
    70  				Elem:     &schema.Schema{Type: schema.TypeString},
    71  				Set: func(v interface{}) int {
    72  					return hashcode.String(v.(string))
    73  				},
    74  			},
    75  
    76  			"target_tags": &schema.Schema{
    77  				Type:     schema.TypeSet,
    78  				Optional: true,
    79  				Elem:     &schema.Schema{Type: schema.TypeString},
    80  				Set: func(v interface{}) int {
    81  					return hashcode.String(v.(string))
    82  				},
    83  			},
    84  		},
    85  	}
    86  }
    87  
    88  func resourceComputeFirewallAllowHash(v interface{}) int {
    89  	var buf bytes.Buffer
    90  	m := v.(map[string]interface{})
    91  	buf.WriteString(fmt.Sprintf("%s-", m["protocol"].(string)))
    92  
    93  	// We need to make sure to sort the strings below so that we always
    94  	// generate the same hash code no matter what is in the set.
    95  	if v, ok := m["ports"]; ok {
    96  		vs := v.(*schema.Set).List()
    97  		s := make([]string, len(vs))
    98  		for i, raw := range vs {
    99  			s[i] = raw.(string)
   100  		}
   101  		sort.Strings(s)
   102  
   103  		for _, v := range s {
   104  			buf.WriteString(fmt.Sprintf("%s-", v))
   105  		}
   106  	}
   107  
   108  	return hashcode.String(buf.String())
   109  }
   110  
   111  func resourceComputeFirewallCreate(d *schema.ResourceData, meta interface{}) error {
   112  	config := meta.(*Config)
   113  
   114  	firewall, err := resourceFirewall(d, meta)
   115  	if err != nil {
   116  		return err
   117  	}
   118  
   119  	op, err := config.clientCompute.Firewalls.Insert(
   120  		config.Project, firewall).Do()
   121  	if err != nil {
   122  		return fmt.Errorf("Error creating firewall: %s", err)
   123  	}
   124  
   125  	// It probably maybe worked, so store the ID now
   126  	d.SetId(firewall.Name)
   127  
   128  	// Wait for the operation to complete
   129  	w := &OperationWaiter{
   130  		Service: config.clientCompute,
   131  		Op:      op,
   132  		Project: config.Project,
   133  		Type:    OperationWaitGlobal,
   134  	}
   135  	state := w.Conf()
   136  	state.Timeout = 2 * time.Minute
   137  	state.MinTimeout = 1 * time.Second
   138  	opRaw, err := state.WaitForState()
   139  	if err != nil {
   140  		return fmt.Errorf("Error waiting for firewall to create: %s", err)
   141  	}
   142  	op = opRaw.(*compute.Operation)
   143  	if op.Error != nil {
   144  		// The resource didn't actually create
   145  		d.SetId("")
   146  
   147  		// Return the error
   148  		return OperationError(*op.Error)
   149  	}
   150  
   151  	return resourceComputeFirewallRead(d, meta)
   152  }
   153  
   154  func resourceComputeFirewallRead(d *schema.ResourceData, meta interface{}) error {
   155  	config := meta.(*Config)
   156  
   157  	_, err := config.clientCompute.Firewalls.Get(
   158  		config.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  			d.SetId("")
   163  
   164  			return nil
   165  		}
   166  
   167  		return fmt.Errorf("Error reading firewall: %s", err)
   168  	}
   169  
   170  	return nil
   171  }
   172  
   173  func resourceComputeFirewallUpdate(d *schema.ResourceData, meta interface{}) error {
   174  	config := meta.(*Config)
   175  
   176  	d.Partial(true)
   177  
   178  	firewall, err := resourceFirewall(d, meta)
   179  	if err != nil {
   180  		return err
   181  	}
   182  
   183  	op, err := config.clientCompute.Firewalls.Update(
   184  		config.Project, d.Id(), firewall).Do()
   185  	if err != nil {
   186  		return fmt.Errorf("Error updating firewall: %s", err)
   187  	}
   188  
   189  	// Wait for the operation to complete
   190  	w := &OperationWaiter{
   191  		Service: config.clientCompute,
   192  		Op:      op,
   193  		Project: config.Project,
   194  		Type:    OperationWaitGlobal,
   195  	}
   196  	state := w.Conf()
   197  	state.Timeout = 2 * time.Minute
   198  	state.MinTimeout = 1 * time.Second
   199  	opRaw, err := state.WaitForState()
   200  	if err != nil {
   201  		return fmt.Errorf("Error waiting for firewall to update: %s", err)
   202  	}
   203  	op = opRaw.(*compute.Operation)
   204  	if op.Error != nil {
   205  		// Return the error
   206  		return OperationError(*op.Error)
   207  	}
   208  
   209  	d.Partial(false)
   210  
   211  	return resourceComputeFirewallRead(d, meta)
   212  }
   213  
   214  func resourceComputeFirewallDelete(d *schema.ResourceData, meta interface{}) error {
   215  	config := meta.(*Config)
   216  
   217  	// Delete the firewall
   218  	op, err := config.clientCompute.Firewalls.Delete(
   219  		config.Project, d.Id()).Do()
   220  	if err != nil {
   221  		return fmt.Errorf("Error deleting firewall: %s", err)
   222  	}
   223  
   224  	// Wait for the operation to complete
   225  	w := &OperationWaiter{
   226  		Service: config.clientCompute,
   227  		Op:      op,
   228  		Project: config.Project,
   229  		Type:    OperationWaitGlobal,
   230  	}
   231  	state := w.Conf()
   232  	state.Timeout = 2 * time.Minute
   233  	state.MinTimeout = 1 * time.Second
   234  	opRaw, err := state.WaitForState()
   235  	if err != nil {
   236  		return fmt.Errorf("Error waiting for firewall to delete: %s", err)
   237  	}
   238  	op = opRaw.(*compute.Operation)
   239  	if op.Error != nil {
   240  		// Return the error
   241  		return OperationError(*op.Error)
   242  	}
   243  
   244  	d.SetId("")
   245  	return nil
   246  }
   247  
   248  func resourceFirewall(
   249  	d *schema.ResourceData,
   250  	meta interface{}) (*compute.Firewall, error) {
   251  	config := meta.(*Config)
   252  
   253  	// Look up the network to attach the firewall to
   254  	network, err := config.clientCompute.Networks.Get(
   255  		config.Project, d.Get("network").(string)).Do()
   256  	if err != nil {
   257  		return nil, fmt.Errorf("Error reading network: %s", err)
   258  	}
   259  
   260  	// Build up the list of allowed entries
   261  	var allowed []*compute.FirewallAllowed
   262  	if v := d.Get("allow").(*schema.Set); v.Len() > 0 {
   263  		allowed = make([]*compute.FirewallAllowed, 0, v.Len())
   264  		for _, v := range v.List() {
   265  			m := v.(map[string]interface{})
   266  
   267  			var ports []string
   268  			if v := m["ports"].(*schema.Set); v.Len() > 0 {
   269  				ports = make([]string, v.Len())
   270  				for i, v := range v.List() {
   271  					ports[i] = v.(string)
   272  				}
   273  			}
   274  
   275  			allowed = append(allowed, &compute.FirewallAllowed{
   276  				IPProtocol: m["protocol"].(string),
   277  				Ports:      ports,
   278  			})
   279  		}
   280  	}
   281  
   282  	// Build up the list of sources
   283  	var sourceRanges, sourceTags []string
   284  	if v := d.Get("source_ranges").(*schema.Set); v.Len() > 0 {
   285  		sourceRanges = make([]string, v.Len())
   286  		for i, v := range v.List() {
   287  			sourceRanges[i] = v.(string)
   288  		}
   289  	}
   290  	if v := d.Get("source_tags").(*schema.Set); v.Len() > 0 {
   291  		sourceTags = make([]string, v.Len())
   292  		for i, v := range v.List() {
   293  			sourceTags[i] = v.(string)
   294  		}
   295  	}
   296  
   297  	// Build up the list of targets
   298  	var targetTags []string
   299  	if v := d.Get("target_tags").(*schema.Set); v.Len() > 0 {
   300  		targetTags = make([]string, v.Len())
   301  		for i, v := range v.List() {
   302  			targetTags[i] = v.(string)
   303  		}
   304  	}
   305  
   306  	// Build the firewall parameter
   307  	return &compute.Firewall{
   308  		Name:         d.Get("name").(string),
   309  		Network:      network.SelfLink,
   310  		Allowed:      allowed,
   311  		SourceRanges: sourceRanges,
   312  		SourceTags:   sourceTags,
   313  		TargetTags:   targetTags,
   314  	}, nil
   315  }