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 }