github.com/ottenhoff/terraform@v0.7.0-rc1.0.20160607213102-ac2d195cc560/builtin/providers/azurerm/resource_arm_network_security_group.go (about)

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