github.com/anuaimi/terraform@v0.6.4-0.20150904235404-2bf9aec61da8/builtin/providers/google/resource_compute_firewall.go (about)

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