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