How can I enable / disable a field in a .tf file

I am working on writing a custom provider. For a particular resource I have a field defined in the .tf file host_instance_type. The specific value of host_instance_type determines if another field in the same resource (storage_capacity) value must be set or not. How can I write a condition on the field storage_capacity whose value is determined by the value of host_instance_type ?

You could take a look at this one: https://github.com/hashicorp/terraform/issues/15281#issuecomment-308275154

1 Like

Hi @saloneerege,

The pure validation functionality in the SDK is designed for isolated validation of individual arguments, as I’m sure you’ve seen. Checks that involve interactions between arguments are better to handle as part of planning, because in that case it’s important to consider the situation where an argument’s attribute might not be known until after apply.

You can use the CustomizeDiff field of schema.Resource to add specialized logic during the plan phase. You can return errors from that function to cause planning to fail altogether, if you determine that the configuration is not valid enough to produce a plan.

There are some pre-made composable CustomizeDiff helpers in the customdiff package, but I think this requirement might be specialized enough that it’d be simpler to just write a normal function to represent it. An important thing to consider is what to do if Terraform doesn’t know yet whether a particular argument is set: in that case, the most common answer is to optimistically allow the plan to succeed and then Terraform will re-run the CustomizeDiff function during the apply step (when all of the values are known) and it will get a second opportunity to fail then.

For example:

    CustomizeDiff: func(d *ResourceDiff, meta interface{}) error {
        if !d.NewValueKnown("host_instance_type") {
            // If the host instance type isn't known yet,
            // we must wait until apply time to validate
            // this, when Terraform will call CustomizeDiff
            // again with everything known.
            return nil
        }
        newInstanceType := d.Get("host_instance_type").(string)
        switch newInstanceType {
            case "type1", "type2", "type3":
                if !d.NewValueKnown("storage_capacity") {
                    return nil // can't validate yet
                }
                if d.Get("storage_capacity").(string) != "" {
                    return fmt.Errorf("storage_capacity is not supported for host_instance_type %q", newInstanceType)
                }
            default:
                // All other types support storage_capacity,
                // so there is nothing to check.
                return nil
        }
    }

For most things, allowing the validation to be deferred until apply time is preferable to allow users the flexibility of deriving their argument values from the outputs of other resources. The example above does this by returning nil if it detects that either of the arguments in question have unknown values.

However, in some situations it’s better to be conservative because e.g. a failure during apply is likely to leave things in a severely broken or unsafe state. You can choose to return an error when the relevant arguments are unknown if you think that’s more appropriate, in which case the argument will behave a bit like Terraform’s built-in count and for_each arguments where Terraform will produce an error during planning if those arguments are not sufficiently known to produce a complete plan.

1 Like

Thank you @apparentlymart for the detailed answer. I will implement this !!

@apparentlymart This solution was simple and worked for me