github.com/koding/terraform@v0.6.4-0.20170608090606-5d7e0339779d/builtin/providers/openstack/resource_openstack_networking_secgroup_rule_v2.go (about) 1 package openstack 2 3 import ( 4 "fmt" 5 "log" 6 "strconv" 7 "strings" 8 "time" 9 10 "github.com/hashicorp/terraform/helper/resource" 11 "github.com/hashicorp/terraform/helper/schema" 12 13 "github.com/gophercloud/gophercloud" 14 "github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/security/rules" 15 ) 16 17 func resourceNetworkingSecGroupRuleV2() *schema.Resource { 18 return &schema.Resource{ 19 Create: resourceNetworkingSecGroupRuleV2Create, 20 Read: resourceNetworkingSecGroupRuleV2Read, 21 Delete: resourceNetworkingSecGroupRuleV2Delete, 22 Importer: &schema.ResourceImporter{ 23 State: schema.ImportStatePassthrough, 24 }, 25 26 Timeouts: &schema.ResourceTimeout{ 27 Delete: schema.DefaultTimeout(10 * time.Minute), 28 }, 29 30 Schema: map[string]*schema.Schema{ 31 "region": &schema.Schema{ 32 Type: schema.TypeString, 33 Required: true, 34 ForceNew: true, 35 DefaultFunc: schema.EnvDefaultFunc("OS_REGION_NAME", ""), 36 }, 37 "direction": &schema.Schema{ 38 Type: schema.TypeString, 39 Required: true, 40 ForceNew: true, 41 }, 42 "ethertype": &schema.Schema{ 43 Type: schema.TypeString, 44 Required: true, 45 ForceNew: true, 46 }, 47 "port_range_min": &schema.Schema{ 48 Type: schema.TypeInt, 49 Optional: true, 50 ForceNew: true, 51 Computed: true, 52 }, 53 "port_range_max": &schema.Schema{ 54 Type: schema.TypeInt, 55 Optional: true, 56 ForceNew: true, 57 Computed: true, 58 }, 59 "protocol": &schema.Schema{ 60 Type: schema.TypeString, 61 Optional: true, 62 ForceNew: true, 63 Computed: true, 64 }, 65 "remote_group_id": &schema.Schema{ 66 Type: schema.TypeString, 67 Optional: true, 68 ForceNew: true, 69 Computed: true, 70 }, 71 "remote_ip_prefix": &schema.Schema{ 72 Type: schema.TypeString, 73 Optional: true, 74 ForceNew: true, 75 Computed: true, 76 StateFunc: func(v interface{}) string { 77 return strings.ToLower(v.(string)) 78 }, 79 }, 80 "security_group_id": &schema.Schema{ 81 Type: schema.TypeString, 82 Required: true, 83 ForceNew: true, 84 }, 85 "tenant_id": &schema.Schema{ 86 Type: schema.TypeString, 87 Optional: true, 88 ForceNew: true, 89 Computed: true, 90 }, 91 }, 92 } 93 } 94 95 func resourceNetworkingSecGroupRuleV2Create(d *schema.ResourceData, meta interface{}) error { 96 97 config := meta.(*Config) 98 networkingClient, err := config.networkingV2Client(GetRegion(d)) 99 if err != nil { 100 return fmt.Errorf("Error creating OpenStack networking client: %s", err) 101 } 102 103 portRangeMin := d.Get("port_range_min").(int) 104 portRangeMax := d.Get("port_range_max").(int) 105 protocol := d.Get("protocol").(string) 106 107 if protocol == "" { 108 if portRangeMin != 0 || portRangeMax != 0 { 109 return fmt.Errorf("A protocol must be specified when using port_range_min and port_range_max") 110 } 111 } 112 113 opts := rules.CreateOpts{ 114 SecGroupID: d.Get("security_group_id").(string), 115 PortRangeMin: d.Get("port_range_min").(int), 116 PortRangeMax: d.Get("port_range_max").(int), 117 RemoteGroupID: d.Get("remote_group_id").(string), 118 RemoteIPPrefix: d.Get("remote_ip_prefix").(string), 119 TenantID: d.Get("tenant_id").(string), 120 } 121 122 if v, ok := d.GetOk("direction"); ok { 123 direction := resourceNetworkingSecGroupRuleV2DetermineDirection(v.(string)) 124 opts.Direction = direction 125 } 126 127 if v, ok := d.GetOk("ethertype"); ok { 128 ethertype := resourceNetworkingSecGroupRuleV2DetermineEtherType(v.(string)) 129 opts.EtherType = ethertype 130 } 131 132 if v, ok := d.GetOk("protocol"); ok { 133 protocol := resourceNetworkingSecGroupRuleV2DetermineProtocol(v.(string)) 134 opts.Protocol = protocol 135 } 136 137 log.Printf("[DEBUG] Create OpenStack Neutron security group: %#v", opts) 138 139 security_group_rule, err := rules.Create(networkingClient, opts).Extract() 140 if err != nil { 141 return err 142 } 143 144 log.Printf("[DEBUG] OpenStack Neutron Security Group Rule created: %#v", security_group_rule) 145 146 d.SetId(security_group_rule.ID) 147 148 return resourceNetworkingSecGroupRuleV2Read(d, meta) 149 } 150 151 func resourceNetworkingSecGroupRuleV2Read(d *schema.ResourceData, meta interface{}) error { 152 log.Printf("[DEBUG] Retrieve information about security group rule: %s", d.Id()) 153 154 config := meta.(*Config) 155 networkingClient, err := config.networkingV2Client(GetRegion(d)) 156 if err != nil { 157 return fmt.Errorf("Error creating OpenStack networking client: %s", err) 158 } 159 160 security_group_rule, err := rules.Get(networkingClient, d.Id()).Extract() 161 162 if err != nil { 163 return CheckDeleted(d, err, "OpenStack Security Group Rule") 164 } 165 166 d.Set("direction", security_group_rule.Direction) 167 d.Set("ethertype", security_group_rule.EtherType) 168 d.Set("protocol", security_group_rule.Protocol) 169 d.Set("port_range_min", security_group_rule.PortRangeMin) 170 d.Set("port_range_max", security_group_rule.PortRangeMax) 171 d.Set("remote_group_id", security_group_rule.RemoteGroupID) 172 d.Set("remote_ip_prefix", security_group_rule.RemoteIPPrefix) 173 d.Set("security_group_id", security_group_rule.SecGroupID) 174 d.Set("tenant_id", security_group_rule.TenantID) 175 d.Set("region", GetRegion(d)) 176 177 return nil 178 } 179 180 func resourceNetworkingSecGroupRuleV2Delete(d *schema.ResourceData, meta interface{}) error { 181 log.Printf("[DEBUG] Destroy security group rule: %s", d.Id()) 182 183 config := meta.(*Config) 184 networkingClient, err := config.networkingV2Client(GetRegion(d)) 185 if err != nil { 186 return fmt.Errorf("Error creating OpenStack networking client: %s", err) 187 } 188 189 stateConf := &resource.StateChangeConf{ 190 Pending: []string{"ACTIVE"}, 191 Target: []string{"DELETED"}, 192 Refresh: waitForSecGroupRuleDelete(networkingClient, d.Id()), 193 Timeout: d.Timeout(schema.TimeoutDelete), 194 Delay: 5 * time.Second, 195 MinTimeout: 3 * time.Second, 196 } 197 198 _, err = stateConf.WaitForState() 199 if err != nil { 200 return fmt.Errorf("Error deleting OpenStack Neutron Security Group Rule: %s", err) 201 } 202 203 d.SetId("") 204 return err 205 } 206 207 func resourceNetworkingSecGroupRuleV2DetermineDirection(v string) rules.RuleDirection { 208 var direction rules.RuleDirection 209 switch v { 210 case "ingress": 211 direction = rules.DirIngress 212 case "egress": 213 direction = rules.DirEgress 214 } 215 216 return direction 217 } 218 219 func resourceNetworkingSecGroupRuleV2DetermineEtherType(v string) rules.RuleEtherType { 220 var etherType rules.RuleEtherType 221 switch v { 222 case "IPv4": 223 etherType = rules.EtherType4 224 case "IPv6": 225 etherType = rules.EtherType6 226 } 227 228 return etherType 229 } 230 231 func resourceNetworkingSecGroupRuleV2DetermineProtocol(v string) rules.RuleProtocol { 232 var protocol rules.RuleProtocol 233 234 // Check and see if the requested protocol matched a list of known protocol names. 235 switch v { 236 case "tcp": 237 protocol = rules.ProtocolTCP 238 case "udp": 239 protocol = rules.ProtocolUDP 240 case "icmp": 241 protocol = rules.ProtocolICMP 242 case "ah": 243 protocol = rules.ProtocolAH 244 case "dccp": 245 protocol = rules.ProtocolDCCP 246 case "egp": 247 protocol = rules.ProtocolEGP 248 case "esp": 249 protocol = rules.ProtocolESP 250 case "gre": 251 protocol = rules.ProtocolGRE 252 case "igmp": 253 protocol = rules.ProtocolIGMP 254 case "ipv6-encap": 255 protocol = rules.ProtocolIPv6Encap 256 case "ipv6-frag": 257 protocol = rules.ProtocolIPv6Frag 258 case "ipv6-icmp": 259 protocol = rules.ProtocolIPv6ICMP 260 case "ipv6-nonxt": 261 protocol = rules.ProtocolIPv6NoNxt 262 case "ipv6-opts": 263 protocol = rules.ProtocolIPv6Opts 264 case "ipv6-route": 265 protocol = rules.ProtocolIPv6Route 266 case "ospf": 267 protocol = rules.ProtocolOSPF 268 case "pgm": 269 protocol = rules.ProtocolPGM 270 case "rsvp": 271 protocol = rules.ProtocolRSVP 272 case "sctp": 273 protocol = rules.ProtocolSCTP 274 case "udplite": 275 protocol = rules.ProtocolUDPLite 276 case "vrrp": 277 protocol = rules.ProtocolVRRP 278 } 279 280 // If the protocol wasn't matched above, see if it's an integer. 281 if protocol == "" { 282 _, err := strconv.Atoi(v) 283 if err == nil { 284 protocol = rules.RuleProtocol(v) 285 } 286 } 287 288 return protocol 289 } 290 291 func waitForSecGroupRuleDelete(networkingClient *gophercloud.ServiceClient, secGroupRuleId string) resource.StateRefreshFunc { 292 return func() (interface{}, string, error) { 293 log.Printf("[DEBUG] Attempting to delete OpenStack Security Group Rule %s.\n", secGroupRuleId) 294 295 r, err := rules.Get(networkingClient, secGroupRuleId).Extract() 296 if err != nil { 297 if _, ok := err.(gophercloud.ErrDefault404); ok { 298 log.Printf("[DEBUG] Successfully deleted OpenStack Neutron Security Group Rule %s", secGroupRuleId) 299 return r, "DELETED", nil 300 } 301 return r, "ACTIVE", err 302 } 303 304 err = rules.Delete(networkingClient, secGroupRuleId).ExtractErr() 305 if err != nil { 306 if _, ok := err.(gophercloud.ErrDefault404); ok { 307 log.Printf("[DEBUG] Successfully deleted OpenStack Neutron Security Group Rule %s", secGroupRuleId) 308 return r, "DELETED", nil 309 } 310 return r, "ACTIVE", err 311 } 312 313 log.Printf("[DEBUG] OpenStack Neutron Security Group Rule %s still active.\n", secGroupRuleId) 314 return r, "ACTIVE", nil 315 } 316 }