Newer
Older
package utils
import (
"context"
"github.com/hashicorp/terraform-plugin-framework/attr"
"github.com/hashicorp/terraform-plugin-framework/diag"
"github.com/hashicorp/terraform-plugin-framework/path"
"github.com/hashicorp/terraform-plugin-framework/types"
v20230301 "github.com/smallstep/terraform-provider-smallstep/internal/apiclient/v20230301"
)
// These helpers handle conversion from API types to terraform types for
// optional fields. The challenge with optional fields is that they may be
// either null or empty in terraform config, but the API returns nil for
// both. In this case use the value from state to avoid "inconsistent result
// after apply" errors.
// https://github.com/hashicorp/terraform/blob/main/docs/resource-instance-change-lifecycle.md#planresourcechange
func ToOptionalSet(ctx context.Context, remote *[]string, priorState AttributeGetter, p path.Path) (types.Set, diag.Diagnostics) {
if remote == nil || len(*remote) == 0 {
setFromState := types.Set{}
diags := priorState.GetAttribute(ctx, p, &setFromState)
if diags.HasError() {
return types.Set{}, diags
}
if setFromState.IsNull() || len(setFromState.Elements()) == 0 {
return setFromState, diags
}
}
if remote == nil {
return types.SetNull(types.StringType), diag.Diagnostics{}
}
values := make([]attr.Value, len(*remote))
for i, s := range *remote {
values[i] = types.StringValue(s)
}
return types.SetValue(types.StringType, values)
}
func ToOptionalList(ctx context.Context, remote *[]string, priorState AttributeGetter, p path.Path) (types.List, diag.Diagnostics) {
if remote == nil || len(*remote) == 0 {
listFromState := types.List{}
diags := priorState.GetAttribute(ctx, p, &listFromState)
if diags.HasError() {
return types.List{}, diags
}
if listFromState.IsNull() || len(listFromState.Elements()) == 0 {
return listFromState, diags
}
}
if remote == nil {
return types.ListNull(types.StringType), diag.Diagnostics{}
}
values := make([]attr.Value, len(*remote))
for i, s := range *remote {
values[i] = types.StringValue(s)
}
return types.ListValue(types.StringType, values)
}
type Str interface {
string |
v20230301.EndpointKeyInfoFormat |
v20230301.EndpointKeyInfoType
}
func ToOptionalString[S Str](ctx context.Context, remote *S, priorState AttributeGetter, p path.Path) (types.String, diag.Diagnostics) {
if remote == nil || *remote == "" {
stringFromState := types.String{}
diags := priorState.GetAttribute(ctx, p, &stringFromState)
if diags.HasError() {
return types.String{}, diags
}
if stringFromState.IsNull() || stringFromState.ValueString() == "" {
return stringFromState, diags
}
}
if remote == nil {
return types.StringNull(), diag.Diagnostics{}
}
return types.StringValue(string(*remote)), diag.Diagnostics{}
}
func ToOptionalBool(ctx context.Context, remote *bool, priorState AttributeGetter, p path.Path) (types.Bool, diag.Diagnostics) {
if remote == nil || *remote == false {
boolFromState := types.Bool{}
diags := priorState.GetAttribute(ctx, p, &boolFromState)
if diags.HasError() {
return types.Bool{}, diags
}
if boolFromState.IsNull() || boolFromState.ValueBool() == false {
return boolFromState, diags
}
}
if remote == nil {
return types.BoolNull(), diag.Diagnostics{}
}
return types.BoolValue(*remote), diag.Diagnostics{}
}
func ToOptionalInt(ctx context.Context, remote *int, priorState AttributeGetter, p path.Path) (types.Int64, diag.Diagnostics) {
if remote == nil || *remote == 0 {
intFromState := types.Int64{}
diags := priorState.GetAttribute(ctx, p, &intFromState)
if diags.HasError() {
return types.Int64{}, diags
}
if intFromState.IsNull() || intFromState.ValueInt64() == 0 {
return intFromState, diags
}
}
if remote == nil {
return types.Int64Null(), diag.Diagnostics{}
}
return types.Int64Value(int64(*remote)), diag.Diagnostics{}
}