hashicorp / hashicorp/terraform-plugin-sdk
Terraform apply always shows a change for unset optional boolean with default of false
- Dominant language
- Go
- Stars
- 485
- Forks
- 244
- Avg merge
- 19h 57m
- Merged PRs (30d)
- 4
Description
### SDK version
```
github.com/hashicorp/terraform-plugin-sdk/v2 v2.4.0
```
### Relevant provider source code
```go
func guacamoleUser() *schema.Resource {
return &schema.Resource{
CreateContext: resourceUserCreate,
ReadContext: resourceUserRead,
UpdateContext: resourceUserUpdate,
DeleteContext: resourceUserDelete,
Schema: map[string]*schema.Schema{
"username": {
Type: schema.TypeString,
Description: "Username of guacamole user",
Required: true,
ForceNew: true,
},
"last_active": {
Type: schema.TypeString,
Description: "Epoch time string of last user activity",
Computed: true,
},
"attributes": {
Type: schema.TypeList,
Description: "Attributes of guacamole user",
Optional: true,
MaxItems: 1,
Elem: &schema.Resource{
Schema: map[string]*schema.Schema{
"organizational_role": {
Type: schema.TypeString,
Description: "Organizational role of user",
Optional: true,
Default: "",
},
"full_name": {
Type: schema.TypeString,
Description: "Full name of user",
Optional: true,
Default: "",
},
"email": {
Type: schema.TypeString,
Description: "Email of user",
Optional: true,
Default: "",
},
"expired": {
Type: schema.TypeBool,
Description: "Whether the user is expired",
Optional: true,
Default: false,
},
"timezone": {
Type: schema.TypeString,
Description: "Timezone of user",
Optional: true,
Default: "",
},
"access_window_start": {
Type: schema.TypeString,
Description: "Access window start time for user",
Optional: true,
Default: "",
},
"access_window_end": {
Type: schema.TypeString,
Description: "Access window end time for user",
Optional: true,
Default: "",
},
"disabled": {
Type: schema.TypeBool,
Description: "Whether account is disabled",
Optional: true,
Default: false,
},
"valid_from": {
Type: schema.TypeString,
Description: "Start date for when user is valid",
Optional: true,
Default: "",
},
"valid_until": {
Type: schema.TypeString,
Description: "End date for when user is valid",
Optional: true,
Default: "",
},
},
},
},
"group_membership": {
Type: schema.TypeSet,
Description: "Groups this user is a member of",
Optional: true,
Elem: &schema.Schema{
Type: schema.TypeString,
},
},
"system_permissions": {
Type: schema.TypeSet,
Description: "System permissions assigned to user",
Optional: true,
Elem: &schema.Schema{
Type: schema.TypeString,
},
},
},
}
}
```
### Terraform Configuration Files
```hcl
...
```
### Debug Output
```bash
An execution plan has been generated and is shown below.
Resource actions are indicated with the following symbols:
~ update in-place
Terraform will perform the following actions:
2021/01/06 08:53:23 [DEBUG] command: asking for input: "Do you want to perform these actions?"
# guacamole_user.test_user will be updated in-place
~ resource "guacamole_user" "test_user" {
id = "testUser"
# (4 unchanged attributes hidden)
- attributes {
- disabled = false -> null
- expired = false -> null
}
}
Plan: 0 to add, 1 to change, 0 to destroy.
```
### Config snippets
#### main.tf
```hcl
resource "guacamole_user" "test_user" {
username = "testUser"
}
```
#### terraform.tfstate
```json
{
"version": 4,
"terraform_version": "0.14.3",
"serial": 234,
"lineage": "06621170-99a5-4601-6744-02b6e5831bb1",
"outputs": {},
"resources": [
{
"mode": "managed",
"type": "guacamole_user",
"name": "test_user",
"provider": "provider[\"techbeck03.com/techbeck03/guacamole\"]",
"instances": [
{
"schema_version": 0,
"attributes": {
"attributes": [
{
"access_window_end": "",
"access_window_start": "",
"disabled": false,
"email": "",
"expired": false,
"full_name": "",
"organizational_role": "",
"timezone": "",
"valid_from": "",
"valid_until": ""
}
],
"group_membership": [],
"id": "testUser",
"last_active": "0",
"system_permissions": [],
"username": "testUser"
},
"sensitive_attributes": [],
"private": "bnVsbA=="
}
]
}
]
}
```
### Expected Behavior
On the first `terraform apply` the resource should be created and the state file should reflect the one shown above. Subsequent calls to `terraform apply` without any changes to resource definition should show no pending changes.
### Actual Behavior
On the first `terraform apply` everything works as expected and the above state file is created (and looks as expected). Subsequent calls to `terraform apply` always show the following pending changes:
```bash
An execution plan has been generated and is shown below.
Resource actions are indicated with the following symbols:
~ update in-place
Terraform will perform the following actions:
2021/01/06 08:53:23 [DEBUG] command: asking for input: "Do you want to perform these actions?"
# guacamole_user.test_user will be updated in-place
~ resource "guacamole_user" "test_user" {
id = "testUser"
# (4 unchanged attributes hidden)
- attributes {
- disabled = false -> null
- expired = false -> null
}
}
Plan: 0 to add, 1 to change, 0 to destroy.
```
This happens every time i do a `terraform apply` even though nothing has changed within the resource definition.
### Steps to Reproduce
1. `terraform init`
2. `terraform apply`
3.
### References
Contributor guide
Research direction
Start with the guacamoleUser schema and the nested attributes block shown in the issue, then reproduce the behavior with the provided main.tf and Terraform state using terraform init and terraform apply. Compare the optional boolean defaults with the plan's disabled and expired changes; done means repeated applies produce no pending changes when the configuration is unchanged.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- go, terraform
- Domain
- tooling
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100