diff --git a/builtin/providers/heroku/provider.go b/builtin/providers/heroku/provider.go index 28445a2bb..7fe0e2dad 100644 --- a/builtin/providers/heroku/provider.go +++ b/builtin/providers/heroku/provider.go @@ -23,8 +23,9 @@ func Provider() *schema.Provider { }, ResourcesMap: map[string]*schema.Resource{ - "heroku_app": resourceHerokuApp(), - "heroku_addon": resourceHerokuAddon(), + "heroku_app": resourceHerokuApp(), + "heroku_addon": resourceHerokuAddon(), + "heroku_domain": resourceHerokuDomain(), }, ConfigureFunc: providerConfigure, diff --git a/builtin/providers/heroku/resource_heroku_domain.go b/builtin/providers/heroku/resource_heroku_domain.go new file mode 100644 index 000000000..56e2ee0f7 --- /dev/null +++ b/builtin/providers/heroku/resource_heroku_domain.go @@ -0,0 +1,86 @@ +package heroku + +import ( + "fmt" + "log" + + "github.com/bgentry/heroku-go" + "github.com/hashicorp/terraform/helper/schema" +) + +func resourceHerokuDomain() *schema.Resource { + return &schema.Resource{ + Create: resourceHerokuDomainCreate, + Read: resourceHerokuDomainRead, + Delete: resourceHerokuDomainDelete, + + Schema: map[string]*schema.Schema{ + "hostname": &schema.Schema{ + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + + "app": &schema.Schema{ + Type: schema.TypeString, + Required: true, + ForceNew: true, + }, + + "cname": &schema.Schema{ + Type: schema.TypeString, + Computed: true, + }, + }, + } +} + +func resourceHerokuDomainCreate(d *schema.ResourceData, meta interface{}) error { + client := meta.(*heroku.Client) + + app := d.Get("app").(string) + hostname := d.Get("hostname").(string) + + log.Printf("[DEBUG] Domain create configuration: %#v, %#v", app, hostname) + + do, err := client.DomainCreate(app, hostname) + if err != nil { + return err + } + + d.SetId(do.Id) + d.Set("hostname", do.Hostname) + d.Set("cname", fmt.Sprintf("%s.herokuapp.com", app)) + + log.Printf("[INFO] Domain ID: %s", d.Id()) + return nil +} + +func resourceHerokuDomainDelete(d *schema.ResourceData, meta interface{}) error { + client := meta.(*heroku.Client) + + log.Printf("[INFO] Deleting Domain: %s", d.Id()) + + // Destroy the domain + err := client.DomainDelete(d.Get("app").(string), d.Id()) + if err != nil { + return fmt.Errorf("Error deleting domain: %s", err) + } + + return nil +} + +func resourceHerokuDomainRead(d *schema.ResourceData, meta interface{}) error { + client := meta.(*heroku.Client) + + app := d.Get("app").(string) + do, err := client.DomainInfo(app, d.Id()) + if err != nil { + return fmt.Errorf("Error retrieving domain: %s", err) + } + + d.Set("hostname", do.Hostname) + d.Set("cname", fmt.Sprintf("%s.herokuapp.com", app)) + + return nil +} diff --git a/builtin/providers/heroku/resource_heroku_domain_test.go b/builtin/providers/heroku/resource_heroku_domain_test.go new file mode 100644 index 000000000..4b34b91ab --- /dev/null +++ b/builtin/providers/heroku/resource_heroku_domain_test.go @@ -0,0 +1,104 @@ +package heroku + +import ( + "fmt" + "testing" + + "github.com/bgentry/heroku-go" + "github.com/hashicorp/terraform/helper/resource" + "github.com/hashicorp/terraform/terraform" +) + +func TestAccHerokuDomain_Basic(t *testing.T) { + var domain heroku.Domain + + resource.Test(t, resource.TestCase{ + PreCheck: func() { testAccPreCheck(t) }, + Providers: testAccProviders, + CheckDestroy: testAccCheckHerokuDomainDestroy, + Steps: []resource.TestStep{ + resource.TestStep{ + Config: testAccCheckHerokuDomainConfig_basic, + Check: resource.ComposeTestCheckFunc( + testAccCheckHerokuDomainExists("heroku_domain.foobar", &domain), + testAccCheckHerokuDomainAttributes(&domain), + resource.TestCheckResourceAttr( + "heroku_domain.foobar", "hostname", "terraform.example.com"), + resource.TestCheckResourceAttr( + "heroku_domain.foobar", "app", "terraform-test-app"), + resource.TestCheckResourceAttr( + "heroku_domain.foobar", "cname", "terraform-test-app.herokuapp.com"), + ), + }, + }, + }) +} + +func testAccCheckHerokuDomainDestroy(s *terraform.State) error { + client := testAccProvider.Meta().(*heroku.Client) + + for _, rs := range s.Resources { + if rs.Type != "heroku_domain" { + continue + } + + _, err := client.DomainInfo(rs.Attributes["app"], rs.ID) + + if err == nil { + return fmt.Errorf("Domain still exists") + } + } + + return nil +} + +func testAccCheckHerokuDomainAttributes(Domain *heroku.Domain) resource.TestCheckFunc { + return func(s *terraform.State) error { + + if Domain.Hostname != "terraform.example.com" { + return fmt.Errorf("Bad hostname: %s", Domain.Hostname) + } + + return nil + } +} + +func testAccCheckHerokuDomainExists(n string, Domain *heroku.Domain) resource.TestCheckFunc { + return func(s *terraform.State) error { + rs, ok := s.Resources[n] + + if !ok { + return fmt.Errorf("Not found: %s", n) + } + + if rs.ID == "" { + return fmt.Errorf("No Domain ID is set") + } + + client := testAccProvider.Meta().(*heroku.Client) + + foundDomain, err := client.DomainInfo(rs.Attributes["app"], rs.ID) + + if err != nil { + return err + } + + if foundDomain.Id != rs.ID { + return fmt.Errorf("Domain not found") + } + + *Domain = *foundDomain + + return nil + } +} + +const testAccCheckHerokuDomainConfig_basic = ` +resource "heroku_app" "foobar" { + name = "terraform-test-app" +} + +resource "heroku_domain" "foobar" { + app = "${heroku_app.foobar.name}" + hostname = "terraform.example.com" +}`