providers/heroku: add heroku_app_feature resource (#14035)

This commit is contained in:
Dan Peterson 2017-04-27 11:55:07 -03:00 committed by Clint
parent 2af1bd9fe0
commit e495c6bacc
4 changed files with 282 additions and 6 deletions

View File

@ -1,7 +1,9 @@
package heroku
import (
"fmt"
"log"
"strings"
"github.com/hashicorp/terraform/helper/schema"
"github.com/hashicorp/terraform/terraform"
@ -25,12 +27,13 @@ func Provider() terraform.ResourceProvider {
},
ResourcesMap: map[string]*schema.Resource{
"heroku_addon": resourceHerokuAddon(),
"heroku_app": resourceHerokuApp(),
"heroku_cert": resourceHerokuCert(),
"heroku_domain": resourceHerokuDomain(),
"heroku_drain": resourceHerokuDrain(),
"heroku_space": resourceHerokuSpace(),
"heroku_addon": resourceHerokuAddon(),
"heroku_app": resourceHerokuApp(),
"heroku_app_feature": resourceHerokuAppFeature(),
"heroku_cert": resourceHerokuCert(),
"heroku_domain": resourceHerokuDomain(),
"heroku_drain": resourceHerokuDrain(),
"heroku_space": resourceHerokuSpace(),
},
ConfigureFunc: providerConfigure,
@ -46,3 +49,12 @@ func providerConfigure(d *schema.ResourceData) (interface{}, error) {
log.Println("[INFO] Initializing Heroku client")
return config.Client()
}
func buildCompositeID(a, b string) string {
return fmt.Sprintf("%s:%s", a, b)
}
func parseCompositeID(id string) (string, string) {
parts := strings.SplitN(id, ":", 2)
return parts[0], parts[1]
}

View File

@ -0,0 +1,101 @@
package heroku
import (
"context"
"log"
heroku "github.com/cyberdelia/heroku-go/v3"
"github.com/hashicorp/terraform/helper/schema"
)
func resourceHerokuAppFeature() *schema.Resource {
return &schema.Resource{
Create: resourceAppFeatureCreate,
Update: resourceAppFeatureUpdate,
Read: resourceAppFeatureRead,
Delete: resourceAppFeatureDelete,
Schema: map[string]*schema.Schema{
"app": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
},
"name": {
Type: schema.TypeString,
Required: true,
ForceNew: true,
},
"enabled": {
Type: schema.TypeBool,
Optional: true,
Default: true,
},
},
}
}
func resourceAppFeatureRead(d *schema.ResourceData, meta interface{}) error {
client := meta.(*heroku.Service)
app, id := parseCompositeID(d.Id())
feature, err := client.AppFeatureInfo(context.TODO(), app, id)
if err != nil {
return err
}
d.Set("app", app)
d.Set("name", feature.Name)
d.Set("enabled", feature.Enabled)
return nil
}
func resourceAppFeatureCreate(d *schema.ResourceData, meta interface{}) error {
client := meta.(*heroku.Service)
app := d.Get("app").(string)
featureName := d.Get("name").(string)
enabled := d.Get("enabled").(bool)
opts := heroku.AppFeatureUpdateOpts{Enabled: enabled}
log.Printf("[DEBUG] Feature set configuration: %#v, %#v", featureName, opts)
feature, err := client.AppFeatureUpdate(context.TODO(), app, featureName, opts)
if err != nil {
return err
}
d.SetId(buildCompositeID(app, feature.ID))
return resourceAppFeatureRead(d, meta)
}
func resourceAppFeatureUpdate(d *schema.ResourceData, meta interface{}) error {
if d.HasChange("enabled") {
return resourceAppFeatureCreate(d, meta)
}
return resourceAppFeatureRead(d, meta)
}
func resourceAppFeatureDelete(d *schema.ResourceData, meta interface{}) error {
client := meta.(*heroku.Service)
app, id := parseCompositeID(d.Id())
featureName := d.Get("name").(string)
log.Printf("[INFO] Deleting app feature %s (%s) for app %s", featureName, id, app)
opts := heroku.AppFeatureUpdateOpts{Enabled: false}
_, err := client.AppFeatureUpdate(context.TODO(), app, id, opts)
if err != nil {
return err
}
d.SetId("")
return nil
}

View File

@ -0,0 +1,135 @@
package heroku
import (
"context"
"fmt"
"testing"
heroku "github.com/cyberdelia/heroku-go/v3"
"github.com/hashicorp/terraform/helper/acctest"
"github.com/hashicorp/terraform/helper/resource"
"github.com/hashicorp/terraform/terraform"
)
func TestAccHerokuAppFeature(t *testing.T) {
var feature heroku.AppFeatureInfoResult
appName := fmt.Sprintf("tftest-%s", acctest.RandString(10))
resource.Test(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckHerokuFeatureDestroy,
Steps: []resource.TestStep{
{
Config: testAccCheckHerokuFeature_basic(appName),
Check: resource.ComposeTestCheckFunc(
testAccCheckHerokuFeatureExists("heroku_app_feature.runtime_metrics", &feature),
testAccCheckHerokuFeatureEnabled(&feature, true),
resource.TestCheckResourceAttr(
"heroku_app_feature.runtime_metrics", "enabled", "true",
),
),
},
{
Config: testAccCheckHerokuFeature_disabled(appName),
Check: resource.ComposeTestCheckFunc(
testAccCheckHerokuFeatureExists("heroku_app_feature.runtime_metrics", &feature),
testAccCheckHerokuFeatureEnabled(&feature, false),
resource.TestCheckResourceAttr(
"heroku_app_feature.runtime_metrics", "enabled", "false",
),
),
},
},
})
}
func testAccCheckHerokuFeatureDestroy(s *terraform.State) error {
client := testAccProvider.Meta().(*heroku.Service)
for _, rs := range s.RootModule().Resources {
if rs.Type != "heroku_app_feature" {
continue
}
_, err := client.AppFeatureInfo(context.TODO(), rs.Primary.Attributes["app"], rs.Primary.ID)
if err == nil {
return fmt.Errorf("Feature still exists")
}
}
return nil
}
func testAccCheckHerokuFeatureExists(n string, feature *heroku.AppFeatureInfoResult) 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 feature ID is set")
}
app, id := parseCompositeID(rs.Primary.ID)
if app != rs.Primary.Attributes["app"] {
return fmt.Errorf("Bad app: %s", app)
}
client := testAccProvider.Meta().(*heroku.Service)
foundFeature, err := client.AppFeatureInfo(context.TODO(), app, id)
if err != nil {
return err
}
if foundFeature.ID != id {
return fmt.Errorf("Feature not found")
}
*feature = *foundFeature
return nil
}
}
func testAccCheckHerokuFeatureEnabled(feature *heroku.AppFeatureInfoResult, enabled bool) resource.TestCheckFunc {
return func(s *terraform.State) error {
if feature.Enabled != enabled {
return fmt.Errorf("Bad enabled: %v", feature.Enabled)
}
return nil
}
}
func testAccCheckHerokuFeature_basic(appName string) string {
return fmt.Sprintf(`
resource "heroku_app" "example" {
name = "%s"
region = "us"
}
resource "heroku_app_feature" "runtime_metrics" {
app = "${heroku_app.example.name}"
name = "log-runtime-metrics"
}
`, appName)
}
func testAccCheckHerokuFeature_disabled(appName string) string {
return fmt.Sprintf(`
resource "heroku_app" "example" {
name = "%s"
region = "us"
}
resource "heroku_app_feature" "runtime_metrics" {
app = "${heroku_app.example.name}"
name = "log-runtime-metrics"
enabled = false
}
`, appName)
}

View File

@ -0,0 +1,28 @@
---
layout: "heroku"
page_title: "Heroku: heroku_app_feature"
sidebar_current: "docs-heroku-resource-app-feature"
description: |-
Provides a Heroku App Feature resource. This can be used to create and manage App Features on Heroku.
---
# heroku\_app\_feature
Provides a Heroku App Feature resource. This can be used to create and manage App Features on Heroku.
## Example Usage
```hcl
resource "heroku_app_feature" "log_runtime_metrics" {
app = "test-app"
name = "log-runtime-metrics"
}
```
## Argument Reference
The following arguments are supported:
* `app` - (Required) The Heroku app to link to.
* `name` - (Required) The name of the App Feature to manage.
* `enabled` - (Optional) Whether to enable or disable the App Feature. The default value is true.