Skip to content

Commit

Permalink
Update logic to check null/unknowness in both the container and under…
Browse files Browse the repository at this point in the history
…lying value
  • Loading branch information
SBGoods committed Feb 13, 2025
1 parent 624dbc4 commit d514911
Showing 1 changed file with 53 additions and 106 deletions.
159 changes: 53 additions & 106 deletions internal/fwserver/attribute_validation.go
Original file line number Diff line number Diff line change
Expand Up @@ -101,96 +101,63 @@ func AttributeValidate(ctx context.Context, a fwschema.Attribute, req ValidateAt
return
}

// Dynamic values need to perform more logic to check the config value for null/unknown-ness
dynamicValuable, ok := attributeConfig.(basetypes.DynamicValuable)
if ok {
configHasNullValue := attributeConfig.IsNull()
configHasUnknownValue := attributeConfig.IsUnknown()
// If the value is dynamic, we still need to check if the underlying value is null or unknown
if dynamicValuable, isDynamic := attributeConfig.(basetypes.DynamicValuable); !configHasNullValue && !configHasUnknownValue && isDynamic {
dynamicConfigVal, diags := dynamicValuable.ToDynamicValue(ctx)
resp.Diagnostics.Append(diags...)
if diags.HasError() {
return
}

// Terraform CLI does not automatically perform certain configuration
// checks yet. If it eventually does, this logic should remain at least
// until Terraform CLI versions 0.12 through the release containing the
// checks are considered end-of-life.
// Reference: https://github.com/hashicorp/terraform/issues/30669
if a.IsComputed() && !a.IsOptional() && !dynamicConfigVal.IsUnderlyingValueNull() {
resp.Diagnostics.AddAttributeError(
req.AttributePath,
"Invalid Configuration for Read-Only Attribute",
"Cannot set value for this attribute as the provider has marked it as read-only. Remove the configuration line setting the value.\n\n"+
"Refer to the provider documentation or contact the provider developers for additional information about configurable and read-only attributes that are supported.",
)
if dynamicConfigVal.IsUnderlyingValueNull() {
configHasNullValue = true
}

// Terraform CLI does not automatically perform certain configuration
// checks yet. If it eventually does, this logic should remain at least
// until Terraform CLI versions 0.12 through the release containing the
// checks are considered end-of-life.
// Reference: https://github.com/hashicorp/terraform/issues/30669
if a.IsRequired() && dynamicConfigVal.IsUnderlyingValueNull() {
resp.Diagnostics.AddAttributeError(
req.AttributePath,
"Missing Configuration for Required Attribute",
fmt.Sprintf("Must set a configuration value for the %s attribute as the provider has marked it as required.\n\n", req.AttributePath.String())+
"Refer to the provider documentation or contact the provider developers for additional information about configurable attributes that are required.",
)
if dynamicConfigVal.IsUnderlyingValueUnknown() {
configHasUnknownValue = true
}
}

// If the client doesn't support write-only attributes (first supported in Terraform v1.11.0), then we raise an early validation error
// to avoid a confusing data consistency error when the provider attempts to return "null" for a write-only attribute in the planned/final state.
//
// Write-only attributes can only be successfully used with a supporting client, so the only option for a practitoner to utilize a write-only attribute
// is to upgrade their Terraform CLI version to v1.11.0 or later.
if !req.ClientCapabilities.WriteOnlyAttributesAllowed && a.IsWriteOnly() && !dynamicConfigVal.IsUnderlyingValueNull() {
resp.Diagnostics.AddAttributeError(
req.AttributePath,
"WriteOnly Attribute Not Allowed",
fmt.Sprintf("The resource contains a non-null value for WriteOnly attribute %s. Write-only attributes are only supported in Terraform 1.11 and later.", req.AttributePath.String()),
)
}
} else {
// Terraform CLI does not automatically perform certain configuration
// checks yet. If it eventually does, this logic should remain at least
// until Terraform CLI versions 0.12 through the release containing the
// checks are considered end-of-life.
// Reference: https://github.com/hashicorp/terraform/issues/30669
if a.IsComputed() && !a.IsOptional() && !attributeConfig.IsNull() {
resp.Diagnostics.AddAttributeError(
req.AttributePath,
"Invalid Configuration for Read-Only Attribute",
"Cannot set value for this attribute as the provider has marked it as read-only. Remove the configuration line setting the value.\n\n"+
"Refer to the provider documentation or contact the provider developers for additional information about configurable and read-only attributes that are supported.",
)
}
// Terraform CLI does not automatically perform certain configuration
// checks yet. If it eventually does, this logic should remain at least
// until Terraform CLI versions 0.12 through the release containing the
// checks are considered end-of-life.
// Reference: https://github.com/hashicorp/terraform/issues/30669
if a.IsComputed() && !a.IsOptional() && !configHasNullValue {
resp.Diagnostics.AddAttributeError(
req.AttributePath,
"Invalid Configuration for Read-Only Attribute",
"Cannot set value for this attribute as the provider has marked it as read-only. Remove the configuration line setting the value.\n\n"+
"Refer to the provider documentation or contact the provider developers for additional information about configurable and read-only attributes that are supported.",
)
}

// Terraform CLI does not automatically perform certain configuration
// checks yet. If it eventually does, this logic should remain at least
// until Terraform CLI versions 0.12 through the release containing the
// checks are considered end-of-life.
// Reference: https://github.com/hashicorp/terraform/issues/30669
if a.IsRequired() && attributeConfig.IsNull() {
resp.Diagnostics.AddAttributeError(
req.AttributePath,
"Missing Configuration for Required Attribute",
fmt.Sprintf("Must set a configuration value for the %s attribute as the provider has marked it as required.\n\n", req.AttributePath.String())+
"Refer to the provider documentation or contact the provider developers for additional information about configurable attributes that are required.",
)
}
// Terraform CLI does not automatically perform certain configuration
// checks yet. If it eventually does, this logic should remain at least
// until Terraform CLI versions 0.12 through the release containing the
// checks are considered end-of-life.
// Reference: https://github.com/hashicorp/terraform/issues/30669
if a.IsRequired() && configHasNullValue {
resp.Diagnostics.AddAttributeError(
req.AttributePath,
"Missing Configuration for Required Attribute",
fmt.Sprintf("Must set a configuration value for the %s attribute as the provider has marked it as required.\n\n", req.AttributePath.String())+
"Refer to the provider documentation or contact the provider developers for additional information about configurable attributes that are required.",
)
}

// If the client doesn't support write-only attributes (first supported in Terraform v1.11.0), then we raise an early validation error
// to avoid a confusing data consistency error when the provider attempts to return "null" for a write-only attribute in the planned/final state.
//
// Write-only attributes can only be successfully used with a supporting client, so the only option for a practitoner to utilize a write-only attribute
// is to upgrade their Terraform CLI version to v1.11.0 or later.
if !req.ClientCapabilities.WriteOnlyAttributesAllowed && a.IsWriteOnly() && !attributeConfig.IsNull() {
resp.Diagnostics.AddAttributeError(
req.AttributePath,
"WriteOnly Attribute Not Allowed",
fmt.Sprintf("The resource contains a non-null value for WriteOnly attribute %s. Write-only attributes are only supported in Terraform 1.11 and later.", req.AttributePath.String()),
)
}
// If the client doesn't support write-only attributes (first supported in Terraform v1.11.0), then we raise an early validation error
// to avoid a confusing data consistency error when the provider attempts to return "null" for a write-only attribute in the planned/final state.
//
// Write-only attributes can only be successfully used with a supporting client, so the only option for a practitoner to utilize a write-only attribute
// is to upgrade their Terraform CLI version to v1.11.0 or later.
if !req.ClientCapabilities.WriteOnlyAttributesAllowed && a.IsWriteOnly() && !configHasNullValue {
resp.Diagnostics.AddAttributeError(
req.AttributePath,
"WriteOnly Attribute Not Allowed",
fmt.Sprintf("The resource contains a non-null value for WriteOnly attribute %s. Write-only attributes are only supported in Terraform 1.11 and later.", req.AttributePath.String()),
)
}
req.AttributeConfig = attributeConfig

Expand Down Expand Up @@ -224,33 +191,13 @@ func AttributeValidate(ctx context.Context, a fwschema.Attribute, req ValidateAt
AttributeValidateNestedAttributes(ctx, a, req, resp)

// Show deprecation warnings only for known values.
if a.GetDeprecationMessage() != "" && !attributeConfig.IsNull() && !attributeConfig.IsUnknown() {
// Dynamic values need to perform more logic to check the config value for null/unknown-ness
dynamicValuable, ok := attributeConfig.(basetypes.DynamicValuable)
if !ok {
resp.Diagnostics.AddAttributeWarning(
req.AttributePath,
"Attribute Deprecated",
a.GetDeprecationMessage(),
)
return
}

dynamicConfigVal, diags := dynamicValuable.ToDynamicValue(ctx)
resp.Diagnostics.Append(diags...)
if diags.HasError() {
return
}

// For dynamic values, it's possible to be known when only the type is known.
// The underlying value can still be null or unknown, so check for that here
if !dynamicConfigVal.IsUnderlyingValueNull() && !dynamicConfigVal.IsUnderlyingValueUnknown() {
resp.Diagnostics.AddAttributeWarning(
req.AttributePath,
"Attribute Deprecated",
a.GetDeprecationMessage(),
)
}
if a.GetDeprecationMessage() != "" && !configHasNullValue && !configHasUnknownValue {
resp.Diagnostics.AddAttributeWarning(
req.AttributePath,
"Attribute Deprecated",
a.GetDeprecationMessage(),
)
return
}
}

Expand Down

0 comments on commit d514911

Please sign in to comment.