terraform/builtin/providers/heroku/resource_heroku_addon.go

170 lines
3.7 KiB
Go

package heroku
import (
"fmt"
"log"
"strings"
"sync"
"github.com/cyberdelia/heroku-go/v3"
"github.com/hashicorp/terraform/helper/schema"
)
// Global lock to prevent parallelism for heroku_addon since
// the Heroku API cannot handle a single application requesting
// multiple addons simultaneously.
var addonLock sync.Mutex
func resourceHerokuAddon() *schema.Resource {
return &schema.Resource{
Create: resourceHerokuAddonCreate,
Read: resourceHerokuAddonRead,
Update: resourceHerokuAddonUpdate,
Delete: resourceHerokuAddonDelete,
Schema: map[string]*schema.Schema{
"app": &schema.Schema{
Type: schema.TypeString,
Required: true,
ForceNew: true,
},
"plan": &schema.Schema{
Type: schema.TypeString,
Required: true,
},
"config": &schema.Schema{
Type: schema.TypeList,
Optional: true,
ForceNew: true,
Elem: &schema.Schema{
Type: schema.TypeMap,
},
},
"provider_id": &schema.Schema{
Type: schema.TypeString,
Computed: true,
},
"config_vars": &schema.Schema{
Type: schema.TypeList,
Computed: true,
Elem: &schema.Schema{Type: schema.TypeMap},
},
},
}
}
func resourceHerokuAddonCreate(d *schema.ResourceData, meta interface{}) error {
addonLock.Lock()
defer addonLock.Unlock()
client := meta.(*heroku.Service)
app := d.Get("app").(string)
opts := heroku.AddonCreateOpts{Plan: d.Get("plan").(string)}
if v := d.Get("config"); v != nil {
config := make(map[string]string)
for _, v := range v.([]interface{}) {
for k, v := range v.(map[string]interface{}) {
config[k] = v.(string)
}
}
opts.Config = &config
}
log.Printf("[DEBUG] Addon create configuration: %#v, %#v", app, opts)
a, err := client.AddonCreate(app, opts)
if err != nil {
return err
}
d.SetId(a.ID)
log.Printf("[INFO] Addon ID: %s", d.Id())
return resourceHerokuAddonRead(d, meta)
}
func resourceHerokuAddonRead(d *schema.ResourceData, meta interface{}) error {
client := meta.(*heroku.Service)
addon, err := resourceHerokuAddonRetrieve(
d.Get("app").(string), d.Id(), client)
if err != nil {
return err
}
// Determine the plan. If we were configured without a specific plan,
// then just avoid the plan altogether (accepting anything that
// Heroku sends down).
plan := addon.Plan.Name
if v := d.Get("plan").(string); v != "" {
if idx := strings.IndexRune(v, ':'); idx == -1 {
idx = strings.IndexRune(plan, ':')
if idx > -1 {
plan = plan[:idx]
}
}
}
d.Set("name", addon.Name)
d.Set("plan", plan)
d.Set("provider_id", addon.ProviderID)
configVarsMap := make(map[string]interface{})
for i := range addon.ConfigVars {
configVarsMap[addon.ConfigVars[i]] = addon.ConfigVars[i]
}
d.Set("config_vars", []interface{}{configVarsMap})
return nil
}
func resourceHerokuAddonUpdate(d *schema.ResourceData, meta interface{}) error {
client := meta.(*heroku.Service)
app := d.Get("app").(string)
if d.HasChange("plan") {
ad, err := client.AddonUpdate(
app, d.Id(), heroku.AddonUpdateOpts{Plan: d.Get("plan").(string)})
if err != nil {
return err
}
// Store the new ID
d.SetId(ad.ID)
}
return resourceHerokuAddonRead(d, meta)
}
func resourceHerokuAddonDelete(d *schema.ResourceData, meta interface{}) error {
client := meta.(*heroku.Service)
log.Printf("[INFO] Deleting Addon: %s", d.Id())
// Destroy the app
err := client.AddonDelete(d.Get("app").(string), d.Id())
if err != nil {
return fmt.Errorf("Error deleting addon: %s", err)
}
d.SetId("")
return nil
}
func resourceHerokuAddonRetrieve(app string, id string, client *heroku.Service) (*heroku.Addon, error) {
addon, err := client.AddonInfo(app, id)
if err != nil {
return nil, fmt.Errorf("Error retrieving addon: %s", err)
}
return addon, nil
}