Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

providers/heroku: add heroku_app_feature resource #14035

Merged
merged 1 commit into from
Apr 27, 2017
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 18 additions & 6 deletions builtin/providers/heroku/provider.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
package heroku

import (
"fmt"
"log"
"strings"

"github.com/hashicorp/terraform/helper/schema"
"github.com/hashicorp/terraform/terraform"
Expand All @@ -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,
Expand All @@ -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]
}
101 changes: 101 additions & 0 deletions builtin/providers/heroku/resource_heroku_app_feature.go
Original file line number Diff line number Diff line change
@@ -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
}
135 changes: 135 additions & 0 deletions builtin/providers/heroku/resource_heroku_app_feature_test.go
Original file line number Diff line number Diff line change
@@ -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)
}
28 changes: 28 additions & 0 deletions website/source/docs/providers/heroku/r/app_feature.html.markdown
Original file line number Diff line number Diff line change
@@ -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.