package openstack import ( "fmt" "log" "time" "github.com/gophercloud/gophercloud" "github.com/gophercloud/gophercloud/openstack/dns/v2/zones" "github.com/hashicorp/terraform/helper/resource" "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), Update: schema.DefaultTimeout(10 * time.Minute), 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{ Type: schema.TypeString, Optional: true, Computed: true, ForceNew: true, ValidateFunc: resourceDNSZoneV2ValidType, }, "attributes": &schema.Schema{ Type: schema.TypeMap, Optional: true, ForceNew: true, }, "ttl": &schema.Schema{ Type: schema.TypeInt, Optional: true, Computed: true, 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) } 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() d.SetId(n.ID) log.Printf("[DEBUG] Created OpenStack DNS Zone %s: %#v", n.ID, n) 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") } log.Printf("[DEBUG] Retrieved Zone %s: %#v", d.Id(), n) d.Set("name", n.Name) d.Set("email", n.Email) d.Set("description", n.Description) d.Set("ttl", n.TTL) 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") { mastersraw := d.Get("masters").(*schema.Set).List() masters := make([]string, len(mastersraw)) for i, masterraw := range mastersraw { masters[i] = masterraw.(string) } updateOpts.Masters = masters } if d.HasChange("description") { updateOpts.Description = d.Get("description").(string) } log.Printf("[DEBUG] Updating Zone %s with options: %#v", d.Id(), updateOpts) _, err = zones.Update(dnsClient, d.Id(), updateOpts).Extract() if err != nil { return fmt.Errorf("Error updating OpenStack DNS Zone: %s", err) } 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() 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) } 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() d.SetId("") return nil } 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 } }