mirror of
https://github.com/letic/terraform-provider-google.git
synced 2024-10-03 01:01:06 +00:00
Support Google Cloud DNS, Fix #1148
This commit is contained in:
parent
bce21fe6ac
commit
6d763bacfd
27
config.go
27
config.go
@ -14,6 +14,7 @@ import (
|
||||
"golang.org/x/oauth2/google"
|
||||
"golang.org/x/oauth2/jwt"
|
||||
"google.golang.org/api/compute/v1"
|
||||
"google.golang.org/api/dns/v1"
|
||||
)
|
||||
|
||||
// Config is the configuration structure used to instantiate the Google
|
||||
@ -24,6 +25,7 @@ type Config struct {
|
||||
Region string
|
||||
|
||||
clientCompute *compute.Service
|
||||
clientDns *dns.Service
|
||||
}
|
||||
|
||||
func (c *Config) loadAndValidate() error {
|
||||
@ -50,7 +52,10 @@ func (c *Config) loadAndValidate() error {
|
||||
err)
|
||||
}
|
||||
|
||||
clientScopes := []string{"https://www.googleapis.com/auth/compute"}
|
||||
clientScopes := []string{
|
||||
"https://www.googleapis.com/auth/compute",
|
||||
"https://www.googleapis.com/auth/ndev.clouddns.readwrite",
|
||||
}
|
||||
|
||||
// Get the token for use in our requests
|
||||
log.Printf("[INFO] Requesting Google token...")
|
||||
@ -83,23 +88,31 @@ func (c *Config) loadAndValidate() error {
|
||||
|
||||
}
|
||||
|
||||
log.Printf("[INFO] Instantiating GCE client...")
|
||||
var err error
|
||||
c.clientCompute, err = compute.New(client)
|
||||
|
||||
// Set UserAgent
|
||||
// Build UserAgent
|
||||
versionString := "0.0.0"
|
||||
// TODO(dcunnin): Use Terraform's version code from version.go
|
||||
// versionString := main.Version
|
||||
// if main.VersionPrerelease != "" {
|
||||
// versionString = fmt.Sprintf("%s-%s", versionString, main.VersionPrerelease)
|
||||
// }
|
||||
c.clientCompute.UserAgent = fmt.Sprintf(
|
||||
userAgent := fmt.Sprintf(
|
||||
"(%s %s) Terraform/%s", runtime.GOOS, runtime.GOARCH, versionString)
|
||||
|
||||
var err error
|
||||
|
||||
log.Printf("[INFO] Instantiating GCE client...")
|
||||
c.clientCompute, err = compute.New(client)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
c.clientCompute.UserAgent = userAgent
|
||||
|
||||
log.Printf("[INFO] Instantiating Google Cloud DNS client...")
|
||||
c.clientDns, err = dns.New(client)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
c.clientDns.UserAgent = userAgent
|
||||
|
||||
return nil
|
||||
}
|
||||
|
38
dns_change.go
Normal file
38
dns_change.go
Normal file
@ -0,0 +1,38 @@
|
||||
package google
|
||||
|
||||
import (
|
||||
"google.golang.org/api/dns/v1"
|
||||
|
||||
"github.com/hashicorp/terraform/helper/resource"
|
||||
)
|
||||
|
||||
type DnsChangeWaiter struct {
|
||||
Service *dns.Service
|
||||
Change *dns.Change
|
||||
Project string
|
||||
ManagedZone string
|
||||
}
|
||||
|
||||
func (w *DnsChangeWaiter) RefreshFunc() resource.StateRefreshFunc {
|
||||
return func() (interface{}, string, error) {
|
||||
var chg *dns.Change
|
||||
var err error
|
||||
|
||||
chg, err = w.Service.Changes.Get(
|
||||
w.Project, w.ManagedZone, w.Change.Id).Do()
|
||||
|
||||
if err != nil {
|
||||
return nil, "", err
|
||||
}
|
||||
|
||||
return chg, chg.Status, nil
|
||||
}
|
||||
}
|
||||
|
||||
func (w *DnsChangeWaiter) Conf() *resource.StateChangeConf {
|
||||
return &resource.StateChangeConf{
|
||||
Pending: []string{"pending"},
|
||||
Target: "done",
|
||||
Refresh: w.RefreshFunc(),
|
||||
}
|
||||
}
|
@ -39,6 +39,8 @@ func Provider() terraform.ResourceProvider {
|
||||
"google_compute_network": resourceComputeNetwork(),
|
||||
"google_compute_route": resourceComputeRoute(),
|
||||
"google_compute_target_pool": resourceComputeTargetPool(),
|
||||
"google_dns_managed_zone": resourceDnsManagedZone(),
|
||||
"google_dns_record_set": resourceDnsRecordSet(),
|
||||
},
|
||||
|
||||
ConfigureFunc: providerConfigure,
|
||||
|
108
resource_dns_managed_zone.go
Normal file
108
resource_dns_managed_zone.go
Normal file
@ -0,0 +1,108 @@
|
||||
package google
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
|
||||
"github.com/hashicorp/terraform/helper/schema"
|
||||
"google.golang.org/api/dns/v1"
|
||||
"google.golang.org/api/googleapi"
|
||||
)
|
||||
|
||||
func resourceDnsManagedZone() *schema.Resource {
|
||||
return &schema.Resource{
|
||||
Create: resourceDnsManagedZoneCreate,
|
||||
Read: resourceDnsManagedZoneRead,
|
||||
Delete: resourceDnsManagedZoneDelete,
|
||||
|
||||
Schema: map[string]*schema.Schema{
|
||||
"name": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
ForceNew: true,
|
||||
},
|
||||
|
||||
"dns_name": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
ForceNew: true,
|
||||
},
|
||||
|
||||
"description": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Optional: true,
|
||||
ForceNew: true,
|
||||
},
|
||||
|
||||
"name_servers": &schema.Schema{
|
||||
Type: schema.TypeList,
|
||||
Computed: true,
|
||||
Elem: &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
},
|
||||
},
|
||||
|
||||
// Google Cloud DNS ManagedZone resources do not have a SelfLink attribute.
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func resourceDnsManagedZoneCreate(d *schema.ResourceData, meta interface{}) error {
|
||||
config := meta.(*Config)
|
||||
|
||||
// Build the parameter
|
||||
zone := &dns.ManagedZone{
|
||||
Name: d.Get("name").(string),
|
||||
DnsName: d.Get("dns_name").(string),
|
||||
}
|
||||
// Optional things
|
||||
if v, ok := d.GetOk("description"); ok {
|
||||
zone.Description = v.(string)
|
||||
}
|
||||
if v, ok := d.GetOk("dns_name"); ok {
|
||||
zone.DnsName = v.(string)
|
||||
}
|
||||
|
||||
log.Printf("[DEBUG] DNS ManagedZone create request: %#v", zone)
|
||||
zone, err := config.clientDns.ManagedZones.Create(config.Project, zone).Do()
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error creating DNS ManagedZone: %s", err)
|
||||
}
|
||||
|
||||
d.SetId(zone.Name)
|
||||
|
||||
return resourceDnsManagedZoneRead(d, meta)
|
||||
}
|
||||
|
||||
func resourceDnsManagedZoneRead(d *schema.ResourceData, meta interface{}) error {
|
||||
config := meta.(*Config)
|
||||
|
||||
zone, err := config.clientDns.ManagedZones.Get(
|
||||
config.Project, d.Id()).Do()
|
||||
if err != nil {
|
||||
if gerr, ok := err.(*googleapi.Error); ok && gerr.Code == 404 {
|
||||
// The resource doesn't exist anymore
|
||||
d.SetId("")
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
return fmt.Errorf("Error reading DNS ManagedZone: %#v", err)
|
||||
}
|
||||
|
||||
d.Set("name_servers", zone.NameServers)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func resourceDnsManagedZoneDelete(d *schema.ResourceData, meta interface{}) error {
|
||||
config := meta.(*Config)
|
||||
|
||||
err := config.clientDns.ManagedZones.Delete(config.Project, d.Id()).Do()
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error deleting DNS ManagedZone: %s", err)
|
||||
}
|
||||
|
||||
d.SetId("")
|
||||
return nil
|
||||
}
|
83
resource_dns_managed_zone_test.go
Normal file
83
resource_dns_managed_zone_test.go
Normal file
@ -0,0 +1,83 @@
|
||||
package google
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/hashicorp/terraform/helper/resource"
|
||||
"github.com/hashicorp/terraform/terraform"
|
||||
"google.golang.org/api/dns/v1"
|
||||
)
|
||||
|
||||
func TestAccDnsManagedZone_basic(t *testing.T) {
|
||||
var zone dns.ManagedZone
|
||||
|
||||
resource.Test(t, resource.TestCase{
|
||||
PreCheck: func() { testAccPreCheck(t) },
|
||||
Providers: testAccProviders,
|
||||
CheckDestroy: testAccCheckDnsManagedZoneDestroy,
|
||||
Steps: []resource.TestStep{
|
||||
resource.TestStep{
|
||||
Config: testAccDnsManagedZone_basic,
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
testAccCheckDnsManagedZoneExists(
|
||||
"google_dns_managed_zone.foobar", &zone),
|
||||
),
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func testAccCheckDnsManagedZoneDestroy(s *terraform.State) error {
|
||||
config := testAccProvider.Meta().(*Config)
|
||||
|
||||
for _, rs := range s.RootModule().Resources {
|
||||
if rs.Type != "google_dns_zone" {
|
||||
continue
|
||||
}
|
||||
|
||||
_, err := config.clientDns.ManagedZones.Get(
|
||||
config.Project, rs.Primary.ID).Do()
|
||||
if err == nil {
|
||||
return fmt.Errorf("DNS ManagedZone still exists")
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func testAccCheckDnsManagedZoneExists(n string, zone *dns.ManagedZone) 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)
|
||||
|
||||
found, err := config.clientDns.ManagedZones.Get(
|
||||
config.Project, rs.Primary.ID).Do()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if found.Name != rs.Primary.ID {
|
||||
return fmt.Errorf("DNS Zone not found")
|
||||
}
|
||||
|
||||
*zone = *found
|
||||
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
const testAccDnsManagedZone_basic = `
|
||||
resource "google_dns_managed_zone" "foobar" {
|
||||
name = "terraform-test"
|
||||
dns_name = "terraform.test."
|
||||
description = "Test Description"
|
||||
}`
|
182
resource_dns_record_set.go
Normal file
182
resource_dns_record_set.go
Normal file
@ -0,0 +1,182 @@
|
||||
package google
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"time"
|
||||
|
||||
"github.com/hashicorp/terraform/helper/schema"
|
||||
"google.golang.org/api/dns/v1"
|
||||
)
|
||||
|
||||
func resourceDnsRecordSet() *schema.Resource {
|
||||
return &schema.Resource{
|
||||
Create: resourceDnsRecordSetCreate,
|
||||
Read: resourceDnsRecordSetRead,
|
||||
Delete: resourceDnsRecordSetDelete,
|
||||
|
||||
Schema: map[string]*schema.Schema{
|
||||
"name": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
ForceNew: true,
|
||||
},
|
||||
|
||||
"managed_zone": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
ForceNew: true,
|
||||
},
|
||||
|
||||
"type": &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
Required: true,
|
||||
ForceNew: true,
|
||||
},
|
||||
|
||||
"ttl": &schema.Schema{
|
||||
Type: schema.TypeInt,
|
||||
Required: true,
|
||||
ForceNew: true,
|
||||
},
|
||||
|
||||
"rrdatas": &schema.Schema{
|
||||
Type: schema.TypeList,
|
||||
Required: true,
|
||||
ForceNew: true,
|
||||
Elem: &schema.Schema{
|
||||
Type: schema.TypeString,
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func resourceDnsRecordSetCreate(d *schema.ResourceData, meta interface{}) error {
|
||||
config := meta.(*Config)
|
||||
|
||||
zone := d.Get("managed_zone").(string)
|
||||
|
||||
rrdatasCount := d.Get("rrdatas.#").(int)
|
||||
|
||||
// Build the change
|
||||
chg := &dns.Change{
|
||||
Additions: []*dns.ResourceRecordSet {
|
||||
&dns.ResourceRecordSet {
|
||||
Name: d.Get("name").(string),
|
||||
Type: d.Get("type").(string),
|
||||
Ttl: int64(d.Get("ttl").(int)),
|
||||
Rrdatas: make([]string, rrdatasCount),
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for i := 0; i < rrdatasCount ; i++ {
|
||||
rrdata := fmt.Sprintf("rrdatas.%d", i)
|
||||
chg.Additions[0].Rrdatas[i] = d.Get(rrdata).(string)
|
||||
}
|
||||
|
||||
log.Printf("[DEBUG] DNS Record create request: %#v", chg)
|
||||
chg, err := config.clientDns.Changes.Create(config.Project, zone, chg).Do()
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error creating DNS RecordSet: %s", err)
|
||||
}
|
||||
|
||||
d.SetId(chg.Id)
|
||||
|
||||
w := &DnsChangeWaiter{
|
||||
Service: config.clientDns,
|
||||
Change: chg,
|
||||
Project: config.Project,
|
||||
ManagedZone: zone,
|
||||
}
|
||||
state := w.Conf()
|
||||
state.Delay = 10 * time.Second
|
||||
state.Timeout = 10 * time.Minute
|
||||
state.MinTimeout = 2 * time.Second
|
||||
_, err = state.WaitForState()
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error waiting for Google DNS change: %s", err)
|
||||
}
|
||||
|
||||
return resourceDnsRecordSetRead(d, meta)
|
||||
}
|
||||
|
||||
func resourceDnsRecordSetRead(d *schema.ResourceData, meta interface{}) error {
|
||||
config := meta.(*Config)
|
||||
|
||||
zone := d.Get("managed_zone").(string)
|
||||
|
||||
// name and type are effectively the 'key'
|
||||
name := d.Get("name").(string)
|
||||
dnsType := d.Get("type").(string)
|
||||
|
||||
resp, err := config.clientDns.ResourceRecordSets.List(
|
||||
config.Project, zone).Name(name).Type(dnsType).Do()
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error reading DNS RecordSet: %#v", err)
|
||||
}
|
||||
if len(resp.Rrsets) == 0 {
|
||||
// The resource doesn't exist anymore
|
||||
d.SetId("")
|
||||
return nil
|
||||
}
|
||||
|
||||
if len(resp.Rrsets) > 1 {
|
||||
return fmt.Errorf("Only expected 1 record set, got %d", len(resp.Rrsets))
|
||||
}
|
||||
|
||||
|
||||
d.Set("ttl", resp.Rrsets[0].Ttl)
|
||||
d.Set("rrdatas", resp.Rrsets[0].Rrdatas)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func resourceDnsRecordSetDelete(d *schema.ResourceData, meta interface{}) error {
|
||||
config := meta.(*Config)
|
||||
|
||||
zone := d.Get("managed_zone").(string)
|
||||
|
||||
rrdatasCount := d.Get("rrdatas.#").(int)
|
||||
|
||||
// Build the change
|
||||
chg := &dns.Change{
|
||||
Deletions: []*dns.ResourceRecordSet {
|
||||
&dns.ResourceRecordSet {
|
||||
Name: d.Get("name").(string),
|
||||
Type: d.Get("type").(string),
|
||||
Ttl: int64(d.Get("ttl").(int)),
|
||||
Rrdatas: make([]string, rrdatasCount),
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
for i := 0; i < rrdatasCount ; i++ {
|
||||
rrdata := fmt.Sprintf("rrdatas.%d", i)
|
||||
chg.Deletions[0].Rrdatas[i] = d.Get(rrdata).(string)
|
||||
}
|
||||
log.Printf("[DEBUG] DNS Record delete request: %#v", chg)
|
||||
chg, err := config.clientDns.Changes.Create(config.Project, zone, chg).Do()
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error deleting DNS RecordSet: %s", err)
|
||||
}
|
||||
|
||||
w := &DnsChangeWaiter{
|
||||
Service: config.clientDns,
|
||||
Change: chg,
|
||||
Project: config.Project,
|
||||
ManagedZone: zone,
|
||||
}
|
||||
state := w.Conf()
|
||||
state.Delay = 10 * time.Second
|
||||
state.Timeout = 10 * time.Minute
|
||||
state.MinTimeout = 2 * time.Second
|
||||
_, err = state.WaitForState()
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error waiting for Google DNS change: %s", err)
|
||||
}
|
||||
|
||||
d.SetId("")
|
||||
return nil
|
||||
}
|
92
resource_dns_record_set_test.go
Normal file
92
resource_dns_record_set_test.go
Normal file
@ -0,0 +1,92 @@
|
||||
package google
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/hashicorp/terraform/helper/resource"
|
||||
"github.com/hashicorp/terraform/terraform"
|
||||
)
|
||||
|
||||
func TestAccDnsRecordSet_basic(t *testing.T) {
|
||||
resource.Test(t, resource.TestCase{
|
||||
PreCheck: func() { testAccPreCheck(t) },
|
||||
Providers: testAccProviders,
|
||||
CheckDestroy: testAccCheckDnsRecordSetDestroy,
|
||||
Steps: []resource.TestStep{
|
||||
resource.TestStep{
|
||||
Config: testAccDnsRecordSet_basic,
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
testAccCheckDnsRecordSetExists(
|
||||
"google_dns_record_set.foobar"),
|
||||
),
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func testAccCheckDnsRecordSetDestroy(s *terraform.State) error {
|
||||
config := testAccProvider.Meta().(*Config)
|
||||
|
||||
for _, rs := range s.RootModule().Resources {
|
||||
// Deletion of the managed_zone implies everything is gone
|
||||
if rs.Type == "google_dns_managed_zone" {
|
||||
_, err := config.clientDns.ManagedZones.Get(
|
||||
config.Project, rs.Primary.ID).Do()
|
||||
if err == nil {
|
||||
return fmt.Errorf("DNS ManagedZone still exists")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func testAccCheckDnsRecordSetExists(name string) resource.TestCheckFunc {
|
||||
return func(s *terraform.State) error {
|
||||
rs, ok := s.RootModule().Resources[name]
|
||||
if !ok {
|
||||
return fmt.Errorf("Not found: %s", name)
|
||||
}
|
||||
|
||||
dnsName := rs.Primary.Attributes["name"]
|
||||
dnsType := rs.Primary.Attributes["type"]
|
||||
|
||||
if rs.Primary.ID == "" {
|
||||
return fmt.Errorf("No ID is set")
|
||||
}
|
||||
|
||||
config := testAccProvider.Meta().(*Config)
|
||||
|
||||
resp, err := config.clientDns.ResourceRecordSets.List(
|
||||
config.Project, "terraform-test-zone").Name(dnsName).Type(dnsType).Do()
|
||||
if err != nil {
|
||||
return fmt.Errorf("Error confirming DNS RecordSet existence: %#v", err)
|
||||
}
|
||||
if len(resp.Rrsets) == 0 {
|
||||
// The resource doesn't exist anymore
|
||||
return fmt.Errorf("DNS RecordSet not found")
|
||||
}
|
||||
|
||||
if len(resp.Rrsets) > 1 {
|
||||
return fmt.Errorf("Only expected 1 record set, got %d", len(resp.Rrsets))
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
const testAccDnsRecordSet_basic = `
|
||||
resource "google_dns_managed_zone" "parent-zone" {
|
||||
name = "terraform-test-zone"
|
||||
dns_name = "terraform.test."
|
||||
description = "Test Description"
|
||||
}
|
||||
resource "google_dns_record_set" "foobar" {
|
||||
managed_zone = "${google_dns_managed_zone.parent-zone.name}"
|
||||
name = "test-record.terraform.test."
|
||||
type = "A"
|
||||
rrdatas = ["127.0.0.1", "127.0.0.10"]
|
||||
ttl = 600
|
||||
}
|
||||
`
|
Loading…
Reference in New Issue
Block a user