github.com/koding/terraform@v0.6.4-0.20170608090606-5d7e0339779d/builtin/providers/google/resource_compute_firewall.go (about)

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