Check if optional attribute is set in .tf file

I am trying to solve this issue. Basically, I need to make sure that if gitlab_project doesn’t have default_branch attribute in .tf file, it is not tracked in state.

  1. What is the proper API call to check that default_branch is absent from .tf?
  2. How to make sure that default_branch is not tracked in the state?

Determining whether a value is in the config or not is a tricky proposition at best right now, and is often functionally not possible. I’ve seen ResourceData.GetChange used to approximate this, on the theory that the “old value” is what’s in state, and the “new value” is what’s in the config, but that’s not foolproof.

Making sure a value is not tracked in state can be achieved by setting it to nil or the empty value in ResourceData.Set, though it is not always valid to do so. The current SDK makes it somewhat opaque as to when it will and will not cause problems; the debug logs should log warnings, however.

1 Like

Regarding behavior of default_branch that is marked as optional. What would be the outcome of ResourceData.GetChange?

.tf GitLab ResourceData.GetChange
- - ?
- “master” ?
“master” - ?
“master” “master” ?

ResourceData.GetChange doesn’t work if optional attribute is not set.

I inserted debug statements after Create finished without setting “default_branch”, and before setting it in Read. ResourceData.GetChange returned two empty strings.

The confusing part came when setting the value of default_branch. The log all of a sudden mentioned null value.

2020-06-19T20:55:55.133+0300 [DEBUG] plugin.terraform-provider-gitlab: 2020/06/19 20:55:55 [DEBUG] d.GetChange default_branch (string) "", (string) ""
2020/06/19 20:55:55 [WARN] Provider "registry.terraform.io/-/gitlab" produced an unexpected new value for gitlab_project.default, but we are tolerating it because it is using the legacy plugin SDK.
    The following problems may be the cause of any confusing errors from downstream operations:
      - .remove_source_branch_after_merge: was null, but now cty.False
      - .description: was null, but now cty.StringVal("")
      - .path: was null, but now cty.StringVal("terraform-empty-project")
      - .default_branch: was null, but now cty.StringVal("")

I also find it confusing that after .default_branch changed from being null to cty.StringVal(""), the subsequent d.GetOk("default_branch") still returns false.

Hey @abitrolly,

Sorry, yeah, this is all confusing. The behavior with an unset field not showing up in GetChange sounds like an optimization somewhere to me–no change was detected, so it isn’t populating the values. That’s the way the method was intended to be used, to detect what the change was when you know there was a change, which is why it’s (unfortunately) not a bulletproof way to detect this kind of information.

The null and empty string stuff is a symptom of the current SDK (which has no concept of null) being layered over the Terraform 0.12 type system (which has the concept of null). This is why GetOk is unreliable; it’s just checking that the value isn’t the empty string, not for null . GetOkExists is sometimes more accurate, but is also leaky and will sometimes not recognize the difference between empty values and unset. Currently, there’s no sure way to do that. That’s something we’re working on, still.