2017-05-18 23:25:28 +02:00
|
|
|
package openstack
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
"log"
|
|
|
|
"time"
|
|
|
|
|
2017-05-22 00:39:52 +02:00
|
|
|
"github.com/gophercloud/gophercloud"
|
2017-05-18 23:25:28 +02:00
|
|
|
"github.com/gophercloud/gophercloud/openstack/dns/v2/zones"
|
2017-05-22 00:39:52 +02:00
|
|
|
|
|
|
|
"github.com/hashicorp/terraform/helper/resource"
|
2017-05-18 23:25:28 +02:00
|
|
|
"github.com/hashicorp/terraform/helper/schema"
|
|
|
|
)
|
|
|
|
|
|
|
|
func resourceDNSZoneV2() *schema.Resource {
|
|
|
|
return &schema.Resource{
|
|
|
|
Create: resourceDNSZoneV2Create,
|
|
|
|
Read: resourceDNSZoneV2Read,
|
|
|
|
Update: resourceDNSZoneV2Update,
|
|
|
|
Delete: resourceDNSZoneV2Delete,
|
|
|
|
Importer: &schema.ResourceImporter{
|
|
|
|
State: schema.ImportStatePassthrough,
|
|
|
|
},
|
|
|
|
|
|
|
|
Timeouts: &schema.ResourceTimeout{
|
|
|
|
Create: schema.DefaultTimeout(10 * time.Minute),
|
2017-05-22 00:39:52 +02:00
|
|
|
Update: schema.DefaultTimeout(10 * time.Minute),
|
2017-05-18 23:25:28 +02:00
|
|
|
Delete: 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,
|
|
|
|
Required: true,
|
|
|
|
ForceNew: true,
|
|
|
|
},
|
|
|
|
"email": &schema.Schema{
|
|
|
|
Type: schema.TypeString,
|
|
|
|
Optional: true,
|
|
|
|
ForceNew: false,
|
|
|
|
},
|
|
|
|
"type": &schema.Schema{
|
2017-05-22 00:39:52 +02:00
|
|
|
Type: schema.TypeString,
|
|
|
|
Optional: true,
|
|
|
|
Computed: true,
|
|
|
|
ForceNew: true,
|
|
|
|
ValidateFunc: resourceDNSZoneV2ValidType,
|
2017-05-18 23:25:28 +02:00
|
|
|
},
|
|
|
|
"attributes": &schema.Schema{
|
|
|
|
Type: schema.TypeMap,
|
|
|
|
Optional: true,
|
|
|
|
ForceNew: true,
|
|
|
|
},
|
|
|
|
"ttl": &schema.Schema{
|
|
|
|
Type: schema.TypeInt,
|
|
|
|
Optional: true,
|
2017-05-22 00:39:52 +02:00
|
|
|
Computed: true,
|
2017-05-18 23:25:28 +02:00
|
|
|
ForceNew: false,
|
|
|
|
},
|
|
|
|
"description": &schema.Schema{
|
|
|
|
Type: schema.TypeString,
|
|
|
|
Optional: true,
|
|
|
|
ForceNew: false,
|
|
|
|
},
|
|
|
|
"masters": &schema.Schema{
|
|
|
|
Type: schema.TypeSet,
|
|
|
|
Optional: true,
|
|
|
|
ForceNew: false,
|
|
|
|
Elem: &schema.Schema{Type: schema.TypeString},
|
|
|
|
},
|
|
|
|
"value_specs": &schema.Schema{
|
|
|
|
Type: schema.TypeMap,
|
|
|
|
Optional: true,
|
|
|
|
ForceNew: true,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
func resourceDNSZoneV2Create(d *schema.ResourceData, meta interface{}) error {
|
|
|
|
config := meta.(*Config)
|
|
|
|
dnsClient, err := config.dnsV2Client(GetRegion(d))
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("Error creating OpenStack DNS client: %s", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
mastersraw := d.Get("masters").(*schema.Set).List()
|
|
|
|
masters := make([]string, len(mastersraw))
|
|
|
|
for i, masterraw := range mastersraw {
|
|
|
|
masters[i] = masterraw.(string)
|
|
|
|
}
|
|
|
|
|
|
|
|
attrsraw := d.Get("attributes").(map[string]interface{})
|
|
|
|
attrs := make(map[string]string, len(attrsraw))
|
|
|
|
for k, v := range attrsraw {
|
|
|
|
attrs[k] = v.(string)
|
|
|
|
}
|
|
|
|
|
|
|
|
createOpts := ZoneCreateOpts{
|
|
|
|
zones.CreateOpts{
|
|
|
|
Name: d.Get("name").(string),
|
|
|
|
Type: d.Get("type").(string),
|
|
|
|
Attributes: attrs,
|
|
|
|
TTL: d.Get("ttl").(int),
|
|
|
|
Email: d.Get("email").(string),
|
|
|
|
Description: d.Get("description").(string),
|
|
|
|
Masters: masters,
|
|
|
|
},
|
|
|
|
MapValueSpecs(d),
|
|
|
|
}
|
|
|
|
|
|
|
|
log.Printf("[DEBUG] Create Options: %#v", createOpts)
|
|
|
|
n, err := zones.Create(dnsClient, createOpts).Extract()
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("Error creating OpenStack DNS zone: %s", err)
|
|
|
|
}
|
2017-05-22 00:39:52 +02:00
|
|
|
|
|
|
|
log.Printf("[DEBUG] Waiting for DNS Zone (%s) to become available", n.ID)
|
|
|
|
stateConf := &resource.StateChangeConf{
|
|
|
|
Target: []string{"ACTIVE"},
|
|
|
|
Pending: []string{"PENDING"},
|
|
|
|
Refresh: waitForDNSZone(dnsClient, n.ID),
|
|
|
|
Timeout: d.Timeout(schema.TimeoutCreate),
|
|
|
|
Delay: 5 * time.Second,
|
|
|
|
MinTimeout: 3 * time.Second,
|
|
|
|
}
|
|
|
|
|
|
|
|
_, err = stateConf.WaitForState()
|
2017-05-18 23:25:28 +02:00
|
|
|
|
|
|
|
d.SetId(n.ID)
|
|
|
|
|
2017-05-22 00:39:52 +02:00
|
|
|
log.Printf("[DEBUG] Created OpenStack DNS Zone %s: %#v", n.ID, n)
|
2017-05-18 23:25:28 +02:00
|
|
|
return resourceDNSZoneV2Read(d, meta)
|
|
|
|
}
|
|
|
|
|
|
|
|
func resourceDNSZoneV2Read(d *schema.ResourceData, meta interface{}) error {
|
|
|
|
config := meta.(*Config)
|
|
|
|
dnsClient, err := config.dnsV2Client(GetRegion(d))
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("Error creating OpenStack DNS client: %s", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
n, err := zones.Get(dnsClient, d.Id()).Extract()
|
|
|
|
if err != nil {
|
|
|
|
return CheckDeleted(d, err, "zone")
|
|
|
|
}
|
|
|
|
|
2017-05-22 00:39:52 +02:00
|
|
|
log.Printf("[DEBUG] Retrieved Zone %s: %#v", d.Id(), n)
|
2017-05-18 23:25:28 +02:00
|
|
|
|
|
|
|
d.Set("name", n.Name)
|
|
|
|
d.Set("email", n.Email)
|
|
|
|
d.Set("description", n.Description)
|
2017-05-22 00:39:52 +02:00
|
|
|
d.Set("ttl", n.TTL)
|
2017-05-18 23:25:28 +02:00
|
|
|
d.Set("type", n.Type)
|
|
|
|
d.Set("attributes", n.Attributes)
|
|
|
|
d.Set("masters", n.Masters)
|
|
|
|
d.Set("region", GetRegion(d))
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func resourceDNSZoneV2Update(d *schema.ResourceData, meta interface{}) error {
|
|
|
|
config := meta.(*Config)
|
|
|
|
dnsClient, err := config.dnsV2Client(GetRegion(d))
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("Error creating OpenStack DNS client: %s", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
var updateOpts zones.UpdateOpts
|
|
|
|
if d.HasChange("email") {
|
|
|
|
updateOpts.Email = d.Get("email").(string)
|
|
|
|
}
|
|
|
|
if d.HasChange("ttl") {
|
|
|
|
updateOpts.TTL = d.Get("ttl").(int)
|
|
|
|
}
|
|
|
|
if d.HasChange("masters") {
|
2017-05-25 06:58:44 +02:00
|
|
|
mastersraw := d.Get("masters").(*schema.Set).List()
|
|
|
|
masters := make([]string, len(mastersraw))
|
|
|
|
for i, masterraw := range mastersraw {
|
|
|
|
masters[i] = masterraw.(string)
|
|
|
|
}
|
|
|
|
updateOpts.Masters = masters
|
2017-05-18 23:25:28 +02:00
|
|
|
}
|
|
|
|
if d.HasChange("description") {
|
|
|
|
updateOpts.Description = d.Get("description").(string)
|
|
|
|
}
|
|
|
|
|
2017-05-22 00:39:52 +02:00
|
|
|
log.Printf("[DEBUG] Updating Zone %s with options: %#v", d.Id(), updateOpts)
|
2017-05-18 23:25:28 +02:00
|
|
|
|
|
|
|
_, err = zones.Update(dnsClient, d.Id(), updateOpts).Extract()
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("Error updating OpenStack DNS Zone: %s", err)
|
|
|
|
}
|
|
|
|
|
2017-05-22 00:39:52 +02:00
|
|
|
log.Printf("[DEBUG] Waiting for DNS Zone (%s) to update", d.Id())
|
|
|
|
stateConf := &resource.StateChangeConf{
|
|
|
|
Target: []string{"ACTIVE"},
|
|
|
|
Pending: []string{"PENDING"},
|
|
|
|
Refresh: waitForDNSZone(dnsClient, d.Id()),
|
|
|
|
Timeout: d.Timeout(schema.TimeoutUpdate),
|
|
|
|
Delay: 5 * time.Second,
|
|
|
|
MinTimeout: 3 * time.Second,
|
|
|
|
}
|
|
|
|
|
|
|
|
_, err = stateConf.WaitForState()
|
|
|
|
|
2017-05-18 23:25:28 +02:00
|
|
|
return resourceDNSZoneV2Read(d, meta)
|
|
|
|
}
|
|
|
|
|
|
|
|
func resourceDNSZoneV2Delete(d *schema.ResourceData, meta interface{}) error {
|
|
|
|
config := meta.(*Config)
|
|
|
|
dnsClient, err := config.dnsV2Client(GetRegion(d))
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("Error creating OpenStack DNS client: %s", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
_, err = zones.Delete(dnsClient, d.Id()).Extract()
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("Error deleting OpenStack DNS Zone: %s", err)
|
|
|
|
}
|
|
|
|
|
2017-05-22 00:39:52 +02:00
|
|
|
log.Printf("[DEBUG] Waiting for DNS Zone (%s) to become available", d.Id())
|
|
|
|
stateConf := &resource.StateChangeConf{
|
|
|
|
Target: []string{"DELETED"},
|
|
|
|
Pending: []string{"ACTIVE", "PENDING"},
|
|
|
|
Refresh: waitForDNSZone(dnsClient, d.Id()),
|
|
|
|
Timeout: d.Timeout(schema.TimeoutDelete),
|
|
|
|
Delay: 5 * time.Second,
|
|
|
|
MinTimeout: 3 * time.Second,
|
|
|
|
}
|
|
|
|
|
|
|
|
_, err = stateConf.WaitForState()
|
|
|
|
|
2017-05-18 23:25:28 +02:00
|
|
|
d.SetId("")
|
|
|
|
return nil
|
|
|
|
}
|
2017-05-22 00:39:52 +02:00
|
|
|
|
|
|
|
func resourceDNSZoneV2ValidType(v interface{}, k string) (ws []string, errors []error) {
|
|
|
|
value := v.(string)
|
|
|
|
validTypes := []string{
|
|
|
|
"PRIMARY",
|
|
|
|
"SECONDARY",
|
|
|
|
}
|
|
|
|
|
|
|
|
for _, v := range validTypes {
|
|
|
|
if value == v {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
err := fmt.Errorf("%s must be one of %s", k, validTypes)
|
|
|
|
errors = append(errors, err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
func waitForDNSZone(dnsClient *gophercloud.ServiceClient, zoneId string) resource.StateRefreshFunc {
|
|
|
|
return func() (interface{}, string, error) {
|
|
|
|
zone, err := zones.Get(dnsClient, zoneId).Extract()
|
|
|
|
if err != nil {
|
|
|
|
if _, ok := err.(gophercloud.ErrDefault404); ok {
|
|
|
|
return zone, "DELETED", nil
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil, "", err
|
|
|
|
}
|
|
|
|
|
|
|
|
log.Printf("[DEBUG] OpenStack DNS Zone (%s) current status: %s", zone.ID, zone.Status)
|
|
|
|
return zone, zone.Status, nil
|
|
|
|
}
|
|
|
|
}
|