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 }