diff --git a/builtin/providers/heroku/resource_heroku_addon_test.go b/builtin/providers/heroku/resource_heroku_addon_test.go index 610360073..1c099b683 100644 --- a/builtin/providers/heroku/resource_heroku_addon_test.go +++ b/builtin/providers/heroku/resource_heroku_addon_test.go @@ -38,7 +38,7 @@ func testAccCheckHerokuAddonDestroy(s *terraform.State) error { client := testAccProvider.client for _, rs := range s.Resources { - if rs.Type != "heroku_app" { + if rs.Type != "heroku_addon" { continue } diff --git a/builtin/providers/heroku/resource_heroku_app.go b/builtin/providers/heroku/resource_heroku_app.go index 755dae711..5c88cded8 100644 --- a/builtin/providers/heroku/resource_heroku_app.go +++ b/builtin/providers/heroku/resource_heroku_app.go @@ -218,6 +218,10 @@ func resource_heroku_app_update_state( s.Attributes["git_url"] = app.App.GitURL s.Attributes["web_url"] = app.App.WebURL + // We know that the hostname on heroku will be the name+herokuapp.com + // You need this to do things like create DNS CNAME records + s.Attributes["heroku_hostname"] = fmt.Sprintf("%s.herokuapp.com", app.App.Name) + toFlatten := make(map[string]interface{}) if len(app.Vars) > 0 { diff --git a/builtin/providers/heroku/resource_heroku_domain.go b/builtin/providers/heroku/resource_heroku_domain.go new file mode 100644 index 000000000..1dcb3cc2c --- /dev/null +++ b/builtin/providers/heroku/resource_heroku_domain.go @@ -0,0 +1,122 @@ +package heroku + +import ( + "fmt" + "log" + + "github.com/bgentry/heroku-go" + "github.com/hashicorp/terraform/helper/config" + "github.com/hashicorp/terraform/helper/diff" + "github.com/hashicorp/terraform/terraform" +) + +func resource_heroku_domain_create( + s *terraform.ResourceState, + d *terraform.ResourceDiff, + meta interface{}) (*terraform.ResourceState, error) { + p := meta.(*ResourceProvider) + client := p.client + + // Merge the diff into the state so that we have all the attributes + // properly. + rs := s.MergeDiff(d) + + app := rs.Attributes["app"] + hostname := rs.Attributes["hostname"] + + log.Printf("[DEBUG] Domain create configuration: %#v, %#v", app, hostname) + + do, err := client.DomainCreate(app, hostname) + + if err != nil { + return s, err + } + + rs.ID = do.Id + rs.Attributes["hostname"] = do.Hostname + + log.Printf("[INFO] Domain ID: %s", rs.ID) + + return rs, nil +} + +func resource_heroku_domain_update( + s *terraform.ResourceState, + d *terraform.ResourceDiff, + meta interface{}) (*terraform.ResourceState, error) { + + panic("Cannot update domain") + + return nil, nil +} + +func resource_heroku_domain_destroy( + s *terraform.ResourceState, + meta interface{}) error { + p := meta.(*ResourceProvider) + client := p.client + + log.Printf("[INFO] Deleting Domain: %s", s.ID) + + // Destroy the app + err := client.DomainDelete(s.Attributes["app"], s.ID) + + if err != nil { + return fmt.Errorf("Error deleting domain: %s", err) + } + + return nil +} + +func resource_heroku_domain_refresh( + s *terraform.ResourceState, + meta interface{}) (*terraform.ResourceState, error) { + p := meta.(*ResourceProvider) + client := p.client + + domain, err := resource_heroku_domain_retrieve(s.Attributes["app"], s.ID, client) + if err != nil { + return nil, err + } + + s.Attributes["hostname"] = domain.Hostname + + return s, nil +} + +func resource_heroku_domain_diff( + s *terraform.ResourceState, + c *terraform.ResourceConfig, + meta interface{}) (*terraform.ResourceDiff, error) { + + b := &diff.ResourceBuilder{ + Attrs: map[string]diff.AttrType{ + "hostname": diff.AttrTypeCreate, + "app": diff.AttrTypeCreate, + }, + + ComputedAttrs: []string{}, + } + + return b.Diff(s, c) +} + +func resource_heroku_domain_retrieve(app string, id string, client *heroku.Client) (*heroku.Domain, error) { + domain, err := client.DomainInfo(app, id) + + if err != nil { + return nil, fmt.Errorf("Error retrieving domain: %s", err) + } + + return domain, nil +} + +func resource_heroku_domain_validation() *config.Validator { + return &config.Validator{ + Required: []string{ + "hostname", + "app", + }, + Optional: []string{}, + } +} 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..87e2439de --- /dev/null +++ b/builtin/providers/heroku/resource_heroku_domain_test.go @@ -0,0 +1,102 @@ +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"), + ), + }, + }, + }) +} + +func testAccCheckHerokuDomainDestroy(s *terraform.State) error { + client := testAccProvider.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.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" +}` diff --git a/builtin/providers/heroku/resources.go b/builtin/providers/heroku/resources.go index 5712dba08..a208714c6 100644 --- a/builtin/providers/heroku/resources.go +++ b/builtin/providers/heroku/resources.go @@ -28,6 +28,14 @@ func init() { Refresh: resource_heroku_app_refresh, Update: resource_heroku_app_update, }, + + "heroku_domain": resource.Resource{ + ConfigValidator: resource_heroku_domain_validation(), + Create: resource_heroku_domain_create, + Destroy: resource_heroku_domain_destroy, + Diff: resource_heroku_domain_diff, + Refresh: resource_heroku_domain_refresh, + }, }, } }