github.com/erriapo/terraform@v0.6.12-0.20160203182612-0340ea72354f/builtin/providers/azurerm/resource_arm_network_security_group.go (about)

     1  package azurerm
     2  
     3  import (
     4  	"bytes"
     5  	"fmt"
     6  	"log"
     7  	"net/http"
     8  	"time"
     9  
    10  	"github.com/Azure/azure-sdk-for-go/arm/network"
    11  	"github.com/hashicorp/terraform/helper/hashcode"
    12  	"github.com/hashicorp/terraform/helper/resource"
    13  	"github.com/hashicorp/terraform/helper/schema"
    14  )
    15  
    16  func resourceArmNetworkSecurityGroup() *schema.Resource {
    17  	return &schema.Resource{
    18  		Create: resourceArmNetworkSecurityGroupCreate,
    19  		Read:   resourceArmNetworkSecurityGroupRead,
    20  		Update: resourceArmNetworkSecurityGroupCreate,
    21  		Delete: resourceArmNetworkSecurityGroupDelete,
    22  
    23  		Schema: map[string]*schema.Schema{
    24  			"name": &schema.Schema{
    25  				Type:     schema.TypeString,
    26  				Required: true,
    27  				ForceNew: true,
    28  			},
    29  
    30  			"location": &schema.Schema{
    31  				Type:      schema.TypeString,
    32  				Required:  true,
    33  				ForceNew:  true,
    34  				StateFunc: azureRMNormalizeLocation,
    35  			},
    36  
    37  			"resource_group_name": &schema.Schema{
    38  				Type:     schema.TypeString,
    39  				Required: true,
    40  				ForceNew: true,
    41  			},
    42  
    43  			"security_rule": &schema.Schema{
    44  				Type:     schema.TypeSet,
    45  				Optional: true,
    46  				Computed: true,
    47  				Elem: &schema.Resource{
    48  					Schema: map[string]*schema.Schema{
    49  						"name": &schema.Schema{
    50  							Type:     schema.TypeString,
    51  							Required: true,
    52  						},
    53  
    54  						"description": &schema.Schema{
    55  							Type:     schema.TypeString,
    56  							Optional: true,
    57  							ValidateFunc: func(v interface{}, k string) (ws []string, errors []error) {
    58  								value := v.(string)
    59  								if len(value) > 140 {
    60  									errors = append(errors, fmt.Errorf(
    61  										"The network security rule description can be no longer than 140 chars"))
    62  								}
    63  								return
    64  							},
    65  						},
    66  
    67  						"protocol": &schema.Schema{
    68  							Type:         schema.TypeString,
    69  							Required:     true,
    70  							ValidateFunc: validateNetworkSecurityRuleProtocol,
    71  						},
    72  
    73  						"source_port_range": &schema.Schema{
    74  							Type:     schema.TypeString,
    75  							Required: true,
    76  						},
    77  
    78  						"destination_port_range": &schema.Schema{
    79  							Type:     schema.TypeString,
    80  							Required: true,
    81  						},
    82  
    83  						"source_address_prefix": &schema.Schema{
    84  							Type:     schema.TypeString,
    85  							Required: true,
    86  						},
    87  
    88  						"destination_address_prefix": &schema.Schema{
    89  							Type:     schema.TypeString,
    90  							Required: true,
    91  						},
    92  
    93  						"access": &schema.Schema{
    94  							Type:         schema.TypeString,
    95  							Required:     true,
    96  							ValidateFunc: validateNetworkSecurityRuleAccess,
    97  						},
    98  
    99  						"priority": &schema.Schema{
   100  							Type:     schema.TypeInt,
   101  							Required: true,
   102  							ValidateFunc: func(v interface{}, k string) (ws []string, errors []error) {
   103  								value := v.(int)
   104  								if value < 100 || value > 4096 {
   105  									errors = append(errors, fmt.Errorf(
   106  										"The `priority` can only be between 100 and 4096"))
   107  								}
   108  								return
   109  							},
   110  						},
   111  
   112  						"direction": &schema.Schema{
   113  							Type:         schema.TypeString,
   114  							Required:     true,
   115  							ValidateFunc: validateNetworkSecurityRuleDirection,
   116  						},
   117  					},
   118  				},
   119  				Set: resourceArmNetworkSecurityGroupRuleHash,
   120  			},
   121  
   122  			"tags": tagsSchema(),
   123  		},
   124  	}
   125  }
   126  
   127  func resourceArmNetworkSecurityGroupCreate(d *schema.ResourceData, meta interface{}) error {
   128  	client := meta.(*ArmClient)
   129  	secClient := client.secGroupClient
   130  
   131  	name := d.Get("name").(string)
   132  	location := d.Get("location").(string)
   133  	resGroup := d.Get("resource_group_name").(string)
   134  	tags := d.Get("tags").(map[string]interface{})
   135  
   136  	sgRules, sgErr := expandAzureRmSecurityRules(d)
   137  	if sgErr != nil {
   138  		return fmt.Errorf("Error Building list of Network Security Group Rules: %s", sgErr)
   139  	}
   140  
   141  	sg := network.SecurityGroup{
   142  		Name:     &name,
   143  		Location: &location,
   144  		Properties: &network.SecurityGroupPropertiesFormat{
   145  			SecurityRules: &sgRules,
   146  		},
   147  		Tags: expandTags(tags),
   148  	}
   149  
   150  	resp, err := secClient.CreateOrUpdate(resGroup, name, sg)
   151  	if err != nil {
   152  		return err
   153  	}
   154  
   155  	d.SetId(*resp.ID)
   156  
   157  	log.Printf("[DEBUG] Waiting for Network Security Group (%s) to become available", name)
   158  	stateConf := &resource.StateChangeConf{
   159  		Pending: []string{"Accepted", "Updating"},
   160  		Target:  []string{"Succeeded"},
   161  		Refresh: securityGroupStateRefreshFunc(client, resGroup, name),
   162  		Timeout: 10 * time.Minute,
   163  	}
   164  	if _, err := stateConf.WaitForState(); err != nil {
   165  		return fmt.Errorf("Error waiting for Network Securty Group (%s) to become available: %s", name, err)
   166  	}
   167  
   168  	return resourceArmNetworkSecurityGroupRead(d, meta)
   169  }
   170  
   171  func resourceArmNetworkSecurityGroupRead(d *schema.ResourceData, meta interface{}) error {
   172  	secGroupClient := meta.(*ArmClient).secGroupClient
   173  
   174  	id, err := parseAzureResourceID(d.Id())
   175  	if err != nil {
   176  		return err
   177  	}
   178  	resGroup := id.ResourceGroup
   179  	name := id.Path["networkSecurityGroups"]
   180  
   181  	resp, err := secGroupClient.Get(resGroup, name, "")
   182  	if resp.StatusCode == http.StatusNotFound {
   183  		d.SetId("")
   184  		return nil
   185  	}
   186  	if err != nil {
   187  		return fmt.Errorf("Error making Read request on Azure Network Security Group %s: %s", name, err)
   188  	}
   189  
   190  	if resp.Properties.SecurityRules != nil {
   191  		d.Set("security_rule", flattenNetworkSecurityRules(resp.Properties.SecurityRules))
   192  	}
   193  
   194  	flattenAndSetTags(d, resp.Tags)
   195  
   196  	return nil
   197  }
   198  
   199  func resourceArmNetworkSecurityGroupDelete(d *schema.ResourceData, meta interface{}) error {
   200  	secGroupClient := meta.(*ArmClient).secGroupClient
   201  
   202  	id, err := parseAzureResourceID(d.Id())
   203  	if err != nil {
   204  		return err
   205  	}
   206  	resGroup := id.ResourceGroup
   207  	name := id.Path["networkSecurityGroups"]
   208  
   209  	_, err = secGroupClient.Delete(resGroup, name)
   210  
   211  	return err
   212  }
   213  
   214  func resourceArmNetworkSecurityGroupRuleHash(v interface{}) int {
   215  	var buf bytes.Buffer
   216  	m := v.(map[string]interface{})
   217  	buf.WriteString(fmt.Sprintf("%s-", m["protocol"].(string)))
   218  	buf.WriteString(fmt.Sprintf("%s-", m["source_port_range"].(string)))
   219  	buf.WriteString(fmt.Sprintf("%s-", m["destination_port_range"].(string)))
   220  	buf.WriteString(fmt.Sprintf("%s-", m["source_address_prefix"].(string)))
   221  	buf.WriteString(fmt.Sprintf("%s-", m["destination_address_prefix"].(string)))
   222  	buf.WriteString(fmt.Sprintf("%s-", m["access"].(string)))
   223  	buf.WriteString(fmt.Sprintf("%d-", m["priority"].(int)))
   224  	buf.WriteString(fmt.Sprintf("%s-", m["direction"].(string)))
   225  
   226  	return hashcode.String(buf.String())
   227  }
   228  
   229  func securityGroupStateRefreshFunc(client *ArmClient, resourceGroupName string, securityGroupName string) resource.StateRefreshFunc {
   230  	return func() (interface{}, string, error) {
   231  		res, err := client.secGroupClient.Get(resourceGroupName, securityGroupName, "")
   232  		if err != nil {
   233  			return nil, "", fmt.Errorf("Error issuing read request in securityGroupStateRefreshFunc to Azure ARM for network security group '%s' (RG: '%s'): %s", securityGroupName, resourceGroupName, err)
   234  		}
   235  
   236  		return res, *res.Properties.ProvisioningState, nil
   237  	}
   238  }
   239  
   240  func flattenNetworkSecurityRules(rules *[]network.SecurityRule) []map[string]interface{} {
   241  	result := make([]map[string]interface{}, 0, len(*rules))
   242  	for _, rule := range *rules {
   243  		sgRule := make(map[string]interface{})
   244  		sgRule["name"] = *rule.Name
   245  		sgRule["destination_address_prefix"] = *rule.Properties.DestinationAddressPrefix
   246  		sgRule["destination_port_range"] = *rule.Properties.DestinationPortRange
   247  		sgRule["source_address_prefix"] = *rule.Properties.SourceAddressPrefix
   248  		sgRule["source_port_range"] = *rule.Properties.SourcePortRange
   249  		sgRule["priority"] = int(*rule.Properties.Priority)
   250  		sgRule["access"] = rule.Properties.Access
   251  		sgRule["direction"] = rule.Properties.Direction
   252  		sgRule["protocol"] = rule.Properties.Protocol
   253  
   254  		if rule.Properties.Description != nil {
   255  			sgRule["description"] = *rule.Properties.Description
   256  		}
   257  
   258  		result = append(result, sgRule)
   259  	}
   260  	return result
   261  }
   262  
   263  func expandAzureRmSecurityRules(d *schema.ResourceData) ([]network.SecurityRule, error) {
   264  	sgRules := d.Get("security_rule").(*schema.Set).List()
   265  	rules := make([]network.SecurityRule, 0, len(sgRules))
   266  
   267  	for _, sgRaw := range sgRules {
   268  		data := sgRaw.(map[string]interface{})
   269  
   270  		source_port_range := data["source_port_range"].(string)
   271  		destination_port_range := data["destination_port_range"].(string)
   272  		source_address_prefix := data["source_address_prefix"].(string)
   273  		destination_address_prefix := data["destination_address_prefix"].(string)
   274  		priority := data["priority"].(int)
   275  
   276  		properties := network.SecurityRulePropertiesFormat{
   277  			SourcePortRange:          &source_port_range,
   278  			DestinationPortRange:     &destination_port_range,
   279  			SourceAddressPrefix:      &source_address_prefix,
   280  			DestinationAddressPrefix: &destination_address_prefix,
   281  			Priority:                 &priority,
   282  			Access:                   network.SecurityRuleAccess(data["access"].(string)),
   283  			Direction:                network.SecurityRuleDirection(data["direction"].(string)),
   284  			Protocol:                 network.SecurityRuleProtocol(data["protocol"].(string)),
   285  		}
   286  
   287  		if v := data["description"].(string); v != "" {
   288  			properties.Description = &v
   289  		}
   290  
   291  		name := data["name"].(string)
   292  		rule := network.SecurityRule{
   293  			Name:       &name,
   294  			Properties: &properties,
   295  		}
   296  
   297  		rules = append(rules, rule)
   298  	}
   299  
   300  	return rules, nil
   301  }