provider/openstack: Add openstack_dns_zone_v2 resource

This commit is contained in:
jrperritt 2017-05-18 16:25:28 -05:00 committed by Joe Topjian
parent 986b9fcc53
commit 5792b9fe76
6 changed files with 399 additions and 0 deletions

View File

@ -152,6 +152,13 @@ func (c *Config) computeV2Client(region string) (*gophercloud.ServiceClient, err
}) })
} }
func (c *Config) dnsV2Client(region string) (*gophercloud.ServiceClient, error) {
return openstack.NewDNSV2(c.osClient, gophercloud.EndpointOpts{
Region: region,
Availability: c.getEndpointType(),
})
}
func (c *Config) imageV2Client(region string) (*gophercloud.ServiceClient, error) { func (c *Config) imageV2Client(region string) (*gophercloud.ServiceClient, error) {
return openstack.NewImageServiceV2(c.osClient, gophercloud.EndpointOpts{ return openstack.NewImageServiceV2(c.osClient, gophercloud.EndpointOpts{
Region: region, Region: region,

View File

@ -0,0 +1,28 @@
package openstack
import (
"testing"
"github.com/hashicorp/terraform/helper/resource"
)
func TestAccDNSV2Zone_importBasic(t *testing.T) {
resourceName := "openstack_dns_zone_v2.zone_1"
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheckDNSZoneV2(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckDNSV2ZoneDestroy,
Steps: []resource.TestStep{
resource.TestStep{
Config: testAccDNSV2Zone_basic,
},
resource.TestStep{
ResourceName: resourceName,
ImportState: true,
ImportStateVerify: true,
},
},
})
}

View File

@ -150,6 +150,7 @@ func Provider() terraform.ResourceProvider {
"openstack_compute_floatingip_v2": resourceComputeFloatingIPV2(), "openstack_compute_floatingip_v2": resourceComputeFloatingIPV2(),
"openstack_compute_floatingip_associate_v2": resourceComputeFloatingIPAssociateV2(), "openstack_compute_floatingip_associate_v2": resourceComputeFloatingIPAssociateV2(),
"openstack_compute_volume_attach_v2": resourceComputeVolumeAttachV2(), "openstack_compute_volume_attach_v2": resourceComputeVolumeAttachV2(),
"openstack_dns_zone_v2": resourceDNSZoneV2(),
"openstack_fw_firewall_v1": resourceFWFirewallV1(), "openstack_fw_firewall_v1": resourceFWFirewallV1(),
"openstack_fw_policy_v1": resourceFWPolicyV1(), "openstack_fw_policy_v1": resourceFWPolicyV1(),
"openstack_fw_rule_v1": resourceFWRuleV1(), "openstack_fw_rule_v1": resourceFWRuleV1(),

View File

@ -0,0 +1,195 @@
package openstack
import (
"fmt"
"log"
"strconv"
"time"
"github.com/gophercloud/gophercloud/openstack/dns/v2/zones"
"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),
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,
ForceNew: true,
},
"attributes": &schema.Schema{
Type: schema.TypeMap,
Optional: true,
ForceNew: true,
},
"ttl": &schema.Schema{
Type: schema.TypeInt,
Optional: 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("[INFO] Zone ID: %s", n.ID)
d.SetId(n.ID)
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", strconv.Itoa(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") {
updateOpts.Masters = d.Get("masters").([]string)
}
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)
}
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)
}
d.SetId("")
return nil
}

View File

@ -0,0 +1,145 @@
package openstack
import (
"fmt"
"os"
"testing"
"github.com/hashicorp/terraform/helper/resource"
"github.com/hashicorp/terraform/terraform"
"github.com/gophercloud/gophercloud/openstack/dns/v2/zones"
)
func TestAccDNSV2Zone_basic(t *testing.T) {
var zone zones.Zone
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheckDNSZoneV2(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckDNSV2ZoneDestroy,
Steps: []resource.TestStep{
resource.TestStep{
Config: testAccDNSV2Zone_basic,
Check: resource.ComposeTestCheckFunc(
testAccCheckDNSV2ZoneExists("openstack_dns_zone_v2.zone_1", &zone),
),
},
resource.TestStep{
Config: testAccDNSV2Zone_update,
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttr("openstack_dns_zone_v2.zone_1", "name", "example.com"),
resource.TestCheckResourceAttr("openstack_dns_zone_v2.zone_1", "email", "email2@example.com"),
resource.TestCheckResourceAttr("openstack_dns_zone_v2.zone_1", "ttl", "6000"),
),
},
},
})
}
func TestAccDNSV2Zone_timeout(t *testing.T) {
var zone zones.Zone
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheckDNSZoneV2(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckDNSV2ZoneDestroy,
Steps: []resource.TestStep{
resource.TestStep{
Config: testAccDNSV2Zone_timeout,
Check: resource.ComposeTestCheckFunc(
testAccCheckDNSV2ZoneExists("openstack_dns_zone_v2.zone_1", &zone),
),
},
},
})
}
func testAccCheckDNSV2ZoneDestroy(s *terraform.State) error {
config := testAccProvider.Meta().(*Config)
dnsClient, err := config.dnsV2Client(OS_REGION_NAME)
if err != nil {
return fmt.Errorf("Error creating OpenStack DNS client: %s", err)
}
for _, rs := range s.RootModule().Resources {
if rs.Type != "openstack_dns_zone_v2" {
continue
}
_, err := zones.Get(dnsClient, rs.Primary.ID).Extract()
if err == nil {
return fmt.Errorf("Zone still exists")
}
}
return nil
}
func testAccCheckDNSV2ZoneExists(n string, zone *zones.Zone) resource.TestCheckFunc {
return func(s *terraform.State) error {
rs, ok := s.RootModule().Resources[n]
if !ok {
return fmt.Errorf("Not found: %s", n)
}
if rs.Primary.ID == "" {
return fmt.Errorf("No ID is set")
}
config := testAccProvider.Meta().(*Config)
dnsClient, err := config.dnsV2Client(OS_REGION_NAME)
if err != nil {
return fmt.Errorf("Error creating OpenStack DNS client: %s", err)
}
found, err := zones.Get(dnsClient, rs.Primary.ID).Extract()
if err != nil {
return err
}
if found.ID != rs.Primary.ID {
return fmt.Errorf("Zone not found")
}
*zone = *found
return nil
}
}
func testAccPreCheckDNSZoneV2(t *testing.T) {
v := os.Getenv("OS_AUTH_URL")
if v == "" {
t.Fatal("OS_AUTH_URL must be set for acceptance tests")
}
}
const testAccDNSV2Zone_basic = `
resource "openstack_dns_zone_v2" "zone_1" {
name = "example.com."
email = "email1@example.com"
ttl = 3000
}
`
const testAccDNSV2Zone_update = `
resource "openstack_dns_zone_v2" "zone_1" {
name = "example.com."
email = "email2@example.com"
ttl = 6000
}
`
const testAccDNSV2Zone_timeout = `
resource "openstack_dns_zone_v2" "zone_1" {
name = "example.com."
email = "email@example.com"
ttl = 3000
timeouts {
create = "5m"
delete = "5m"
}
}
`

