From cdee8c70ecda241a113751068a3a1211a29871e3 Mon Sep 17 00:00:00 2001 From: Sander van Harmelen Date: Mon, 17 Nov 2014 14:01:00 +0100 Subject: [PATCH] Refactoring the DNSimple provider With this refactor the DNSimple provider is updated to use the schema.Provider approach released with TF 0.2. --- builtin/bins/provider-dnsimple/main.go | 5 +- builtin/providers/dnsimple/config.go | 14 +- builtin/providers/dnsimple/provider.go | 54 ++++ builtin/providers/dnsimple/provider_test.go | 43 +++ .../dnsimple/resource_dnsimple_record.go | 253 ++++++++---------- .../dnsimple/resource_dnsimple_record_test.go | 4 +- .../providers/dnsimple/resource_provider.go | 77 ------ .../dnsimple/resource_provider_test.go | 80 ------ builtin/providers/dnsimple/resources.go | 24 -- 9 files changed, 208 insertions(+), 346 deletions(-) create mode 100644 builtin/providers/dnsimple/provider.go create mode 100644 builtin/providers/dnsimple/provider_test.go delete mode 100644 builtin/providers/dnsimple/resource_provider.go delete mode 100644 builtin/providers/dnsimple/resource_provider_test.go delete mode 100644 builtin/providers/dnsimple/resources.go diff --git a/builtin/bins/provider-dnsimple/main.go b/builtin/bins/provider-dnsimple/main.go index 2c578ace2..96c5046c3 100644 --- a/builtin/bins/provider-dnsimple/main.go +++ b/builtin/bins/provider-dnsimple/main.go @@ -3,13 +3,10 @@ package main import ( "github.com/hashicorp/terraform/builtin/providers/dnsimple" "github.com/hashicorp/terraform/plugin" - "github.com/hashicorp/terraform/terraform" ) func main() { plugin.Serve(&plugin.ServeOpts{ - ProviderFunc: func() terraform.ResourceProvider { - return new(dnsimple.ResourceProvider) - }, + ProviderFunc: dnsimple.Provider, }) } diff --git a/builtin/providers/dnsimple/config.go b/builtin/providers/dnsimple/config.go index 6be132f2f..6501a7c9d 100644 --- a/builtin/providers/dnsimple/config.go +++ b/builtin/providers/dnsimple/config.go @@ -3,29 +3,17 @@ package dnsimple import ( "fmt" "log" - "os" "github.com/pearkes/dnsimple" ) type Config struct { - Token string `mapstructure:"token"` Email string `mapstructure:"email"` + Token string `mapstructure:"token"` } // Client() returns a new client for accessing dnsimple. -// func (c *Config) Client() (*dnsimple.Client, error) { - - // If we have env vars set (like in the acc) tests, - // we need to override the values passed in here. - if v := os.Getenv("DNSIMPLE_EMAIL"); v != "" { - c.Email = v - } - if v := os.Getenv("DNSIMPLE_TOKEN"); v != "" { - c.Token = v - } - client, err := dnsimple.NewClient(c.Email, c.Token) if err != nil { diff --git a/builtin/providers/dnsimple/provider.go b/builtin/providers/dnsimple/provider.go new file mode 100644 index 000000000..30b8b5976 --- /dev/null +++ b/builtin/providers/dnsimple/provider.go @@ -0,0 +1,54 @@ +package dnsimple + +import ( + "os" + + "github.com/hashicorp/terraform/helper/schema" + "github.com/hashicorp/terraform/terraform" +) + +// Provider returns a terraform.ResourceProvider. +func Provider() terraform.ResourceProvider { + return &schema.Provider{ + Schema: map[string]*schema.Schema{ + "email": &schema.Schema{ + Type: schema.TypeString, + Required: true, + DefaultFunc: envDefaultFunc("DNSIMPLE_EMAIL"), + Description: "A registered DNSimple email address.", + }, + + "token": &schema.Schema{ + Type: schema.TypeString, + Required: true, + DefaultFunc: envDefaultFunc("DNSIMPLE_TOKEN"), + Description: "The token key for API operations.", + }, + }, + + ResourcesMap: map[string]*schema.Resource{ + "dnsimple_record": resourceDNSimpleRecord(), + }, + + ConfigureFunc: providerConfigure, + } +} + +func envDefaultFunc(k string) schema.SchemaDefaultFunc { + return func() (interface{}, error) { + if v := os.Getenv(k); v != "" { + return v, nil + } + + return nil, nil + } +} + +func providerConfigure(d *schema.ResourceData) (interface{}, error) { + config := Config{ + Email: d.Get("email").(string), + Token: d.Get("token").(string), + } + + return config.Client() +} diff --git a/builtin/providers/dnsimple/provider_test.go b/builtin/providers/dnsimple/provider_test.go new file mode 100644 index 000000000..506efdc6f --- /dev/null +++ b/builtin/providers/dnsimple/provider_test.go @@ -0,0 +1,43 @@ +package dnsimple + +import ( + "os" + "testing" + + "github.com/hashicorp/terraform/helper/schema" + "github.com/hashicorp/terraform/terraform" +) + +var testAccProviders map[string]terraform.ResourceProvider +var testAccProvider *schema.Provider + +func init() { + testAccProvider = Provider().(*schema.Provider) + testAccProviders = map[string]terraform.ResourceProvider{ + "dnsimple": testAccProvider, + } +} + +func TestProvider(t *testing.T) { + if err := Provider().(*schema.Provider).InternalValidate(); err != nil { + t.Fatalf("err: %s", err) + } +} + +func TestProvider_impl(t *testing.T) { + var _ terraform.ResourceProvider = Provider() +} + +func testAccPreCheck(t *testing.T) { + if v := os.Getenv("DNSIMPLE_EMAIL"); v == "" { + t.Fatal("DNSIMPLE_EMAIL must be set for acceptance tests") + } + + if v := os.Getenv("DNSIMPLE_TOKEN"); v == "" { + t.Fatal("DNSIMPLE_TOKEN must be set for acceptance tests") + } + + if v := os.Getenv("DNSIMPLE_DOMAIN"); v == "" { + t.Fatal("DNSIMPLE_DOMAIN must be set for acceptance tests. The domain is used to ` and destroy record against.") + } +} diff --git a/builtin/providers/dnsimple/resource_dnsimple_record.go b/builtin/providers/dnsimple/resource_dnsimple_record.go index 36b0a058a..e3669c3c3 100644 --- a/builtin/providers/dnsimple/resource_dnsimple_record.go +++ b/builtin/providers/dnsimple/resource_dnsimple_record.go @@ -4,104 +4,150 @@ import ( "fmt" "log" - "github.com/hashicorp/terraform/helper/config" - "github.com/hashicorp/terraform/helper/diff" - "github.com/hashicorp/terraform/terraform" + "github.com/hashicorp/terraform/helper/schema" "github.com/pearkes/dnsimple" ) -func resource_dnsimple_record_create( - s *terraform.InstanceState, - d *terraform.InstanceDiff, - meta interface{}) (*terraform.InstanceState, error) { - p := meta.(*ResourceProvider) - client := p.client +func resourceDNSimpleRecord() *schema.Resource { + return &schema.Resource{ + Create: resourceDNSimpleRecordCreate, + Read: resourceDNSimpleRecordRead, + Update: resourceDNSimpleRecordUpdate, + Delete: resourceDNSimpleRecordDelete, - // Merge the diff into the state so that we have all the attributes - // properly. - rs := s.MergeDiff(d) + Schema: map[string]*schema.Schema{ + "domain": &schema.Schema{ + Type: schema.TypeString, + Required: true, + }, - var err error + "domain_id": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + }, - newRecord := dnsimple.ChangeRecord{ - Name: rs.Attributes["name"], - Value: rs.Attributes["value"], - Type: rs.Attributes["type"], + "name": &schema.Schema{ + Type: schema.TypeString, + Required: true, + }, + + "hostname": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + }, + + "type": &schema.Schema{ + Type: schema.TypeString, + Required: true, + }, + + "value": &schema.Schema{ + Type: schema.TypeString, + Required: true, + }, + + "ttl": &schema.Schema{ + Type: schema.TypeString, + Optional: true, + }, + + "priority": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + }, + }, + } +} + +func resourceDNSimpleRecordCreate(d *schema.ResourceData, meta interface{}) error { + client := meta.(*dnsimple.Client) + + // Create the new record + newRecord := &dnsimple.ChangeRecord{ + Name: d.Get("name").(string), + Type: d.Get("type").(string), + Value: d.Get("value").(string), } - if attr, ok := rs.Attributes["ttl"]; ok { - newRecord.Ttl = attr + if ttl, ok := d.GetOk("ttl"); ok { + newRecord.Ttl = ttl.(string) } log.Printf("[DEBUG] record create configuration: %#v", newRecord) - recId, err := client.CreateRecord(rs.Attributes["domain"], &newRecord) + recId, err := client.CreateRecord(d.Get("domain").(string), newRecord) if err != nil { - return nil, fmt.Errorf("Failed to create record: %s", err) + return fmt.Errorf("Failed to create record: %s", err) } - rs.ID = recId - log.Printf("[INFO] record ID: %s", rs.ID) + d.SetId(recId) + log.Printf("[INFO] record ID: %s", d.Id()) - record, err := resource_dnsimple_record_retrieve(rs.Attributes["domain"], rs.ID, client) - if err != nil { - return nil, fmt.Errorf("Couldn't find record: %s", err) - } - - return resource_dnsimple_record_update_state(rs, record) + return resourceDNSimpleRecordRead(d, meta) } -func resource_dnsimple_record_update( - s *terraform.InstanceState, - d *terraform.InstanceDiff, - meta interface{}) (*terraform.InstanceState, error) { - p := meta.(*ResourceProvider) - client := p.client - rs := s.MergeDiff(d) +func resourceDNSimpleRecordRead(d *schema.ResourceData, meta interface{}) error { + client := meta.(*dnsimple.Client) - updateRecord := dnsimple.ChangeRecord{} - - if attr, ok := d.Attributes["name"]; ok { - updateRecord.Name = attr.New + rec, err := client.RetrieveRecord(d.Get("domain").(string), d.Id()) + if err != nil { + return fmt.Errorf("Couldn't find record: %s", err) } - if attr, ok := d.Attributes["value"]; ok { - updateRecord.Value = attr.New + d.Set("domain_id", rec.StringDomainId()) + d.Set("name", rec.Name) + d.Set("type", rec.RecordType) + d.Set("value", rec.Content) + d.Set("ttl", rec.StringTtl()) + d.Set("priority", rec.StringPrio()) + + if rec.Name == "" { + d.Set("hostname", d.Get("domain").(string)) + } else { + d.Set("hostname", fmt.Sprintf("%s.%s", rec.Name, d.Get("domain").(string))) } - if attr, ok := d.Attributes["type"]; ok { - updateRecord.Type = attr.New + return nil +} + +func resourceDNSimpleRecordUpdate(d *schema.ResourceData, meta interface{}) error { + client := meta.(*dnsimple.Client) + + updateRecord := &dnsimple.ChangeRecord{} + + if attr, ok := d.GetOk("name"); ok { + updateRecord.Name = attr.(string) } - if attr, ok := d.Attributes["ttl"]; ok { - updateRecord.Ttl = attr.New + if attr, ok := d.GetOk("type"); ok { + updateRecord.Type = attr.(string) + } + + if attr, ok := d.GetOk("value"); ok { + updateRecord.Value = attr.(string) + } + + if attr, ok := d.GetOk("ttl"); ok { + updateRecord.Ttl = attr.(string) } log.Printf("[DEBUG] record update configuration: %#v", updateRecord) - _, err := client.UpdateRecord(rs.Attributes["domain"], rs.ID, &updateRecord) + _, err := client.UpdateRecord(d.Get("domain").(string), d.Id(), updateRecord) if err != nil { - return rs, fmt.Errorf("Failed to update record: %s", err) + return fmt.Errorf("Failed to update record: %s", err) } - record, err := resource_dnsimple_record_retrieve(rs.Attributes["domain"], rs.ID, client) - if err != nil { - return rs, fmt.Errorf("Couldn't find record: %s", err) - } - - return resource_dnsimple_record_update_state(rs, record) + return resourceDNSimpleRecordRead(d, meta) } -func resource_dnsimple_record_destroy( - s *terraform.InstanceState, - meta interface{}) error { - p := meta.(*ResourceProvider) - client := p.client +func resourceDNSimpleRecordDelete(d *schema.ResourceData, meta interface{}) error { + client := meta.(*dnsimple.Client) - log.Printf("[INFO] Deleting record: %s, %s", s.Attributes["domain"], s.ID) + log.Printf("[INFO] Deleting record: %s, %s", d.Get("domain").(string), d.Id()) - err := client.DestroyRecord(s.Attributes["domain"], s.ID) + err := client.DestroyRecord(d.Get("domain").(string), d.Id()) if err != nil { return fmt.Errorf("Error deleting record: %s", err) @@ -109,88 +155,3 @@ func resource_dnsimple_record_destroy( return nil } - -func resource_dnsimple_record_refresh( - s *terraform.InstanceState, - meta interface{}) (*terraform.InstanceState, error) { - p := meta.(*ResourceProvider) - client := p.client - - rec, err := resource_dnsimple_record_retrieve(s.Attributes["domain"], s.ID, client) - if err != nil { - return nil, err - } - - return resource_dnsimple_record_update_state(s, rec) -} - -func resource_dnsimple_record_diff( - s *terraform.InstanceState, - c *terraform.ResourceConfig, - meta interface{}) (*terraform.InstanceDiff, error) { - - b := &diff.ResourceBuilder{ - Attrs: map[string]diff.AttrType{ - "domain": diff.AttrTypeCreate, - "name": diff.AttrTypeUpdate, - "value": diff.AttrTypeUpdate, - "ttl": diff.AttrTypeUpdate, - "type": diff.AttrTypeUpdate, - }, - - ComputedAttrs: []string{ - "priority", - "domain_id", - "ttl", - }, - - ComputedAttrsUpdate: []string{ - "hostname", - }, - } - - return b.Diff(s, c) -} - -func resource_dnsimple_record_update_state( - s *terraform.InstanceState, - rec *dnsimple.Record) (*terraform.InstanceState, error) { - - s.Attributes["name"] = rec.Name - s.Attributes["value"] = rec.Content - s.Attributes["type"] = rec.RecordType - s.Attributes["ttl"] = rec.StringTtl() - s.Attributes["priority"] = rec.StringPrio() - s.Attributes["domain_id"] = rec.StringDomainId() - - if rec.Name == "" { - s.Attributes["hostname"] = s.Attributes["domain"] - } else { - s.Attributes["hostname"] = fmt.Sprintf("%s.%s", rec.Name, s.Attributes["domain"]) - } - - return s, nil -} - -func resource_dnsimple_record_retrieve(domain string, id string, client *dnsimple.Client) (*dnsimple.Record, error) { - record, err := client.RetrieveRecord(domain, id) - if err != nil { - return nil, err - } - - return record, nil -} - -func resource_dnsimple_record_validation() *config.Validator { - return &config.Validator{ - Required: []string{ - "domain", - "name", - "value", - "type", - }, - Optional: []string{ - "ttl", - }, - } -} diff --git a/builtin/providers/dnsimple/resource_dnsimple_record_test.go b/builtin/providers/dnsimple/resource_dnsimple_record_test.go index 78d825a0a..a07792a54 100644 --- a/builtin/providers/dnsimple/resource_dnsimple_record_test.go +++ b/builtin/providers/dnsimple/resource_dnsimple_record_test.go @@ -76,7 +76,7 @@ func TestAccDNSimpleRecord_Updated(t *testing.T) { } func testAccCheckDNSimpleRecordDestroy(s *terraform.State) error { - client := testAccProvider.client + client := testAccProvider.Meta().(*dnsimple.Client) for _, rs := range s.RootModule().Resources { if rs.Type != "dnsimple_record" { @@ -127,7 +127,7 @@ func testAccCheckDNSimpleRecordExists(n string, record *dnsimple.Record) resourc return fmt.Errorf("No Record ID is set") } - client := testAccProvider.client + client := testAccProvider.Meta().(*dnsimple.Client) foundRecord, err := client.RetrieveRecord(rs.Primary.Attributes["domain"], rs.Primary.ID) diff --git a/builtin/providers/dnsimple/resource_provider.go b/builtin/providers/dnsimple/resource_provider.go deleted file mode 100644 index a9d0f3159..000000000 --- a/builtin/providers/dnsimple/resource_provider.go +++ /dev/null @@ -1,77 +0,0 @@ -package dnsimple - -import ( - "log" - - "github.com/hashicorp/terraform/helper/config" - "github.com/hashicorp/terraform/terraform" - "github.com/pearkes/dnsimple" -) - -type ResourceProvider struct { - Config Config - - client *dnsimple.Client -} - -func (p *ResourceProvider) Input( - input terraform.UIInput, - c *terraform.ResourceConfig) (*terraform.ResourceConfig, error) { - return c, nil -} - -func (p *ResourceProvider) Validate(c *terraform.ResourceConfig) ([]string, []error) { - v := &config.Validator{ - Required: []string{ - "token", - "email", - }, - } - - return v.Validate(c) -} - -func (p *ResourceProvider) ValidateResource( - t string, c *terraform.ResourceConfig) ([]string, []error) { - return resourceMap.Validate(t, c) -} - -func (p *ResourceProvider) Configure(c *terraform.ResourceConfig) error { - if _, err := config.Decode(&p.Config, c.Config); err != nil { - return err - } - - log.Println("[INFO] Initializing DNSimple client") - var err error - p.client, err = p.Config.Client() - - if err != nil { - return err - } - - return nil -} - -func (p *ResourceProvider) Apply( - info *terraform.InstanceInfo, - s *terraform.InstanceState, - d *terraform.InstanceDiff) (*terraform.InstanceState, error) { - return resourceMap.Apply(info, s, d, p) -} - -func (p *ResourceProvider) Diff( - info *terraform.InstanceInfo, - s *terraform.InstanceState, - c *terraform.ResourceConfig) (*terraform.InstanceDiff, error) { - return resourceMap.Diff(info, s, c, p) -} - -func (p *ResourceProvider) Refresh( - info *terraform.InstanceInfo, - s *terraform.InstanceState) (*terraform.InstanceState, error) { - return resourceMap.Refresh(info, s, p) -} - -func (p *ResourceProvider) Resources() []terraform.ResourceType { - return resourceMap.Resources() -} diff --git a/builtin/providers/dnsimple/resource_provider_test.go b/builtin/providers/dnsimple/resource_provider_test.go deleted file mode 100644 index 4867c1ebd..000000000 --- a/builtin/providers/dnsimple/resource_provider_test.go +++ /dev/null @@ -1,80 +0,0 @@ -package dnsimple - -import ( - "os" - "reflect" - "testing" - - "github.com/hashicorp/terraform/config" - "github.com/hashicorp/terraform/terraform" -) - -var testAccProviders map[string]terraform.ResourceProvider -var testAccProvider *ResourceProvider - -func init() { - testAccProvider = new(ResourceProvider) - testAccProviders = map[string]terraform.ResourceProvider{ - "dnsimple": testAccProvider, - } -} - -func TestResourceProvider_impl(t *testing.T) { - var _ terraform.ResourceProvider = new(ResourceProvider) -} - -func TestResourceProvider_Configure(t *testing.T) { - rp := new(ResourceProvider) - var expectedToken string - var expectedEmail string - - if v := os.Getenv("DNSIMPLE_EMAIL"); v != "" { - expectedEmail = v - } else { - expectedEmail = "foo" - } - - if v := os.Getenv("DNSIMPLE_TOKEN"); v != "" { - expectedToken = v - } else { - expectedToken = "foo" - } - - raw := map[string]interface{}{ - "token": expectedToken, - "email": expectedEmail, - } - - rawConfig, err := config.NewRawConfig(raw) - if err != nil { - t.Fatalf("err: %s", err) - } - - err = rp.Configure(terraform.NewResourceConfig(rawConfig)) - if err != nil { - t.Fatalf("err: %s", err) - } - - expected := Config{ - Token: expectedToken, - Email: expectedEmail, - } - - if !reflect.DeepEqual(rp.Config, expected) { - t.Fatalf("bad: %#v", rp.Config) - } -} - -func testAccPreCheck(t *testing.T) { - if v := os.Getenv("DNSIMPLE_EMAIL"); v == "" { - t.Fatal("DNSIMPLE_EMAIL must be set for acceptance tests") - } - - if v := os.Getenv("DNSIMPLE_TOKEN"); v == "" { - t.Fatal("DNSIMPLE_TOKEN must be set for acceptance tests") - } - - if v := os.Getenv("DNSIMPLE_DOMAIN"); v == "" { - t.Fatal("DNSIMPLE_DOMAIN must be set for acceptance tests. The domain is used to ` and destroy record against.") - } -} diff --git a/builtin/providers/dnsimple/resources.go b/builtin/providers/dnsimple/resources.go deleted file mode 100644 index 7cbd5db91..000000000 --- a/builtin/providers/dnsimple/resources.go +++ /dev/null @@ -1,24 +0,0 @@ -package dnsimple - -import ( - "github.com/hashicorp/terraform/helper/resource" -) - -// resourceMap is the mapping of resources we support to their basic -// operations. This makes it easy to implement new resource types. -var resourceMap *resource.Map - -func init() { - resourceMap = &resource.Map{ - Mapping: map[string]resource.Resource{ - "dnsimple_record": resource.Resource{ - ConfigValidator: resource_dnsimple_record_validation(), - Create: resource_dnsimple_record_create, - Destroy: resource_dnsimple_record_destroy, - Diff: resource_dnsimple_record_diff, - Update: resource_dnsimple_record_update, - Refresh: resource_dnsimple_record_refresh, - }, - }, - } -}