232 lines
5.7 KiB
Go
232 lines
5.7 KiB
Go
package openstack
|
|
|
|
import (
|
|
"fmt"
|
|
"log"
|
|
"time"
|
|
|
|
"github.com/gophercloud/gophercloud"
|
|
"github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/fwaas/policies"
|
|
"github.com/hashicorp/terraform/helper/resource"
|
|
"github.com/hashicorp/terraform/helper/schema"
|
|
)
|
|
|
|
func resourceFWPolicyV1() *schema.Resource {
|
|
return &schema.Resource{
|
|
Create: resourceFWPolicyV1Create,
|
|
Read: resourceFWPolicyV1Read,
|
|
Update: resourceFWPolicyV1Update,
|
|
Delete: resourceFWPolicyV1Delete,
|
|
Importer: &schema.ResourceImporter{
|
|
State: schema.ImportStatePassthrough,
|
|
},
|
|
|
|
Timeouts: &schema.ResourceTimeout{
|
|
Create: schema.DefaultTimeout(10 * time.Minute),
|
|
},
|
|
|
|
Schema: map[string]*schema.Schema{
|
|
"region": &schema.Schema{
|
|
Type: schema.TypeString,
|
|
Required: true,
|
|
ForceNew: true,
|
|
DefaultFunc: schema.EnvDefaultFunc("OS_REGION_NAME", ""),
|
|
},
|
|
"name": &schema.Schema{
|
|
Type: schema.TypeString,
|
|
Optional: true,
|
|
},
|
|
"description": &schema.Schema{
|
|
Type: schema.TypeString,
|
|
Optional: true,
|
|
},
|
|
"audited": &schema.Schema{
|
|
Type: schema.TypeBool,
|
|
Optional: true,
|
|
Default: false,
|
|
},
|
|
"shared": &schema.Schema{
|
|
Type: schema.TypeBool,
|
|
Optional: true,
|
|
},
|
|
"tenant_id": &schema.Schema{
|
|
Type: schema.TypeString,
|
|
Optional: true,
|
|
ForceNew: true,
|
|
Computed: true,
|
|
},
|
|
"rules": &schema.Schema{
|
|
Type: schema.TypeList,
|
|
Optional: true,
|
|
Elem: &schema.Schema{Type: schema.TypeString},
|
|
},
|
|
"value_specs": &schema.Schema{
|
|
Type: schema.TypeMap,
|
|
Optional: true,
|
|
ForceNew: true,
|
|
},
|
|
},
|
|
}
|
|
}
|
|
|
|
func resourceFWPolicyV1Create(d *schema.ResourceData, meta interface{}) error {
|
|
config := meta.(*Config)
|
|
networkingClient, err := config.networkingV2Client(GetRegion(d))
|
|
if err != nil {
|
|
return fmt.Errorf("Error creating OpenStack networking client: %s", err)
|
|
}
|
|
|
|
v := d.Get("rules").([]interface{})
|
|
|
|
log.Printf("[DEBUG] Rules found : %#v", v)
|
|
log.Printf("[DEBUG] Rules count : %d", len(v))
|
|
|
|
rules := make([]string, len(v))
|
|
for i, v := range v {
|
|
rules[i] = v.(string)
|
|
}
|
|
|
|
audited := d.Get("audited").(bool)
|
|
|
|
opts := PolicyCreateOpts{
|
|
policies.CreateOpts{
|
|
Name: d.Get("name").(string),
|
|
Description: d.Get("description").(string),
|
|
Audited: &audited,
|
|
TenantID: d.Get("tenant_id").(string),
|
|
Rules: rules,
|
|
},
|
|
MapValueSpecs(d),
|
|
}
|
|
|
|
if r, ok := d.GetOk("shared"); ok {
|
|
shared := r.(bool)
|
|
opts.Shared = &shared
|
|
}
|
|
|
|
log.Printf("[DEBUG] Create firewall policy: %#v", opts)
|
|
|
|
policy, err := policies.Create(networkingClient, opts).Extract()
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
log.Printf("[DEBUG] Firewall policy created: %#v", policy)
|
|
|
|
d.SetId(policy.ID)
|
|
|
|
return resourceFWPolicyV1Read(d, meta)
|
|
}
|
|
|
|
func resourceFWPolicyV1Read(d *schema.ResourceData, meta interface{}) error {
|
|
log.Printf("[DEBUG] Retrieve information about firewall policy: %s", d.Id())
|
|
|
|
config := meta.(*Config)
|
|
networkingClient, err := config.networkingV2Client(GetRegion(d))
|
|
if err != nil {
|
|
return fmt.Errorf("Error creating OpenStack networking client: %s", err)
|
|
}
|
|
|
|
policy, err := policies.Get(networkingClient, d.Id()).Extract()
|
|
if err != nil {
|
|
return CheckDeleted(d, err, "FW policy")
|
|
}
|
|
|
|
log.Printf("[DEBUG] Read OpenStack Firewall Policy %s: %#v", d.Id(), policy)
|
|
|
|
d.Set("name", policy.Name)
|
|
d.Set("description", policy.Description)
|
|
d.Set("shared", policy.Shared)
|
|
d.Set("audited", policy.Audited)
|
|
d.Set("tenant_id", policy.TenantID)
|
|
d.Set("rules", policy.Rules)
|
|
d.Set("region", GetRegion(d))
|
|
|
|
return nil
|
|
}
|
|
|
|
func resourceFWPolicyV1Update(d *schema.ResourceData, meta interface{}) error {
|
|
config := meta.(*Config)
|
|
networkingClient, err := config.networkingV2Client(GetRegion(d))
|
|
if err != nil {
|
|
return fmt.Errorf("Error creating OpenStack networking client: %s", err)
|
|
}
|
|
|
|
opts := policies.UpdateOpts{}
|
|
|
|
if d.HasChange("name") {
|
|
opts.Name = d.Get("name").(string)
|
|
}
|
|
|
|
if d.HasChange("description") {
|
|
opts.Description = d.Get("description").(string)
|
|
}
|
|
|
|
if d.HasChange("rules") {
|
|
v := d.Get("rules").([]interface{})
|
|
|
|
log.Printf("[DEBUG] Rules found : %#v", v)
|
|
log.Printf("[DEBUG] Rules count : %d", len(v))
|
|
|
|
rules := make([]string, len(v))
|
|
for i, v := range v {
|
|
rules[i] = v.(string)
|
|
}
|
|
opts.Rules = rules
|
|
}
|
|
|
|
log.Printf("[DEBUG] Updating firewall policy with id %s: %#v", d.Id(), opts)
|
|
|
|
err = policies.Update(networkingClient, d.Id(), opts).Err
|
|
if err != nil {
|
|
return err
|
|
}
|
|
|
|
return resourceFWPolicyV1Read(d, meta)
|
|
}
|
|
|
|
func resourceFWPolicyV1Delete(d *schema.ResourceData, meta interface{}) error {
|
|
log.Printf("[DEBUG] Destroy firewall policy: %s", d.Id())
|
|
|
|
config := meta.(*Config)
|
|
networkingClient, err := config.networkingV2Client(GetRegion(d))
|
|
if err != nil {
|
|
return fmt.Errorf("Error creating OpenStack networking client: %s", err)
|
|
}
|
|
|
|
stateConf := &resource.StateChangeConf{
|
|
Pending: []string{"ACTIVE"},
|
|
Target: []string{"DELETED"},
|
|
Refresh: waitForFirewallPolicyDeletion(networkingClient, d.Id()),
|
|
Timeout: d.Timeout(schema.TimeoutCreate),
|
|
Delay: 0,
|
|
MinTimeout: 2 * time.Second,
|
|
}
|
|
|
|
if _, err = stateConf.WaitForState(); err != nil {
|
|
return err
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func waitForFirewallPolicyDeletion(networkingClient *gophercloud.ServiceClient, id string) resource.StateRefreshFunc {
|
|
return func() (interface{}, string, error) {
|
|
err := policies.Delete(networkingClient, id).Err
|
|
if err == nil {
|
|
return "", "DELETED", nil
|
|
}
|
|
|
|
if errCode, ok := err.(gophercloud.ErrUnexpectedResponseCode); ok {
|
|
if errCode.Actual == 409 {
|
|
// This error usually means that the policy is attached
|
|
// to a firewall. At this point, the firewall is probably
|
|
// being delete. So, we retry a few times.
|
|
return nil, "ACTIVE", nil
|
|
}
|
|
}
|
|
|
|
return nil, "ACTIVE", err
|
|
}
|
|
}
|