github.com/danp/terraform@v0.9.5-0.20170426144147-39d740081351/builtin/providers/google/resource_compute_firewall.go (about)

     1  package google
     2  
     3  import (
     4  	"bytes"
     5  	"fmt"
     6  	"log"
     7  	"sort"
     8  	"strings"
     9  
    10  	"github.com/hashicorp/terraform/helper/hashcode"
    11  	"github.com/hashicorp/terraform/helper/schema"
    12  	"google.golang.org/api/compute/v1"
    13  	"google.golang.org/api/googleapi"
    14  )
    15  
    16  func resourceComputeFirewall() *schema.Resource {
    17  	return &schema.Resource{
    18  		Create: resourceComputeFirewallCreate,
    19  		Read:   resourceComputeFirewallRead,
    20  		Update: resourceComputeFirewallUpdate,
    21  		Delete: resourceComputeFirewallDelete,
    22  		Importer: &schema.ResourceImporter{
    23  			State: schema.ImportStatePassthrough,
    24  		},
    25  		SchemaVersion: 1,
    26  		MigrateState:  resourceComputeFirewallMigrateState,
    27  
    28  		Schema: map[string]*schema.Schema{
    29  			"name": {
    30  				Type:     schema.TypeString,
    31  				Required: true,
    32  				ForceNew: true,
    33  			},
    34  
    35  			"network": {
    36  				Type:     schema.TypeString,
    37  				Required: true,
    38  				ForceNew: true,
    39  			},
    40  
    41  			"allow": {
    42  				Type:     schema.TypeSet,
    43  				Required: true,
    44  				Elem: &schema.Resource{
    45  					Schema: map[string]*schema.Schema{
    46  						"protocol": {
    47  							Type:     schema.TypeString,
    48  							Required: true,
    49  						},
    50  
    51  						"ports": {
    52  							Type:     schema.TypeList,
    53  							Optional: true,
    54  							Elem:     &schema.Schema{Type: schema.TypeString},
    55  						},
    56  					},
    57  				},
    58  				Set: resourceComputeFirewallAllowHash,
    59  			},
    60  
    61  			"description": {
    62  				Type:     schema.TypeString,
    63  				Optional: true,
    64  			},
    65  
    66  			"project": {
    67  				Type:     schema.TypeString,
    68  				Optional: true,
    69  				ForceNew: true,
    70  				Computed: true,
    71  			},
    72  
    73  			"self_link": {
    74  				Type:     schema.TypeString,
    75  				Computed: true,
    76  			},
    77  
    78  			"source_ranges": {
    79  				Type:     schema.TypeSet,
    80  				Optional: true,
    81  				Elem:     &schema.Schema{Type: schema.TypeString},
    82  				Set:      schema.HashString,
    83  			},
    84  
    85  			"source_tags": {
    86  				Type:     schema.TypeSet,
    87  				Optional: true,
    88  				Elem:     &schema.Schema{Type: schema.TypeString},
    89  				Set:      schema.HashString,
    90  			},
    91  
    92  			"target_tags": {
    93  				Type:     schema.TypeSet,
    94  				Optional: true,
    95  				Elem:     &schema.Schema{Type: schema.TypeString},
    96  				Set:      schema.HashString,
    97  			},
    98  		},
    99  	}
   100  }
   101  
   102  func resourceComputeFirewallAllowHash(v interface{}) int {
   103  	var buf bytes.Buffer
   104  	m := v.(map[string]interface{})
   105  	buf.WriteString(fmt.Sprintf("%s-", m["protocol"].(string)))
   106  
   107  	// We need to make sure to sort the strings below so that we always
   108  	// generate the same hash code no matter what is in the set.
   109  	if v, ok := m["ports"]; ok {
   110  		s := convertStringArr(v.([]interface{}))
   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  	project, err := getProject(d, config)
   125  	if err != nil {
   126  		return err
   127  	}
   128  
   129  	firewall, err := resourceFirewall(d, meta)
   130  	if err != nil {
   131  		return err
   132  	}
   133  
   134  	op, err := config.clientCompute.Firewalls.Insert(
   135  		project, firewall).Do()
   136  	if err != nil {
   137  		return fmt.Errorf("Error creating firewall: %s", err)
   138  	}
   139  
   140  	// It probably maybe worked, so store the ID now
   141  	d.SetId(firewall.Name)
   142  
   143  	err = computeOperationWaitGlobal(config, op, project, "Creating Firewall")
   144  	if err != nil {
   145  		return err
   146  	}
   147  
   148  	return resourceComputeFirewallRead(d, meta)
   149  }
   150  
   151  func flattenAllowed(allowed []*compute.FirewallAllowed) []map[string]interface{} {
   152  	result := make([]map[string]interface{}, 0, len(allowed))
   153  	for _, allow := range allowed {
   154  		allowMap := make(map[string]interface{})
   155  		allowMap["protocol"] = allow.IPProtocol
   156  		allowMap["ports"] = allow.Ports
   157  
   158  		result = append(result, allowMap)
   159  	}
   160  	return result
   161  }
   162  
   163  func resourceComputeFirewallRead(d *schema.ResourceData, meta interface{}) error {
   164  	config := meta.(*Config)
   165  
   166  	project, err := getProject(d, config)
   167  	if err != nil {
   168  		return err
   169  	}
   170  
   171  	firewall, err := config.clientCompute.Firewalls.Get(
   172  		project, d.Id()).Do()
   173  	if err != nil {
   174  		if gerr, ok := err.(*googleapi.Error); ok && gerr.Code == 404 {
   175  			// The resource doesn't exist anymore
   176  			log.Printf("[WARN] Removing Firewall %q because it's gone", d.Get("name").(string))
   177  			d.SetId("")
   178  
   179  			return nil
   180  		}
   181  
   182  		return fmt.Errorf("Error reading firewall: %s", err)
   183  	}
   184  
   185  	networkUrl := strings.Split(firewall.Network, "/")
   186  	d.Set("self_link", firewall.SelfLink)
   187  	d.Set("name", firewall.Name)
   188  	d.Set("network", networkUrl[len(networkUrl)-1])
   189  	d.Set("description", firewall.Description)
   190  	d.Set("project", project)
   191  	d.Set("source_ranges", firewall.SourceRanges)
   192  	d.Set("source_tags", firewall.SourceTags)
   193  	d.Set("target_tags", firewall.TargetTags)
   194  	d.Set("allow", flattenAllowed(firewall.Allowed))
   195  	return nil
   196  }
   197  
   198  func resourceComputeFirewallUpdate(d *schema.ResourceData, meta interface{}) error {
   199  	config := meta.(*Config)
   200  
   201  	project, err := getProject(d, config)
   202  	if err != nil {
   203  		return err
   204  	}
   205  
   206  	d.Partial(true)
   207  
   208  	firewall, err := resourceFirewall(d, meta)
   209  	if err != nil {
   210  		return err
   211  	}
   212  
   213  	op, err := config.clientCompute.Firewalls.Update(
   214  		project, d.Id(), firewall).Do()
   215  	if err != nil {
   216  		return fmt.Errorf("Error updating firewall: %s", err)
   217  	}
   218  
   219  	err = computeOperationWaitGlobal(config, op, project, "Updating Firewall")
   220  	if err != nil {
   221  		return err
   222  	}
   223  
   224  	d.Partial(false)
   225  
   226  	return resourceComputeFirewallRead(d, meta)
   227  }
   228  
   229  func resourceComputeFirewallDelete(d *schema.ResourceData, meta interface{}) error {
   230  	config := meta.(*Config)
   231  
   232  	project, err := getProject(d, config)
   233  	if err != nil {
   234  		return err
   235  	}
   236  
   237  	// Delete the firewall
   238  	op, err := config.clientCompute.Firewalls.Delete(
   239  		project, d.Id()).Do()
   240  	if err != nil {
   241  		return fmt.Errorf("Error deleting firewall: %s", err)
   242  	}
   243  
   244  	err = computeOperationWaitGlobal(config, op, project, "Deleting Firewall")
   245  	if err != nil {
   246  		return err
   247  	}
   248  
   249  	d.SetId("")
   250  	return nil
   251  }
   252  
   253  func resourceFirewall(
   254  	d *schema.ResourceData,
   255  	meta interface{}) (*compute.Firewall, error) {
   256  	config := meta.(*Config)
   257  
   258  	project, _ := getProject(d, config)
   259  
   260  	// Look up the network to attach the firewall to
   261  	network, err := config.clientCompute.Networks.Get(
   262  		project, d.Get("network").(string)).Do()
   263  	if err != nil {
   264  		return nil, fmt.Errorf("Error reading network: %s", err)
   265  	}
   266  
   267  	// Build up the list of allowed entries
   268  	var allowed []*compute.FirewallAllowed
   269  	if v := d.Get("allow").(*schema.Set); v.Len() > 0 {
   270  		allowed = make([]*compute.FirewallAllowed, 0, v.Len())
   271  		for _, v := range v.List() {
   272  			m := v.(map[string]interface{})
   273  
   274  			var ports []string
   275  			if v := convertStringArr(m["ports"].([]interface{})); len(v) > 0 {
   276  				ports = make([]string, len(v))
   277  				for i, v := range v {
   278  					ports[i] = v
   279  				}
   280  			}
   281  
   282  			allowed = append(allowed, &compute.FirewallAllowed{
   283  				IPProtocol: m["protocol"].(string),
   284  				Ports:      ports,
   285  			})
   286  		}
   287  	}
   288  
   289  	// Build up the list of sources
   290  	var sourceRanges, sourceTags []string
   291  	if v := d.Get("source_ranges").(*schema.Set); v.Len() > 0 {
   292  		sourceRanges = make([]string, v.Len())
   293  		for i, v := range v.List() {
   294  			sourceRanges[i] = v.(string)
   295  		}
   296  	}
   297  	if v := d.Get("source_tags").(*schema.Set); v.Len() > 0 {
   298  		sourceTags = make([]string, v.Len())
   299  		for i, v := range v.List() {
   300  			sourceTags[i] = v.(string)
   301  		}
   302  	}
   303  
   304  	// Build up the list of targets
   305  	var targetTags []string
   306  	if v := d.Get("target_tags").(*schema.Set); v.Len() > 0 {
   307  		targetTags = make([]string, v.Len())
   308  		for i, v := range v.List() {
   309  			targetTags[i] = v.(string)
   310  		}
   311  	}
   312  
   313  	// Build the firewall parameter
   314  	return &compute.Firewall{
   315  		Name:         d.Get("name").(string),
   316  		Description:  d.Get("description").(string),
   317  		Network:      network.SelfLink,
   318  		Allowed:      allowed,
   319  		SourceRanges: sourceRanges,
   320  		SourceTags:   sourceTags,
   321  		TargetTags:   targetTags,
   322  	}, nil
   323  }