package openstack import ( "fmt" "log" "github.com/gophercloud/gophercloud" "github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/fwaas/policies" "github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/fwaas/rules" "github.com/hashicorp/terraform/helper/schema" ) func resourceFWRuleV1() *schema.Resource { return &schema.Resource{ Create: resourceFWRuleV1Create, Read: resourceFWRuleV1Read, Update: resourceFWRuleV1Update, Delete: resourceFWRuleV1Delete, Importer: &schema.ResourceImporter{ State: schema.ImportStatePassthrough, }, Schema: map[string]*schema.Schema{ "region": { Type: schema.TypeString, Optional: true, Computed: true, ForceNew: true, }, "name": { Type: schema.TypeString, Optional: true, }, "description": { Type: schema.TypeString, Optional: true, }, "protocol": { Type: schema.TypeString, Required: true, }, "action": { Type: schema.TypeString, Required: true, }, "ip_version": { Type: schema.TypeInt, Optional: true, Default: 4, }, "source_ip_address": { Type: schema.TypeString, Optional: true, }, "destination_ip_address": { Type: schema.TypeString, Optional: true, }, "source_port": { Type: schema.TypeString, Optional: true, }, "destination_port": { Type: schema.TypeString, Optional: true, }, "enabled": { Type: schema.TypeBool, Optional: true, Default: true, }, "tenant_id": { Type: schema.TypeString, Optional: true, ForceNew: true, }, "value_specs": { Type: schema.TypeMap, Optional: true, ForceNew: true, }, }, } } func resourceFWRuleV1Create(d *schema.ResourceData, meta interface{}) error { config := meta.(*Config) networkingClient, err := config.networkingV2Client(GetRegion(d, config)) if err != nil { return fmt.Errorf("Error creating OpenStack networking client: %s", err) } enabled := d.Get("enabled").(bool) ipVersion := resourceFWRuleV1DetermineIPVersion(d.Get("ip_version").(int)) protocol := resourceFWRuleV1DetermineProtocol(d.Get("protocol").(string)) ruleConfiguration := RuleCreateOpts{ rules.CreateOpts{ Name: d.Get("name").(string), Description: d.Get("description").(string), Protocol: protocol, Action: d.Get("action").(string), IPVersion: ipVersion, SourceIPAddress: d.Get("source_ip_address").(string), DestinationIPAddress: d.Get("destination_ip_address").(string), SourcePort: d.Get("source_port").(string), DestinationPort: d.Get("destination_port").(string), Enabled: &enabled, TenantID: d.Get("tenant_id").(string), }, MapValueSpecs(d), } log.Printf("[DEBUG] Create firewall rule: %#v", ruleConfiguration) rule, err := rules.Create(networkingClient, ruleConfiguration).Extract() if err != nil { return err } log.Printf("[DEBUG] Firewall rule with id %s : %#v", rule.ID, rule) d.SetId(rule.ID) return resourceFWRuleV1Read(d, meta) } func resourceFWRuleV1Read(d *schema.ResourceData, meta interface{}) error { log.Printf("[DEBUG] Retrieve information about firewall rule: %s", d.Id()) config := meta.(*Config) networkingClient, err := config.networkingV2Client(GetRegion(d, config)) if err != nil { return fmt.Errorf("Error creating OpenStack networking client: %s", err) } rule, err := rules.Get(networkingClient, d.Id()).Extract() if err != nil { return CheckDeleted(d, err, "FW rule") } log.Printf("[DEBUG] Read OpenStack Firewall Rule %s: %#v", d.Id(), rule) d.Set("action", rule.Action) d.Set("name", rule.Name) d.Set("description", rule.Description) d.Set("ip_version", rule.IPVersion) d.Set("source_ip_address", rule.SourceIPAddress) d.Set("destination_ip_address", rule.DestinationIPAddress) d.Set("source_port", rule.SourcePort) d.Set("destination_port", rule.DestinationPort) d.Set("enabled", rule.Enabled) if rule.Protocol == "" { d.Set("protocol", "any") } else { d.Set("protocol", rule.Protocol) } d.Set("region", GetRegion(d, config)) return nil } func resourceFWRuleV1Update(d *schema.ResourceData, meta interface{}) error { config := meta.(*Config) networkingClient, err := config.networkingV2Client(GetRegion(d, config)) if err != nil { return fmt.Errorf("Error creating OpenStack networking client: %s", err) } var updateOpts rules.UpdateOpts if d.HasChange("name") { name := d.Get("name").(string) updateOpts.Name = &name } if d.HasChange("description") { description := d.Get("description").(string) updateOpts.Description = &description } if d.HasChange("protocol") { protocol := d.Get("protocol").(string) updateOpts.Protocol = &protocol } if d.HasChange("action") { action := d.Get("action").(string) updateOpts.Action = &action } if d.HasChange("ip_version") { ipVersion := resourceFWRuleV1DetermineIPVersion(d.Get("ip_version").(int)) updateOpts.IPVersion = &ipVersion } if d.HasChange("source_ip_address") { sourceIPAddress := d.Get("source_ip_address").(string) updateOpts.SourceIPAddress = &sourceIPAddress // Also include the ip_version. ipVersion := resourceFWRuleV1DetermineIPVersion(d.Get("ip_version").(int)) updateOpts.IPVersion = &ipVersion } if d.HasChange("source_port") { sourcePort := d.Get("source_port").(string) if sourcePort == "" { sourcePort = "0" } updateOpts.SourcePort = &sourcePort // Also include the protocol. protocol := d.Get("protocol").(string) updateOpts.Protocol = &protocol } if d.HasChange("destination_ip_address") { destinationIPAddress := d.Get("destination_ip_address").(string) updateOpts.DestinationIPAddress = &destinationIPAddress // Also include the ip_version. ipVersion := resourceFWRuleV1DetermineIPVersion(d.Get("ip_version").(int)) updateOpts.IPVersion = &ipVersion } if d.HasChange("destination_port") { destinationPort := d.Get("destination_port").(string) if destinationPort == "" { destinationPort = "0" } updateOpts.DestinationPort = &destinationPort // Also include the protocol. protocol := d.Get("protocol").(string) updateOpts.Protocol = &protocol } if d.HasChange("enabled") { enabled := d.Get("enabled").(bool) updateOpts.Enabled = &enabled } log.Printf("[DEBUG] Updating firewall rules: %#v", updateOpts) err = rules.Update(networkingClient, d.Id(), updateOpts).Err if err != nil { return err } return resourceFWRuleV1Read(d, meta) } func resourceFWRuleV1Delete(d *schema.ResourceData, meta interface{}) error { log.Printf("[DEBUG] Destroy firewall rule: %s", d.Id()) config := meta.(*Config) networkingClient, err := config.networkingV2Client(GetRegion(d, config)) if err != nil { return fmt.Errorf("Error creating OpenStack networking client: %s", err) } rule, err := rules.Get(networkingClient, d.Id()).Extract() if err != nil { return err } if rule.PolicyID != "" { _, err := policies.RemoveRule(networkingClient, rule.PolicyID, rule.ID).Extract() if err != nil { return err } } return rules.Delete(networkingClient, d.Id()).Err } func resourceFWRuleV1DetermineIPVersion(ipv int) gophercloud.IPVersion { // Determine the IP Version var ipVersion gophercloud.IPVersion switch ipv { case 4: ipVersion = gophercloud.IPv4 case 6: ipVersion = gophercloud.IPv6 } return ipVersion } func resourceFWRuleV1DetermineProtocol(p string) rules.Protocol { var protocol rules.Protocol switch p { case "any": protocol = rules.ProtocolAny case "icmp": protocol = rules.ProtocolICMP case "tcp": protocol = rules.ProtocolTCP case "udp": protocol = rules.ProtocolUDP } return protocol }