Skip to content

Commit

Permalink
Add util_register resource for storing a value
Browse files Browse the repository at this point in the history
* Set a register value to persist in state, even after
the value is no longer set in the Terraform resource
* Setting the value to `null` or "" (empty string)
won't alter the resource value (or show a diff)
* Allow the value to be updated (plan shows a diff)

This differs from conditional expressions that check that
a value isn't null or default to a value (which may be a
data reference to the old value):

```tf
locals {
  out = var.foo == null ? data.old_foo : var.foo
}

data "old_foo" ...
```

Instead, it allows a Terraform resource value to retain
a value from a previous declarative state. This can be
useful in cases where querying and referencing the value
again is expensive and the value cannot change externally.

```tf
resource "util_register" "example" {
  set = null         # previously "bar"
}

output "out" {
  value = util_register.example.value  # "bar"
}
```
  • Loading branch information
dghubble committed Mar 30, 2022
1 parent db86d7f commit da83c2d
Show file tree
Hide file tree
Showing 10 changed files with 201 additions and 5 deletions.
6 changes: 5 additions & 1 deletion CHANGES.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@ Notable changes between releases.

## Latest

## v0.2.0

* Add `util_register` resource for storing values

## v0.1.0

* Add `util_replace` function
* Add `util_replace` data source function
23 changes: 21 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ terraform {
required_providers {
ct = {
source = "poseidon/util"
version = "0.1.0"
version = "0.2.0"
}
}
}
Expand All @@ -36,6 +36,26 @@ output "example" {
}
```

Store a value in state that persists until changed to a non-empty value.

```tf
resource "util_register" "example" {
set = "a1b2c3"
}
```

Later, the register's value may be updated, but setting it to `null` or `""` is ignored.

```tf
resource "util_register" "example" {
set = null
}
output "sha" {
value = util_register.example.value # "a1b2c3"
}
```

Run `terraform init` to ensure plugin version requirements are met.

```
Expand All @@ -55,4 +75,3 @@ To develop the provider plugin locally, build an executable with Go v1.16+.
```
make
```

2 changes: 1 addition & 1 deletion docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ terraform {
required_providers {
ct = {
source = "poseidon/util"
version = "0.1.0"
version = "0.2.0"
}
}
}
Expand Down
29 changes: 29 additions & 0 deletions docs/resources/register.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
# Register

Store a value in state that persists until changed to a non-empty value.

```tf
resource "util_register" "example" {
set = "a1b2c3"
}
```

Later, the register's value may be updated, but setting it to `null` or `""` is ignored.

```tf
resource "util_register" "example" {
set = null
}
output "sha" {
value = util_register.example.value # "a1b2c3"
}
```

## Argument Reference

* `set` - set the register value (`""` or `null` values ignored)

## Attribute Reference

* `value` - computed value of the register
3 changes: 3 additions & 0 deletions example/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
.terraform
*.tfstate*
output
3 changes: 3 additions & 0 deletions example/main.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
resource "util_register" "example" {
set = "a1b2c3"
}
9 changes: 9 additions & 0 deletions example/providers.tf
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
terraform {
required_providers {
util = {
source = "poseidon/util"
#source = "terraform.localhost/poseidon/util"
version = "0.2.0"
}
}
}
5 changes: 4 additions & 1 deletion util/provider.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,12 @@ import (
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
)

// Provider returns a config transpiler Provider.
// Provider returns a util Provider.
func Provider() *schema.Provider {
return &schema.Provider{
ResourcesMap: map[string]*schema.Resource{
"util_register": resourceRegister(),
},
DataSourcesMap: map[string]*schema.Resource{
"util_replace": datasourceReplace(),
},
Expand Down
64 changes: 64 additions & 0 deletions util/resource_register.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
package util

import (
"context"
"strconv"

"github.com/hashicorp/terraform-plugin-sdk/helper/hashcode"
"github.com/hashicorp/terraform-plugin-sdk/v2/diag"
"github.com/hashicorp/terraform-plugin-sdk/v2/helper/schema"
)

func resourceRegister() *schema.Resource {
return &schema.Resource{
CreateContext: resourceCreate,
ReadContext: registerRead,
UpdateContext: registerUpdate,
DeleteContext: registerDelete,
Schema: map[string]*schema.Schema{
"set": &schema.Schema{
Type: schema.TypeString,
Optional: true,
ForceNew: false,
DiffSuppressOnRefresh: true,
DiffSuppressFunc: registerDiffSuppress,
},
"value": &schema.Schema{
Type: schema.TypeString,
Computed: true,
Description: "Last set register value",
},
},
}
}

func resourceCreate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
var diags diag.Diagnostics

set := d.Get("set").(string)
d.Set("value", set)
d.SetId(strconv.Itoa(hashcode.String(set)))
return diags
}

func registerRead(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
return nil
}

func registerUpdate(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
var diags diag.Diagnostics
set := d.Get("set").(string)
if set != "" {
d.Set("value", set)
}
return diags
}

func registerDelete(ctx context.Context, d *schema.ResourceData, meta interface{}) diag.Diagnostics {
d.SetId("")
return nil
}

func registerDiffSuppress(k, oldV, newV string, d *schema.ResourceData) bool {
return newV == ""
}
62 changes: 62 additions & 0 deletions util/resource_register_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
package util

import (
"testing"

r "github.com/hashicorp/terraform-plugin-sdk/v2/helper/resource"
)

const registerInitial = `
resource "util_register" "example" {
set = "a1b2c3"
}
`

const registerUnsetSHA = `
resource "util_register" "example" {
set = ""
}
`

const registerUpdateSHA = `
resource "util_register" "example" {
set = "b2c3d4"
}
`

func TestRegister(t *testing.T) {
r.UnitTest(t, r.TestCase{
Providers: testProviders,
Steps: []r.TestStep{
// set initial value
r.TestStep{
Config: registerInitial,
Check: r.ComposeTestCheckFunc(
r.TestCheckResourceAttr("util_register.example", "value", "a1b2c3"),
),
},
// set with empty value doesn't change value
r.TestStep{
Config: registerUnsetSHA,
Check: r.ComposeTestCheckFunc(
r.TestCheckResourceAttr("util_register.example", "value", "a1b2c3"),
),
},
// set with content updates values
r.TestStep{
Config: registerUpdateSHA,
Check: r.ComposeTestCheckFunc(
r.TestCheckResourceAttr("util_register.example", "value", "b2c3d4"),
),
},
// suppress noisy diffs that won't affect value
r.TestStep{
Config: registerUnsetSHA,
PlanOnly: true,
Check: r.ComposeTestCheckFunc(
r.TestCheckResourceAttr("util_register.example", "value", "b2c3d4"),
),
},
},
})
}

0 comments on commit da83c2d

Please sign in to comment.