Skip to content

Commit

Permalink
fix issue where importing random_string & random_password is not writ…
Browse files Browse the repository at this point in the history
…ing all defaults into TF state

Co-authored-by: Benjamin Bennett <[email protected]>
  • Loading branch information
wakeful and bendbennett committed Jun 23, 2022
1 parent b8d7b4e commit 74c568b
Show file tree
Hide file tree
Showing 11 changed files with 333 additions and 11 deletions.
7 changes: 7 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,10 @@
## 3.3.2 (unreleased)

BUG FIXES:

* resource/random_password: When importing set defaults for all attributes that have a default defined ([256](https://github.com/hashicorp/terraform-provider-random/pull/256)).
* resource/random_string: When importing set defaults for all attributes that have a default defined ([256](https://github.com/hashicorp/terraform-provider-random/pull/256)).

## 3.3.1 (June 07, 2022)

BUG FIXES:
Expand Down
63 changes: 61 additions & 2 deletions docs/resources/password.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
---
# generated by https://github.com/hashicorp/terraform-plugin-docs
page_title: "random_password Resource - terraform-provider-random"
subcategory: ""
description: |-
Expand Down Expand Up @@ -63,6 +62,66 @@ resource "aws_db_instance" "example" {
Import is supported using the following syntax:

```shell
# Random Password can be imported by specifying the value of the string:
terraform import random_password.password securepassword
```

### Limitations of Import

Any attribute values that are specified within Terraform config will be
ignored during import and all attributes that have defaults defined within
the schema will have the default assigned.

For instance, using the following config during import:
```terraform
resource "random_password" "password" {
length = 16
lower = false
}
```

Then importing the resource using `terraform import random_password.password securepassword`,
would result in the triggering of a replacement (i.e., destroy-create) during the next
`terraform apply`.

### Avoiding Replacement

If the resource were imported using `terraform import random_password.password securepassword`,
replacement could be avoided by using:

1. Attribute values that match the imported ID and defaults:

```terraform
resource "random_password" "password" {
length = 14
lower = true
}
```


2. Attribute values that match the imported ID and omit the attributes with defaults:

```terraform
resource "random_password" "password" {
length = 14
}
```


3. `ignore_changes` specifying the attributes to ignore:

```terraform
resource "random_password" "password" {
length = 16
lower = false
lifecycle {
ignore_changes = [
length,
lower,
]
}
}
```

**NOTE** `ignore_changes` is only required until the resource is recreated after import,
after which it will use the configuration values specified.
58 changes: 56 additions & 2 deletions docs/resources/string.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
---
# generated by https://github.com/hashicorp/terraform-plugin-docs
page_title: "random_string Resource - terraform-provider-random"
subcategory: ""
description: |-
Expand Down Expand Up @@ -57,6 +56,61 @@ resource "random_string" "random" {
Import is supported using the following syntax:

```shell
# Strings can be imported by just specifying the value of the string:
terraform import random_string.test test
```

### Limitations of Import

Any attribute values that are specified within Terraform config will be
ignored during import and all attributes that have defaults defined within
the schema will have the default assigned.

For instance, using the following config during import:
```terraform
resource "random_string" "test" {
length = 16
lower = false
}
```

Then importing the resource using `terraform import random_string.test test`,
would result in the triggering of a replacement (i.e., destroy-create) during
the next `terraform apply`.

### Avoiding Replacement

If the resource were imported using `terraform import random_string.test test`,
replacement can be avoided by using:

1. Attribute values that match the imported ID and defaults:
```terraform
resource "random_string" "test" {
length = 4
lower = true
}
```

2. Attribute values that match the imported ID and omit the attributes with defaults:
```terraform
resource "random_string" "test" {
length = 4
}
```

3. `ignore_changes` specifying the attributes to ignore:
```terraform
resource "random_string" "test" {
length = 16
lower = false
lifecycle {
ignore_changes = [
length,
lower,
]
}
}
```

**NOTE** `ignore_changes` is only required until the resource is recreated after import,
after which it will use the configuration values specified.
2 changes: 1 addition & 1 deletion examples/resources/random_password/import.sh
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
# Random Password can be imported by specifying the value of the string:
# Random Password can be imported by specifying the value of the password.
terraform import random_password.password securepassword
2 changes: 1 addition & 1 deletion examples/resources/random_string/import.sh
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
# Strings can be imported by just specifying the value of the string:
# Random String can be imported by specifying the value of the string.
terraform import random_string.test test
19 changes: 19 additions & 0 deletions internal/provider/resource_password.go
Original file line number Diff line number Diff line change
Expand Up @@ -72,13 +72,32 @@ func createPassword(ctx context.Context, d *schema.ResourceData, meta interface{
}

func importPasswordFunc(ctx context.Context, d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) {
for k, v := range passwordSchemaV2() {
if v.Default == nil {
continue
}
if err := d.Set(k, v.Default); err != nil {
return nil, fmt.Errorf("error setting %s: %w", k, err)
}
}

for _, key := range []string{"number", "numeric"} {
if err := d.Set(key, true); err != nil {
return nil, fmt.Errorf("error setting %s: %w", key, err)
}
}

val := d.Id()
d.SetId("none")

if err := d.Set("result", val); err != nil {
return nil, fmt.Errorf("resource password import failed, error setting result: %w", err)
}

if err := d.Set("length", len(val)); err != nil {
return nil, fmt.Errorf("error setting length: %w", err)
}

hash, err := generateHash(val)
if err != nil {
return nil, fmt.Errorf("resource password import failed, generate hash error: %w", err)
Expand Down
2 changes: 1 addition & 1 deletion internal/provider/resource_password_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,7 @@ func TestAccResourcePasswordBasic(t *testing.T) {
},
ImportState: true,
ImportStateVerify: true,
ImportStateVerifyIgnore: []string{"bcrypt_hash", "length", "lower", "number", "numeric", "special", "upper", "min_lower", "min_numeric", "min_special", "min_upper", "override_special"},
ImportStateVerifyIgnore: []string{"bcrypt_hash"},
},
},
})
Expand Down
19 changes: 19 additions & 0 deletions internal/provider/resource_string.go
Original file line number Diff line number Diff line change
Expand Up @@ -51,12 +51,31 @@ func resourceString() *schema.Resource {
}

func importStringFunc(ctx context.Context, d *schema.ResourceData, meta interface{}) ([]*schema.ResourceData, error) {
for k, v := range stringSchemaV2() {
if v.Default == nil {
continue
}
if err := d.Set(k, v.Default); err != nil {
return nil, fmt.Errorf("error setting %s: %w", k, err)
}
}

for _, key := range []string{"number", "numeric"} {
if err := d.Set(key, true); err != nil {
return nil, fmt.Errorf("error setting %s: %w", key, err)
}
}

val := d.Id()

if err := d.Set("result", val); err != nil {
return nil, fmt.Errorf("error setting result: %w", err)
}

if err := d.Set("length", len(val)); err != nil {
return nil, fmt.Errorf("error setting length: %w", err)
}

return []*schema.ResourceData{d}, nil
}

Expand Down
7 changes: 3 additions & 4 deletions internal/provider/resource_string_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,10 +27,9 @@ func TestAccResourceString(t *testing.T) {
),
},
{
ResourceName: "random_string.basic",
ImportState: true,
ImportStateVerify: true,
ImportStateVerifyIgnore: []string{"length", "lower", "number", "numeric", "special", "upper", "min_lower", "min_numeric", "min_special", "min_upper", "override_special"},
ResourceName: "random_string.basic",
ImportState: true,
ImportStateVerify: true,
},
},
})
Expand Down
85 changes: 85 additions & 0 deletions templates/resources/password.md.tmpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
---
page_title: "{{.Name}} {{.Type}} - {{.ProviderName}}"
subcategory: ""
description: |-
{{ .Description | plainmarkdown | trimspace | prefixlines " " }}
---

# {{.Name}} ({{.Type}})

{{ .Description | trimspace }}

## Example Usage

{{ tffile "examples/resources/random_password/resource.tf" }}

{{ .SchemaMarkdown | trimspace }}

## Import

Import is supported using the following syntax:

```shell
terraform import random_password.password securepassword
```

### Limitations of Import

Any attribute values that are specified within Terraform config will be
ignored during import and all attributes that have defaults defined within
the schema will have the default assigned.

For instance, using the following config during import:
```terraform
resource "random_password" "password" {
length = 16
lower = false
}
```

Then importing the resource using `terraform import random_password.password securepassword`,
would result in the triggering of a replacement (i.e., destroy-create) during the next
`terraform apply`.

### Avoiding Replacement

If the resource were imported using `terraform import random_password.password securepassword`,
replacement could be avoided by using:

1. Attribute values that match the imported ID and defaults:

```terraform
resource "random_password" "password" {
length = 14
lower = true
}
```


2. Attribute values that match the imported ID and omit the attributes with defaults:

```terraform
resource "random_password" "password" {
length = 14
}
```


3. `ignore_changes` specifying the attributes to ignore:

```terraform
resource "random_password" "password" {
length = 16
lower = false

lifecycle {
ignore_changes = [
length,
lower,
]
}
}
```

**NOTE** `ignore_changes` is only required until the resource is recreated after import,
after which it will use the configuration values specified.
Loading

0 comments on commit 74c568b

Please sign in to comment.