github.com/andresvia/terraform@v0.6.15-0.20160412045437-d51c75946785/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 }