View File

@ -3,6 +3,7 @@ package openstack
import ( import (
"bytes" "bytes"
"encoding/json" "encoding/json"
"fmt"
"io" "io"
"io/ioutil" "io/ioutil"
"log" "log"
@ -11,6 +12,7 @@ import (
"github.com/gophercloud/gophercloud/openstack/compute/v2/extensions/keypairs" "github.com/gophercloud/gophercloud/openstack/compute/v2/extensions/keypairs"
"github.com/gophercloud/gophercloud/openstack/compute/v2/extensions/servergroups" "github.com/gophercloud/gophercloud/openstack/compute/v2/extensions/servergroups"
"github.com/gophercloud/gophercloud/openstack/dns/v2/zones"
"github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/fwaas/firewalls" "github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/fwaas/firewalls"
"github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/fwaas/policies" "github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/fwaas/policies"
"github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/fwaas/rules" "github.com/gophercloud/gophercloud/openstack/networking/v2/extensions/fwaas/rules"
@ -288,3 +290,24 @@ func (opts SubnetCreateOpts) ToSubnetCreateMap() (map[string]interface{}, error)
return b, nil return b, nil
} }
// ZoneCreateOpts represents the attributes used when creating a new DNS zone.
type ZoneCreateOpts struct {
zones.CreateOpts
ValueSpecs map[string]string `json:"value_specs,omitempty"`
}
// ToZoneCreateMap casts a CreateOpts struct to a map.
// It overrides zones.ToZoneCreateMap to add the ValueSpecs field.
func (opts ZoneCreateOpts) ToZoneCreateMap() (map[string]interface{}, error) {
b, err := BuildRequest(opts, "")
if err != nil {
return nil, err
}
if m, ok := b[""].(map[string]interface{}); ok {
return m, nil
}
return nil, fmt.Errorf("Expected map but got %T", b[""])
}