github.com/erriapo/terraform@v0.6.12-0.20160203182612-0340ea72354f/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: 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  	err = computeOperationWaitGlobal(config, op, "Creating Firewall")
   139  	if err != nil {
   140  		return err
   141  	}
   142  
   143  	return resourceComputeFirewallRead(d, meta)
   144  }
   145  
   146  func resourceComputeFirewallRead(d *schema.ResourceData, meta interface{}) error {
   147  	config := meta.(*Config)
   148  
   149  	firewall, err := config.clientCompute.Firewalls.Get(
   150  		config.Project, d.Id()).Do()
   151  	if err != nil {
   152  		if gerr, ok := err.(*googleapi.Error); ok && gerr.Code == 404 {
   153  			// The resource doesn't exist anymore
   154  			log.Printf("[WARN] Removing Firewall %q because it's gone", d.Get("name").(string))
   155  			d.SetId("")
   156  
   157  			return nil
   158  		}
   159  
   160  		return fmt.Errorf("Error reading firewall: %s", err)
   161  	}
   162  
   163  	d.Set("self_link", firewall.SelfLink)
   164  
   165  	return nil
   166  }
   167  
   168  func resourceComputeFirewallUpdate(d *schema.ResourceData, meta interface{}) error {
   169  	config := meta.(*Config)
   170  
   171  	d.Partial(true)
   172  
   173  	firewall, err := resourceFirewall(d, meta)
   174  	if err != nil {
   175  		return err
   176  	}
   177  
   178  	op, err := config.clientCompute.Firewalls.Update(
   179  		config.Project, d.Id(), firewall).Do()
   180  	if err != nil {
   181  		return fmt.Errorf("Error updating firewall: %s", err)
   182  	}
   183  
   184  	err = computeOperationWaitGlobal(config, op, "Updating Firewall")
   185  	if err != nil {
   186  		return err
   187  	}
   188  
   189  	d.Partial(false)
   190  
   191  	return resourceComputeFirewallRead(d, meta)
   192  }
   193  
   194  func resourceComputeFirewallDelete(d *schema.ResourceData, meta interface{}) error {
   195  	config := meta.(*Config)
   196  
   197  	// Delete the firewall
   198  	op, err := config.clientCompute.Firewalls.Delete(
   199  		config.Project, d.Id()).Do()
   200  	if err != nil {
   201  		return fmt.Errorf("Error deleting firewall: %s", err)
   202  	}
   203  
   204  	err = computeOperationWaitGlobal(config, op, "Deleting Firewall")
   205  	if err != nil {
   206  		return err
   207  	}
   208  
   209  	d.SetId("")
   210  	return nil
   211  }
   212  
   213  func resourceFirewall(
   214  	d *schema.ResourceData,
   215  	meta interface{}) (*compute.Firewall, error) {
   216  	config := meta.(*Config)
   217  
   218  	// Look up the network to attach the firewall to
   219  	network, err := config.clientCompute.Networks.Get(
   220  		config.Project, d.Get("network").(string)).Do()
   221  	if err != nil {
   222  		return nil, fmt.Errorf("Error reading network: %s", err)
   223  	}
   224  
   225  	// Build up the list of allowed entries
   226  	var allowed []*compute.FirewallAllowed
   227  	if v := d.Get("allow").(*schema.Set); v.Len() > 0 {
   228  		allowed = make([]*compute.FirewallAllowed, 0, v.Len())
   229  		for _, v := range v.List() {
   230  			m := v.(map[string]interface{})
   231  
   232  			var ports []string
   233  			if v := m["ports"].(*schema.Set); v.Len() > 0 {
   234  				ports = make([]string, v.Len())
   235  				for i, v := range v.List() {
   236  					ports[i] = v.(string)
   237  				}
   238  			}
   239  
   240  			allowed = append(allowed, &compute.FirewallAllowed{
   241  				IPProtocol: m["protocol"].(string),
   242  				Ports:      ports,
   243  			})
   244  		}
   245  	}
   246  
   247  	// Build up the list of sources
   248  	var sourceRanges, sourceTags []string
   249  	if v := d.Get("source_ranges").(*schema.Set); v.Len() > 0 {
   250  		sourceRanges = make([]string, v.Len())
   251  		for i, v := range v.List() {
   252  			sourceRanges[i] = v.(string)
   253  		}
   254  	}
   255  	if v := d.Get("source_tags").(*schema.Set); v.Len() > 0 {
   256  		sourceTags = make([]string, v.Len())
   257  		for i, v := range v.List() {
   258  			sourceTags[i] = v.(string)
   259  		}
   260  	}
   261  
   262  	// Build up the list of targets
   263  	var targetTags []string
   264  	if v := d.Get("target_tags").(*schema.Set); v.Len() > 0 {
   265  		targetTags = make([]string, v.Len())
   266  		for i, v := range v.List() {
   267  			targetTags[i] = v.(string)
   268  		}
   269  	}
   270  
   271  	// Build the firewall parameter
   272  	return &compute.Firewall{
   273  		Name:         d.Get("name").(string),
   274  		Description:  d.Get("description").(string),
   275  		Network:      network.SelfLink,
   276  		Allowed:      allowed,
   277  		SourceRanges: sourceRanges,
   278  		SourceTags:   sourceTags,
   279  		TargetTags:   targetTags,
   280  	}, nil
   281  }