2014-07-23 06:03:30 +02:00
|
|
|
package heroku
|
|
|
|
|
|
|
|
import (
|
2017-03-10 13:00:03 +01:00
|
|
|
"context"
|
2014-07-23 06:03:30 +02:00
|
|
|
"fmt"
|
|
|
|
"log"
|
|
|
|
|
2014-08-27 16:50:37 +02:00
|
|
|
"github.com/cyberdelia/heroku-go/v3"
|
2017-03-10 13:00:03 +01:00
|
|
|
multierror "github.com/hashicorp/go-multierror"
|
2014-08-18 18:32:40 +02:00
|
|
|
"github.com/hashicorp/terraform/helper/schema"
|
2014-07-23 06:03:30 +02:00
|
|
|
)
|
|
|
|
|
2016-01-04 19:46:52 +01:00
|
|
|
// 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
|
2014-12-14 18:54:01 +01:00
|
|
|
type herokuApplication struct {
|
|
|
|
Name string
|
|
|
|
Region string
|
|
|
|
Stack string
|
|
|
|
GitURL string
|
|
|
|
WebURL string
|
|
|
|
OrganizationName string
|
|
|
|
Locked bool
|
|
|
|
}
|
|
|
|
|
2014-07-23 18:09:27 +02:00
|
|
|
// type application is used to store all the details of a heroku app
|
|
|
|
type application struct {
|
|
|
|
Id string // Id of the resource
|
|
|
|
|
2014-12-14 18:54:01 +01:00
|
|
|
App *herokuApplication // The heroku application
|
|
|
|
Client *heroku.Service // Client to interact with the heroku API
|
|
|
|
Vars map[string]string // The vars on the application
|
2017-04-24 20:29:28 +02:00
|
|
|
Buildpacks []string // The application's buildpack names or URLs
|
2014-12-14 18:54:01 +01:00
|
|
|
Organization bool // is the application organization app
|
2014-07-23 18:09:27 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// Updates the application to have the latest from remote
|
|
|
|
func (a *application) Update() error {
|
|
|
|
var errs []error
|
|
|
|
var err error
|
|
|
|
|
2014-12-14 18:54:01 +01:00
|
|
|
if !a.Organization {
|
2017-03-10 13:00:03 +01:00
|
|
|
app, err := a.Client.AppInfo(context.TODO(), a.Id)
|
2014-12-14 18:54:01 +01:00
|
|
|
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 {
|
2017-03-10 13:00:03 +01:00
|
|
|
app, err := a.Client.OrganizationAppInfo(context.TODO(), a.Id)
|
2014-12-14 18:54:01 +01:00
|
|
|
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
|
|
|
|
}
|
2014-07-23 18:09:27 +02:00
|
|
|
}
|
|
|
|
|
2017-04-24 20:29:28 +02:00
|
|
|
a.Buildpacks, err = retrieveBuildpacks(a.Id, a.Client)
|
|
|
|
if err != nil {
|
|
|
|
errs = append(errs, err)
|
|
|
|
}
|
|
|
|
|
2014-12-15 15:26:17 +01:00
|
|
|
a.Vars, err = retrieveConfigVars(a.Id, a.Client)
|
2014-07-23 18:09:27 +02:00
|
|
|
if err != nil {
|
|
|
|
errs = append(errs, err)
|
|
|
|
}
|
|
|
|
|
|
|
|
if len(errs) > 0 {
|
|
|
|
return &multierror.Error{Errors: errs}
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2014-08-18 18:32:40 +02:00
|
|
|
func resourceHerokuApp() *schema.Resource {
|
|
|
|
return &schema.Resource{
|
2014-10-12 18:49:57 +02:00
|
|
|
Create: switchHerokuAppCreate,
|
2014-08-18 18:32:40 +02:00
|
|
|
Read: resourceHerokuAppRead,
|
|
|
|
Update: resourceHerokuAppUpdate,
|
|
|
|
Delete: resourceHerokuAppDelete,
|
|
|
|
|
|
|
|
Schema: map[string]*schema.Schema{
|
2017-03-10 13:00:03 +01:00
|
|
|
"name": {
|
2014-08-18 18:32:40 +02:00
|
|
|
Type: schema.TypeString,
|
2014-08-28 00:50:38 +02:00
|
|
|
Required: true,
|
2014-08-18 18:32:40 +02:00
|
|
|
},
|
|
|
|
|
2017-03-10 13:00:03 +01:00
|
|
|
"region": {
|
2014-08-18 18:32:40 +02:00
|
|
|
Type: schema.TypeString,
|
2014-08-28 00:50:38 +02:00
|
|
|
Required: true,
|
|
|
|
ForceNew: true,
|
2014-08-18 18:32:40 +02:00
|
|
|
},
|
|
|
|
|
2017-03-10 13:00:03 +01:00
|
|
|
"stack": {
|
2014-08-18 18:32:40 +02:00
|
|
|
Type: schema.TypeString,
|
|
|
|
Optional: true,
|
|
|
|
Computed: true,
|
2014-08-18 18:36:37 +02:00
|
|
|
ForceNew: true,
|
2014-08-18 18:32:40 +02:00
|
|
|
},
|
|
|
|
|
2017-04-24 20:29:28 +02:00
|
|
|
"buildpacks": {
|
|
|
|
Type: schema.TypeList,
|
|
|
|
Optional: true,
|
|
|
|
Elem: &schema.Schema{
|
|
|
|
Type: schema.TypeString,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
|
2017-03-10 13:00:03 +01:00
|
|
|
"config_vars": {
|
2014-08-18 18:32:40 +02:00
|
|
|
Type: schema.TypeList,
|
|
|
|
Optional: true,
|
|
|
|
Elem: &schema.Schema{
|
2014-08-19 00:18:51 +02:00
|
|
|
Type: schema.TypeMap,
|
2014-08-18 18:32:40 +02:00
|
|
|
},
|
|
|
|
},
|
|
|
|
|
2017-03-10 13:00:03 +01:00
|
|
|
"all_config_vars": {
|
2014-08-28 01:34:43 +02:00
|
|
|
Type: schema.TypeMap,
|
|
|
|
Computed: true,
|
|
|
|
},
|
|
|
|
|
2017-03-10 13:00:03 +01:00
|
|
|
"git_url": {
|
2014-08-18 18:32:40 +02:00
|
|
|
Type: schema.TypeString,
|
|
|
|
Computed: true,
|
|
|
|
},
|
|
|
|
|
2017-03-10 13:00:03 +01:00
|
|
|
"web_url": {
|
2014-08-18 18:32:40 +02:00
|
|
|
Type: schema.TypeString,
|
|
|
|
Computed: true,
|
|
|
|
},
|
|
|
|
|
2017-03-10 13:00:03 +01:00
|
|
|
"heroku_hostname": {
|
2014-08-18 18:32:40 +02:00
|
|
|
Type: schema.TypeString,
|
|
|
|
Computed: true,
|
|
|
|
},
|
2014-10-10 18:54:33 +02:00
|
|
|
|
2017-03-10 13:00:03 +01:00
|
|
|
"organization": {
|
2016-01-04 19:46:52 +01:00
|
|
|
Type: schema.TypeList,
|
|
|
|
Optional: true,
|
|
|
|
ForceNew: true,
|
2014-10-12 20:01:47 +02:00
|
|
|
Elem: &schema.Resource{
|
|
|
|
Schema: map[string]*schema.Schema{
|
2017-03-10 13:00:03 +01:00
|
|
|
"name": {
|
2014-10-12 20:01:47 +02:00
|
|
|
Type: schema.TypeString,
|
|
|
|
Required: true,
|
|
|
|
},
|
|
|
|
|
2017-03-10 13:00:03 +01:00
|
|
|
"locked": {
|
2014-10-12 20:01:47 +02:00
|
|
|
Type: schema.TypeBool,
|
|
|
|
Optional: true,
|
|
|
|
},
|
|
|
|
|
2017-03-10 13:00:03 +01:00
|
|
|
"personal": {
|
2014-10-12 20:01:47 +02:00
|
|
|
Type: schema.TypeBool,
|
|
|
|
Optional: true,
|
|
|
|
},
|
|
|
|
},
|
|
|
|
},
|
2014-10-12 18:49:57 +02:00
|
|
|
},
|
2014-08-18 18:32:40 +02:00
|
|
|
},
|
|
|
|
}
|
|
|
|
}
|
2014-07-23 06:03:30 +02:00
|
|
|
|
2014-12-14 18:54:01 +01:00
|
|
|
func isOrganizationApp(d *schema.ResourceData) bool {
|
2016-01-04 19:46:52 +01:00
|
|
|
v := d.Get("organization").([]interface{})
|
|
|
|
return len(v) > 0 && v[0] != nil
|
2014-12-14 18:54:01 +01:00
|
|
|
}
|
|
|
|
|
2014-10-10 18:54:33 +02:00
|
|
|
func switchHerokuAppCreate(d *schema.ResourceData, meta interface{}) error {
|
2014-12-14 18:54:01 +01:00
|
|
|
if isOrganizationApp(d) {
|
2014-10-12 18:49:57 +02:00
|
|
|
return resourceHerokuOrgAppCreate(d, meta)
|
|
|
|
}
|
2016-01-04 19:46:52 +01:00
|
|
|
|
|
|
|
return resourceHerokuAppCreate(d, meta)
|
2014-10-10 18:54:33 +02:00
|
|
|
}
|
|
|
|
|
2014-08-18 18:32:40 +02:00
|
|
|
func resourceHerokuAppCreate(d *schema.ResourceData, meta interface{}) error {
|
2014-08-27 16:50:37 +02:00
|
|
|
client := meta.(*heroku.Service)
|
2014-07-23 06:03:30 +02:00
|
|
|
|
|
|
|
// Build up our creation options
|
|
|
|
opts := heroku.AppCreateOpts{}
|
|
|
|
|
2014-10-14 21:18:18 +02:00
|
|
|
if v, ok := d.GetOk("name"); ok {
|
2014-08-18 18:32:40 +02:00
|
|
|
vs := v.(string)
|
2014-08-19 00:18:51 +02:00
|
|
|
log.Printf("[DEBUG] App name: %s", vs)
|
2014-08-18 18:32:40 +02:00
|
|
|
opts.Name = &vs
|
2014-07-23 06:03:30 +02:00
|
|
|
}
|
2014-10-14 21:18:18 +02:00
|
|
|
if v, ok := d.GetOk("region"); ok {
|
2014-08-18 18:32:40 +02:00
|
|
|
vs := v.(string)
|
2014-08-19 00:18:51 +02:00
|
|
|
log.Printf("[DEBUG] App region: %s", vs)
|
2014-08-18 18:32:40 +02:00
|
|
|
opts.Region = &vs
|
2014-07-23 06:03:30 +02:00
|
|
|
}
|
2014-10-14 21:18:18 +02:00
|
|
|
if v, ok := d.GetOk("stack"); ok {
|
2014-08-18 18:32:40 +02:00
|
|
|
vs := v.(string)
|
2014-08-19 00:18:51 +02:00
|
|
|
log.Printf("[DEBUG] App stack: %s", vs)
|
2014-08-18 18:32:40 +02:00
|
|
|
opts.Stack = &vs
|
2014-07-23 06:03:30 +02:00
|
|
|
}
|
|
|
|
|
2014-08-19 00:18:51 +02:00
|
|
|
log.Printf("[DEBUG] Creating Heroku app...")
|
2017-03-10 13:00:03 +01:00
|
|
|
a, err := client.AppCreate(context.TODO(), opts)
|
2014-07-23 06:03:30 +02:00
|
|
|
if err != nil {
|
2014-08-18 18:32:40 +02:00
|
|
|
return err
|
2014-07-23 06:03:30 +02:00
|
|
|
}
|
|
|
|
|
2014-08-18 18:32:40 +02:00
|
|
|
d.SetId(a.Name)
|
|
|
|
log.Printf("[INFO] App ID: %s", d.Id())
|
2014-07-23 17:09:05 +02:00
|
|
|
|
2014-10-14 21:18:18 +02:00
|
|
|
if v, ok := d.GetOk("config_vars"); ok {
|
2014-12-15 15:26:17 +01:00
|
|
|
err = updateConfigVars(d.Id(), client, nil, v.([]interface{}))
|
2014-07-23 17:09:05 +02:00
|
|
|
if err != nil {
|
2014-08-18 18:32:40 +02:00
|
|
|
return err
|
2014-07-23 17:09:05 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2017-04-24 20:29:28 +02:00
|
|
|
if v, ok := d.GetOk("buildpacks"); ok {
|
|
|
|
err = updateBuildpacks(d.Id(), client, v.([]interface{}))
|
|
|
|
}
|
|
|
|
|
2014-08-18 18:32:40 +02:00
|
|
|
return resourceHerokuAppRead(d, meta)
|
|
|
|
}
|
|
|
|
|
2014-10-10 18:54:33 +02:00
|
|
|
func resourceHerokuOrgAppCreate(d *schema.ResourceData, meta interface{}) error {
|
2014-10-12 18:49:57 +02:00
|
|
|
client := meta.(*heroku.Service)
|
|
|
|
// Build up our creation options
|
|
|
|
opts := heroku.OrganizationAppCreateOpts{}
|
2014-10-12 20:01:47 +02:00
|
|
|
|
2016-01-04 19:46:52 +01:00
|
|
|
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 {
|
2014-10-12 18:49:57 +02:00
|
|
|
vs := v.(string)
|
2014-10-12 20:01:47 +02:00
|
|
|
log.Printf("[DEBUG] Organization name: %s", vs)
|
2014-10-12 18:49:57 +02:00
|
|
|
opts.Organization = &vs
|
|
|
|
}
|
2014-10-12 20:01:47 +02:00
|
|
|
|
2016-01-04 19:46:52 +01:00
|
|
|
if v := orgDetails["personal"]; v != nil {
|
2014-10-12 20:01:47 +02:00
|
|
|
vs := v.(bool)
|
2014-12-17 12:58:12 +01:00
|
|
|
log.Printf("[DEBUG] Organization Personal: %t", vs)
|
2014-10-12 20:01:47 +02:00
|
|
|
opts.Personal = &vs
|
|
|
|
}
|
|
|
|
|
2016-01-04 19:46:52 +01:00
|
|
|
if v := orgDetails["locked"]; v != nil {
|
2014-10-12 20:01:47 +02:00
|
|
|
vs := v.(bool)
|
2014-12-17 12:58:12 +01:00
|
|
|
log.Printf("[DEBUG] Organization locked: %t", vs)
|
2014-10-12 20:01:47 +02:00
|
|
|
opts.Locked = &vs
|
|
|
|
}
|
|
|
|
|
|
|
|
if v := d.Get("name"); v != nil {
|
2014-10-12 18:49:57 +02:00
|
|
|
vs := v.(string)
|
|
|
|
log.Printf("[DEBUG] App name: %s", vs)
|
|
|
|
opts.Name = &vs
|
|
|
|
}
|
2014-10-14 21:18:18 +02:00
|
|
|
if v, ok := d.GetOk("region"); ok {
|
2014-10-12 18:49:57 +02:00
|
|
|
vs := v.(string)
|
|
|
|
log.Printf("[DEBUG] App region: %s", vs)
|
|
|
|
opts.Region = &vs
|
|
|
|
}
|
2014-10-14 21:18:18 +02:00
|
|
|
if v, ok := d.GetOk("stack"); ok {
|
2014-10-12 18:49:57 +02:00
|
|
|
vs := v.(string)
|
|
|
|
log.Printf("[DEBUG] App stack: %s", vs)
|
|
|
|
opts.Stack = &vs
|
|
|
|
}
|
|
|
|
|
|
|
|
log.Printf("[DEBUG] Creating Heroku app...")
|
2017-03-10 13:00:03 +01:00
|
|
|
a, err := client.OrganizationAppCreate(context.TODO(), opts)
|
2014-10-12 18:49:57 +02:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
|
|
|
|
d.SetId(a.Name)
|
|
|
|
log.Printf("[INFO] App ID: %s", d.Id())
|
|
|
|
|
2014-10-14 21:18:18 +02:00
|
|
|
if v, ok := d.GetOk("config_vars"); ok {
|
2014-12-15 15:26:17 +01:00
|
|
|
err = updateConfigVars(d.Id(), client, nil, v.([]interface{}))
|
2014-10-12 18:49:57 +02:00
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return resourceHerokuAppRead(d, meta)
|
2014-10-10 18:54:33 +02:00
|
|
|
}
|
|
|
|
|
2014-08-18 18:32:40 +02:00
|
|
|
func resourceHerokuAppRead(d *schema.ResourceData, meta interface{}) error {
|
2014-08-27 16:50:37 +02:00
|
|
|
client := meta.(*heroku.Service)
|
2014-07-23 17:09:05 +02:00
|
|
|
|
2014-08-28 01:34:43 +02:00
|
|
|
configVars := make(map[string]string)
|
2014-08-28 01:26:03 +02:00
|
|
|
care := make(map[string]struct{})
|
|
|
|
for _, v := range d.Get("config_vars").([]interface{}) {
|
2017-03-10 13:00:03 +01:00
|
|
|
for k := range v.(map[string]interface{}) {
|
2014-08-28 01:26:03 +02:00
|
|
|
care[k] = struct{}{}
|
|
|
|
}
|
|
|
|
}
|
2014-12-14 18:54:01 +01:00
|
|
|
|
2017-04-24 20:29:28 +02:00
|
|
|
// Only track buildpacks when set in the configuration.
|
|
|
|
_, buildpacksConfigured := d.GetOk("buildpacks")
|
|
|
|
|
2016-01-04 19:46:52 +01:00
|
|
|
organizationApp := isOrganizationApp(d)
|
|
|
|
|
2014-12-14 18:54:01 +01:00
|
|
|
// 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
|
|
|
|
}
|
|
|
|
|
2014-08-28 01:34:43 +02:00
|
|
|
for k, v := range app.Vars {
|
2014-08-28 06:07:56 +02:00
|
|
|
if _, ok := care[k]; ok {
|
2014-08-28 01:34:43 +02:00
|
|
|
configVars[k] = v
|
2014-08-28 01:26:03 +02:00
|
|
|
}
|
|
|
|
}
|
2014-08-28 06:07:56 +02:00
|
|
|
var configVarsValue []map[string]string
|
|
|
|
if len(configVars) > 0 {
|
|
|
|
configVarsValue = []map[string]string{configVars}
|
|
|
|
}
|
2014-08-28 01:26:03 +02:00
|
|
|
|
2014-08-18 18:32:40 +02:00
|
|
|
d.Set("name", app.App.Name)
|
2014-12-14 18:54:01 +01:00
|
|
|
d.Set("stack", app.App.Stack)
|
|
|
|
d.Set("region", app.App.Region)
|
2014-08-18 18:32:40 +02:00
|
|
|
d.Set("git_url", app.App.GitURL)
|
|
|
|
d.Set("web_url", app.App.WebURL)
|
2017-04-24 20:29:28 +02:00
|
|
|
if buildpacksConfigured {
|
|
|
|
d.Set("buildpacks", app.Buildpacks)
|
|
|
|
}
|
2014-08-28 06:07:56 +02:00
|
|
|
d.Set("config_vars", configVarsValue)
|
2014-08-28 01:34:43 +02:00
|
|
|
d.Set("all_config_vars", app.Vars)
|
2014-12-14 18:54:01 +01:00
|
|
|
if organizationApp {
|
2016-01-04 19:46:52 +01:00
|
|
|
orgDetails := map[string]interface{}{
|
2016-01-08 15:20:19 +01:00
|
|
|
"name": app.App.OrganizationName,
|
|
|
|
"locked": app.App.Locked,
|
|
|
|
"personal": false,
|
2016-01-04 19:46:52 +01:00
|
|
|
}
|
|
|
|
err := d.Set("organization", []interface{}{orgDetails})
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2014-12-14 18:54:01 +01:00
|
|
|
}
|
2014-07-23 06:03:30 +02:00
|
|
|
|
2014-08-18 18:32:40 +02:00
|
|
|
// We know that the hostname on heroku will be the name+herokuapp.com
|
|
|
|
// You need this to do things like create DNS CNAME records
|
|
|
|
d.Set("heroku_hostname", fmt.Sprintf("%s.herokuapp.com", app.App.Name))
|
2014-07-23 18:38:45 +02:00
|
|
|
|
2014-08-18 18:32:40 +02:00
|
|
|
return nil
|
|
|
|
}
|
2014-07-23 18:38:45 +02:00
|
|
|
|
2014-08-18 18:32:40 +02:00
|
|
|
func resourceHerokuAppUpdate(d *schema.ResourceData, meta interface{}) error {
|
2014-08-27 16:50:37 +02:00
|
|
|
client := meta.(*heroku.Service)
|
2014-07-23 18:38:45 +02:00
|
|
|
|
2014-08-19 00:18:51 +02:00
|
|
|
// If name changed, update it
|
|
|
|
if d.HasChange("name") {
|
|
|
|
v := d.Get("name").(string)
|
|
|
|
opts := heroku.AppUpdateOpts{
|
|
|
|
Name: &v,
|
|
|
|
}
|
2014-07-23 19:56:47 +02:00
|
|
|
|
2017-03-10 13:00:03 +01:00
|
|
|
renamedApp, err := client.AppUpdate(context.TODO(), d.Id(), opts)
|
2014-08-19 00:18:51 +02:00
|
|
|
if err != nil {
|
|
|
|
return err
|
2014-07-23 20:46:12 +02:00
|
|
|
}
|
|
|
|
|
2014-08-19 00:18:51 +02:00
|
|
|
// Store the new ID
|
|
|
|
d.SetId(renamedApp.Name)
|
|
|
|
}
|
|
|
|
|
2014-08-19 19:13:34 +02:00
|
|
|
// If the config vars changed, then recalculate those
|
|
|
|
if d.HasChange("config_vars") {
|
|
|
|
o, n := d.GetChange("config_vars")
|
|
|
|
if o == nil {
|
|
|
|
o = []interface{}{}
|
|
|
|
}
|
|
|
|
if n == nil {
|
|
|
|
n = []interface{}{}
|
|
|
|
}
|
2014-07-23 19:56:47 +02:00
|
|
|
|
2014-12-15 15:26:17 +01:00
|
|
|
err := updateConfigVars(
|
2014-08-19 19:13:34 +02:00
|
|
|
d.Id(), client, o.([]interface{}), n.([]interface{}))
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
2014-07-23 18:38:45 +02:00
|
|
|
}
|
2014-07-23 06:03:30 +02:00
|
|
|
|
2017-04-24 20:29:28 +02:00
|
|
|
if d.HasChange("buildpacks") {
|
|
|
|
err := updateBuildpacks(d.Id(), client, d.Get("buildpacks").([]interface{}))
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-08-18 18:32:40 +02:00
|
|
|
return resourceHerokuAppRead(d, meta)
|
2014-07-23 06:03:30 +02:00
|
|
|
}
|
|
|
|
|
2014-08-18 18:32:40 +02:00
|
|
|
func resourceHerokuAppDelete(d *schema.ResourceData, meta interface{}) error {
|
2014-08-27 16:50:37 +02:00
|
|
|
client := meta.(*heroku.Service)
|
2014-07-23 06:03:30 +02:00
|
|
|
|
2014-08-18 18:32:40 +02:00
|
|
|
log.Printf("[INFO] Deleting App: %s", d.Id())
|
2017-03-10 13:00:03 +01:00
|
|
|
_, err := client.AppDelete(context.TODO(), d.Id())
|
2014-07-23 06:03:30 +02:00
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("Error deleting App: %s", err)
|
|
|
|
}
|
|
|
|
|
2014-08-18 18:32:40 +02:00
|
|
|
d.SetId("")
|
2014-07-23 06:03:30 +02:00
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2014-12-14 18:54:01 +01:00
|
|
|
func resourceHerokuAppRetrieve(id string, organization bool, client *heroku.Service) (*application, error) {
|
|
|
|
app := application{Id: id, Client: client, Organization: organization}
|
2014-07-23 18:09:27 +02:00
|
|
|
|
|
|
|
err := app.Update()
|
2014-07-23 06:03:30 +02:00
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
return nil, fmt.Errorf("Error retrieving app: %s", err)
|
|
|
|
}
|
|
|
|
|
2014-07-23 18:09:27 +02:00
|
|
|
return &app, nil
|
2014-07-23 06:03:30 +02:00
|
|
|
}
|
|
|
|
|
2017-04-24 20:29:28 +02:00
|
|
|
func retrieveBuildpacks(id string, client *heroku.Service) ([]string, error) {
|
|
|
|
results, err := client.BuildpackInstallationList(context.TODO(), id, nil)
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
buildpacks := []string{}
|
|
|
|
for _, installation := range results {
|
|
|
|
buildpacks = append(buildpacks, installation.Buildpack.Name)
|
|
|
|
}
|
|
|
|
|
|
|
|
return buildpacks, nil
|
|
|
|
}
|
|
|
|
|
2014-12-15 15:26:17 +01:00
|
|
|
func retrieveConfigVars(id string, client *heroku.Service) (map[string]string, error) {
|
2017-03-10 13:00:03 +01:00
|
|
|
vars, err := client.ConfigVarInfoForApp(context.TODO(), id)
|
2014-07-23 18:09:27 +02:00
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2017-03-10 13:00:03 +01:00
|
|
|
nonNullVars := map[string]string{}
|
|
|
|
for k, v := range vars {
|
|
|
|
if v != nil {
|
|
|
|
nonNullVars[k] = *v
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return nonNullVars, nil
|
2014-07-23 18:09:27 +02:00
|
|
|
}
|
|
|
|
|
2014-08-18 18:32:40 +02:00
|
|
|
// Updates the config vars for from an expanded configuration.
|
2014-12-15 15:26:17 +01:00
|
|
|
func updateConfigVars(
|
2014-08-19 19:13:34 +02:00
|
|
|
id string,
|
2014-08-27 16:50:37 +02:00
|
|
|
client *heroku.Service,
|
2014-08-19 19:13:34 +02:00
|
|
|
o []interface{},
|
|
|
|
n []interface{}) error {
|
2014-07-23 17:26:31 +02:00
|
|
|
vars := make(map[string]*string)
|
|
|
|
|
2014-08-19 19:13:34 +02:00
|
|
|
for _, v := range o {
|
2015-03-26 17:44:51 +01:00
|
|
|
if v != nil {
|
2017-03-10 13:00:03 +01:00
|
|
|
for k := range v.(map[string]interface{}) {
|
2015-03-26 17:44:51 +01:00
|
|
|
vars[k] = nil
|
|
|
|
}
|
2014-08-19 19:13:34 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
for _, v := range n {
|
2015-03-26 17:44:51 +01:00
|
|
|
if v != nil {
|
|
|
|
for k, v := range v.(map[string]interface{}) {
|
|
|
|
val := v.(string)
|
|
|
|
vars[k] = &val
|
|
|
|
}
|
2014-08-18 18:32:40 +02:00
|
|
|
}
|
2014-07-23 17:26:31 +02:00
|
|
|
}
|
|
|
|
|
2014-07-23 20:46:12 +02:00
|
|
|
log.Printf("[INFO] Updating config vars: *%#v", vars)
|
2017-03-10 13:00:03 +01:00
|
|
|
if _, err := client.ConfigVarUpdate(context.TODO(), id, vars); err != nil {
|
2014-07-23 17:26:31 +02:00
|
|
|
return fmt.Errorf("Error updating config vars: %s", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
2017-04-24 20:29:28 +02:00
|
|
|
|
|
|
|
func updateBuildpacks(id string, client *heroku.Service, v []interface{}) error {
|
|
|
|
opts := heroku.BuildpackInstallationUpdateOpts{
|
|
|
|
Updates: []struct {
|
|
|
|
Buildpack string `json:"buildpack" url:"buildpack,key"`
|
|
|
|
}{}}
|
|
|
|
|
|
|
|
for _, buildpack := range v {
|
|
|
|
opts.Updates = append(opts.Updates, struct {
|
|
|
|
Buildpack string `json:"buildpack" url:"buildpack,key"`
|
|
|
|
}{
|
|
|
|
Buildpack: buildpack.(string),
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
if _, err := client.BuildpackInstallationUpdate(context.TODO(), id, opts); err != nil {
|
|
|
|
return fmt.Errorf("Error updating buildpacks: %s", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|