Merge pull request #4495 from hashicorp/plan3-fixing_heroku_organization_app_read
Heroku Organization App Improvements
This commit is contained in:
commit
b351524367
|
@ -9,13 +9,27 @@ import (
|
|||
"github.com/hashicorp/terraform/helper/schema"
|
||||
)
|
||||
|
||||
// herokuApplication is a value type used to hold the details of an
|
||||
// application. We use this for common storage of values needed for the
|
||||
// heroku.App and heroku.OrganizationApp types
|
||||
type herokuApplication struct {
|
||||
Name string
|
||||
Region string
|
||||
Stack string
|
||||
GitURL string
|
||||
WebURL string
|
||||
OrganizationName string
|
||||
Locked bool
|
||||
}
|
||||
|
||||
// type application is used to store all the details of a heroku app
|
||||
type application struct {
|
||||
Id string // Id of the resource
|
||||
|
||||
App *heroku.App // The heroku application
|
||||
App *herokuApplication // The heroku application
|
||||
Client *heroku.Service // Client to interact with the heroku API
|
||||
Vars map[string]string // The vars on the application
|
||||
Organization bool // is the application organization app
|
||||
}
|
||||
|
||||
// Updates the application to have the latest from remote
|
||||
|
@ -23,9 +37,37 @@ func (a *application) Update() error {
|
|||
var errs []error
|
||||
var err error
|
||||
|
||||
a.App, err = a.Client.AppInfo(a.Id)
|
||||
if !a.Organization {
|
||||
app, err := a.Client.AppInfo(a.Id)
|
||||
if err != nil {
|
||||
errs = append(errs, err)
|
||||
} else {
|
||||
a.App = &herokuApplication{}
|
||||
a.App.Name = app.Name
|
||||
a.App.Region = app.Region.Name
|
||||
a.App.Stack = app.Stack.Name
|
||||
a.App.GitURL = app.GitURL
|
||||
a.App.WebURL = app.WebURL
|
||||
}
|
||||
} else {
|
||||
app, err := a.Client.OrganizationAppInfo(a.Id)
|
||||
if err != nil {
|
||||
errs = append(errs, err)
|
||||
} else {
|
||||
// No inheritance between OrganizationApp and App is killing it :/
|
||||
a.App = &herokuApplication{}
|
||||
a.App.Name = app.Name
|
||||
a.App.Region = app.Region.Name
|
||||
a.App.Stack = app.Stack.Name
|
||||
a.App.GitURL = app.GitURL
|
||||
a.App.WebURL = app.WebURL
|
||||
if app.Organization != nil {
|
||||
a.App.OrganizationName = app.Organization.Name
|
||||
} else {
|
||||
log.Println("[DEBUG] Something is wrong - didn't get information about organization name, while the app is marked as being so")
|
||||
}
|
||||
a.App.Locked = app.Locked
|
||||
}
|
||||
}
|
||||
|
||||
a.Vars, err = retrieveConfigVars(a.Id, a.Client)
|
||||
|
@ -95,7 +137,6 @@ func resourceHerokuApp() *schema.Resource {
|
|||
},
|
||||
|
||||
"organization": &schema.Schema{
|
||||
Description: "Name of Organization to create application in. Leave blank for personal apps.",
|
||||
Type: schema.TypeList,
|
||||
Optional: true,
|
||||
ForceNew: true,
|
||||
|
@ -122,17 +163,17 @@ func resourceHerokuApp() *schema.Resource {
|
|||
}
|
||||
}
|
||||
|
||||
func switchHerokuAppCreate(d *schema.ResourceData, meta interface{}) error {
|
||||
orgCount := d.Get("organization.#").(int)
|
||||
if orgCount > 1 {
|
||||
return fmt.Errorf("Error Creating Heroku App: Only 1 Heroku Organization is permitted")
|
||||
func isOrganizationApp(d *schema.ResourceData) bool {
|
||||
v := d.Get("organization").([]interface{})
|
||||
return len(v) > 0 && v[0] != nil
|
||||
}
|
||||
|
||||
if _, ok := d.GetOk("organization.0.name"); ok {
|
||||
func switchHerokuAppCreate(d *schema.ResourceData, meta interface{}) error {
|
||||
if isOrganizationApp(d) {
|
||||
return resourceHerokuOrgAppCreate(d, meta)
|
||||
} else {
|
||||
return resourceHerokuAppCreate(d, meta)
|
||||
}
|
||||
|
||||
return resourceHerokuAppCreate(d, meta)
|
||||
}
|
||||
|
||||
func resourceHerokuAppCreate(d *schema.ResourceData, meta interface{}) error {
|
||||
|
@ -181,19 +222,25 @@ func resourceHerokuOrgAppCreate(d *schema.ResourceData, meta interface{}) error
|
|||
// Build up our creation options
|
||||
opts := heroku.OrganizationAppCreateOpts{}
|
||||
|
||||
if v := d.Get("organization.0.name"); v != nil {
|
||||
v := d.Get("organization").([]interface{})
|
||||
if len(v) > 1 {
|
||||
return fmt.Errorf("Error Creating Heroku App: Only 1 Heroku Organization is permitted")
|
||||
}
|
||||
orgDetails := v[0].(map[string]interface{})
|
||||
|
||||
if v := orgDetails["name"]; v != nil {
|
||||
vs := v.(string)
|
||||
log.Printf("[DEBUG] Organization name: %s", vs)
|
||||
opts.Organization = &vs
|
||||
}
|
||||
|
||||
if v := d.Get("organization.0.personal"); v != nil {
|
||||
if v := orgDetails["personal"]; v != nil {
|
||||
vs := v.(bool)
|
||||
log.Printf("[DEBUG] Organization Personal: %t", vs)
|
||||
opts.Personal = &vs
|
||||
}
|
||||
|
||||
if v := d.Get("organization.0.locked"); v != nil {
|
||||
if v := orgDetails["locked"]; v != nil {
|
||||
vs := v.(bool)
|
||||
log.Printf("[DEBUG] Organization locked: %t", vs)
|
||||
opts.Locked = &vs
|
||||
|
@ -236,13 +283,7 @@ func resourceHerokuOrgAppCreate(d *schema.ResourceData, meta interface{}) error
|
|||
|
||||
func resourceHerokuAppRead(d *schema.ResourceData, meta interface{}) error {
|
||||
client := meta.(*heroku.Service)
|
||||
app, err := resourceHerokuAppRetrieve(d.Id(), client)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Only set the config_vars that we have set in the configuration.
|
||||
// The "all_config_vars" field has all of them.
|
||||
configVars := make(map[string]string)
|
||||
care := make(map[string]struct{})
|
||||
for _, v := range d.Get("config_vars").([]interface{}) {
|
||||
|
@ -250,6 +291,16 @@ func resourceHerokuAppRead(d *schema.ResourceData, meta interface{}) error {
|
|||
care[k] = struct{}{}
|
||||
}
|
||||
}
|
||||
|
||||
organizationApp := isOrganizationApp(d)
|
||||
|
||||
// Only set the config_vars that we have set in the configuration.
|
||||
// The "all_config_vars" field has all of them.
|
||||
app, err := resourceHerokuAppRetrieve(d.Id(), organizationApp, client)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for k, v := range app.Vars {
|
||||
if _, ok := care[k]; ok {
|
||||
configVars[k] = v
|
||||
|
@ -261,12 +312,23 @@ func resourceHerokuAppRead(d *schema.ResourceData, meta interface{}) error {
|
|||
}
|
||||
|
||||
d.Set("name", app.App.Name)
|
||||
d.Set("stack", app.App.Stack.Name)
|
||||
d.Set("region", app.App.Region.Name)
|
||||
d.Set("stack", app.App.Stack)
|
||||
d.Set("region", app.App.Region)
|
||||
d.Set("git_url", app.App.GitURL)
|
||||
d.Set("web_url", app.App.WebURL)
|
||||
d.Set("config_vars", configVarsValue)
|
||||
d.Set("all_config_vars", app.Vars)
|
||||
if organizationApp {
|
||||
orgDetails := map[string]interface{}{
|
||||
"name": app.App.OrganizationName,
|
||||
"locked": app.App.Locked,
|
||||
"private": false,
|
||||
}
|
||||
err := d.Set("organization", []interface{}{orgDetails})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// We know that the hostname on heroku will be the name+herokuapp.com
|
||||
// You need this to do things like create DNS CNAME records
|
||||
|
@ -327,8 +389,8 @@ func resourceHerokuAppDelete(d *schema.ResourceData, meta interface{}) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
func resourceHerokuAppRetrieve(id string, client *heroku.Service) (*application, error) {
|
||||
app := application{Id: id, Client: client}
|
||||
func resourceHerokuAppRetrieve(id string, organization bool, client *heroku.Service) (*application, error) {
|
||||
app := application{Id: id, Client: client, Organization: organization}
|
||||
|
||||
err := app.Update()
|
||||
|
||||
|
|
|
@ -2,6 +2,7 @@ package heroku
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/cyberdelia/heroku-go/v3"
|
||||
|
@ -102,6 +103,31 @@ func TestAccHerokuApp_NukeVars(t *testing.T) {
|
|||
})
|
||||
}
|
||||
|
||||
func TestAccHerokuApp_Organization(t *testing.T) {
|
||||
var app heroku.OrganizationApp
|
||||
org := os.Getenv("HEROKU_ORGANIZATION")
|
||||
|
||||
resource.Test(t, resource.TestCase{
|
||||
PreCheck: func() {
|
||||
testAccPreCheck(t)
|
||||
if org == "" {
|
||||
t.Skip("HEROKU_ORGANIZATION is not set; skipping test.")
|
||||
}
|
||||
},
|
||||
Providers: testAccProviders,
|
||||
CheckDestroy: testAccCheckHerokuAppDestroy,
|
||||
Steps: []resource.TestStep{
|
||||
resource.TestStep{
|
||||
Config: fmt.Sprintf(testAccCheckHerokuAppConfig_organization, org),
|
||||
Check: resource.ComposeTestCheckFunc(
|
||||
testAccCheckHerokuAppExistsOrg("heroku_app.foobar", &app),
|
||||
testAccCheckHerokuAppAttributesOrg(&app, org),
|
||||
),
|
||||
},
|
||||
},
|
||||
})
|
||||
}
|
||||
|
||||
func testAccCheckHerokuAppDestroy(s *terraform.State) error {
|
||||
client := testAccProvider.Meta().(*heroku.Service)
|
||||
|
||||
|
@ -197,6 +223,39 @@ func testAccCheckHerokuAppAttributesNoVars(app *heroku.App) resource.TestCheckFu
|
|||
}
|
||||
}
|
||||
|
||||
func testAccCheckHerokuAppAttributesOrg(app *heroku.OrganizationApp, org string) resource.TestCheckFunc {
|
||||
return func(s *terraform.State) error {
|
||||
client := testAccProvider.Meta().(*heroku.Service)
|
||||
|
||||
if app.Region.Name != "us" {
|
||||
return fmt.Errorf("Bad region: %s", app.Region.Name)
|
||||
}
|
||||
|
||||
if app.Stack.Name != "cedar-14" {
|
||||
return fmt.Errorf("Bad stack: %s", app.Stack.Name)
|
||||
}
|
||||
|
||||
if app.Name != "terraform-test-app" {
|
||||
return fmt.Errorf("Bad name: %s", app.Name)
|
||||
}
|
||||
|
||||
if app.Organization == nil || app.Organization.Name != org {
|
||||
return fmt.Errorf("Bad org: %v", app.Organization)
|
||||
}
|
||||
|
||||
vars, err := client.ConfigVarInfo(app.Name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if vars["FOO"] != "bar" {
|
||||
return fmt.Errorf("Bad config vars: %v", vars)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
func testAccCheckHerokuAppExists(n string, app *heroku.App) resource.TestCheckFunc {
|
||||
return func(s *terraform.State) error {
|
||||
rs, ok := s.RootModule().Resources[n]
|
||||
|
@ -227,6 +286,36 @@ func testAccCheckHerokuAppExists(n string, app *heroku.App) resource.TestCheckFu
|
|||
}
|
||||
}
|
||||
|
||||
func testAccCheckHerokuAppExistsOrg(n string, app *heroku.OrganizationApp) 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 App Name is set")
|
||||
}
|
||||
|
||||
client := testAccProvider.Meta().(*heroku.Service)
|
||||
|
||||
foundApp, err := client.OrganizationAppInfo(rs.Primary.ID)
|
||||
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if foundApp.Name != rs.Primary.ID {
|
||||
return fmt.Errorf("App not found")
|
||||
}
|
||||
|
||||
*app = *foundApp
|
||||
|
||||
return nil
|
||||
}
|
||||
}
|
||||
|
||||
const testAccCheckHerokuAppConfig_basic = `
|
||||
resource "heroku_app" "foobar" {
|
||||
name = "terraform-test-app"
|
||||
|
@ -253,3 +342,17 @@ resource "heroku_app" "foobar" {
|
|||
name = "terraform-test-app"
|
||||
region = "us"
|
||||
}`
|
||||
|
||||
const testAccCheckHerokuAppConfig_organization = `
|
||||
resource "heroku_app" "foobar" {
|
||||
name = "terraform-test-app"
|
||||
region = "us"
|
||||
|
||||
organization {
|
||||
name = "%s"
|
||||
}
|
||||
|
||||
config_vars {
|
||||
FOO = "bar"
|
||||
}
|
||||
}`
|
||||
|
|
Loading…
Reference in New Issue