// Code generated by terraform-plugin-framework-generator DO NOT EDIT. package temp import ( "context" "fmt" "github.com/hashicorp/terraform-plugin-framework-validators/int64validator" "github.com/hashicorp/terraform-plugin-framework-validators/stringvalidator" "github.com/hashicorp/terraform-plugin-framework/attr" "github.com/hashicorp/terraform-plugin-framework/diag" "github.com/hashicorp/terraform-plugin-framework/resource/schema/stringdefault" "github.com/hashicorp/terraform-plugin-framework/schema/validator" "github.com/hashicorp/terraform-plugin-framework/types" "github.com/hashicorp/terraform-plugin-framework/types/basetypes" "github.com/hashicorp/terraform-plugin-go/tftypes" "strings" "github.com/hashicorp/terraform-plugin-framework/resource/schema" ) func InstanceResourceSchema(ctx context.Context) schema.Schema { return schema.Schema{ Attributes: map[string]schema.Attribute{ "backup_schedule": schema.StringAttribute{ Required: true, Description: "The schedule for on what time and how often the database backup will be created. The schedule is written as a cron schedule.", MarkdownDescription: "The schedule for on what time and how often the database backup will be created. The schedule is written as a cron schedule.", }, "encryption": schema.SingleNestedAttribute{ Attributes: map[string]schema.Attribute{ "kek_key_id": schema.StringAttribute{ Required: true, Description: "The encryption-key key identifier", MarkdownDescription: "The encryption-key key identifier", }, "kek_key_ring_id": schema.StringAttribute{ Required: true, Description: "The encryption-key keyring identifier", MarkdownDescription: "The encryption-key keyring identifier", }, "kek_key_version": schema.StringAttribute{ Required: true, Description: "The encryption-key version", MarkdownDescription: "The encryption-key version", }, "service_account": schema.StringAttribute{ Required: true, }, }, CustomType: EncryptionType{ ObjectType: types.ObjectType{ AttrTypes: EncryptionValue{}.AttributeTypes(ctx), }, }, Optional: true, Computed: true, Description: "The configuration for instance's volume and backup storage encryption.\n\n⚠️ **Note:** This feature is in private preview. Supplying this object is only permitted for enabled accounts. If your account does not have access, the request will be rejected.\n", MarkdownDescription: "The configuration for instance's volume and backup storage encryption.\n\n⚠️ **Note:** This feature is in private preview. Supplying this object is only permitted for enabled accounts. If your account does not have access, the request will be rejected.\n", }, "flavor_id": schema.StringAttribute{ Required: true, Description: "The id of the instance flavor.", MarkdownDescription: "The id of the instance flavor.", }, "id": schema.StringAttribute{ Computed: true, Description: "The ID of the instance.", MarkdownDescription: "The ID of the instance.", }, "instance_id": schema.StringAttribute{ Optional: true, Computed: true, Description: "The ID of the instance.", MarkdownDescription: "The ID of the instance.", }, "is_deletable": schema.BoolAttribute{ Computed: true, Description: "Whether the instance can be deleted or not.", MarkdownDescription: "Whether the instance can be deleted or not.", }, "name": schema.StringAttribute{ Required: true, Description: "The name of the instance.", MarkdownDescription: "The name of the instance.", }, "network": schema.SingleNestedAttribute{ Attributes: map[string]schema.Attribute{ "access_scope": schema.StringAttribute{ Optional: true, Computed: true, Description: "The access scope of the instance. It defines if the instance is public or airgapped.", MarkdownDescription: "The access scope of the instance. It defines if the instance is public or airgapped.", Validators: []validator.String{ stringvalidator.OneOf( "PUBLIC", "SNA", ), }, Default: stringdefault.StaticString("PUBLIC"), }, "acl": schema.ListAttribute{ ElementType: types.StringType, Required: true, Description: "List of IPV4 cidr.", MarkdownDescription: "List of IPV4 cidr.", }, "instance_address": schema.StringAttribute{ Optional: true, Computed: true, }, "router_address": schema.StringAttribute{ Optional: true, Computed: true, }, }, CustomType: NetworkType{ ObjectType: types.ObjectType{ AttrTypes: NetworkValue{}.AttributeTypes(ctx), }, }, Required: true, Description: "The access configuration of the instance", MarkdownDescription: "The access configuration of the instance", }, "project_id": schema.StringAttribute{ Optional: true, Computed: true, Description: "The STACKIT project ID.", MarkdownDescription: "The STACKIT project ID.", }, "region": schema.StringAttribute{ Optional: true, Computed: true, Description: "The region which should be addressed", MarkdownDescription: "The region which should be addressed", Validators: []validator.String{ stringvalidator.OneOf( "eu01", ), }, }, "replicas": schema.Int64Attribute{ Required: true, Description: "How many replicas the instance should have.", MarkdownDescription: "How many replicas the instance should have.", Validators: []validator.Int64{ int64validator.OneOf( 1, 3, ), }, }, "retention_days": schema.Int64Attribute{ Required: true, Description: "How long backups are retained. The value can only be between 32 and 365 days.", MarkdownDescription: "How long backups are retained. The value can only be between 32 and 365 days.", }, "status": schema.StringAttribute{ Computed: true, Description: "The current status of the instance.", MarkdownDescription: "The current status of the instance.", }, "storage": schema.SingleNestedAttribute{ Attributes: map[string]schema.Attribute{ "performance_class": schema.StringAttribute{ Required: true, Description: "The storage class for the storage.", MarkdownDescription: "The storage class for the storage.", }, "size": schema.Int64Attribute{ Required: true, Description: "The storage size in Gigabytes.", MarkdownDescription: "The storage size in Gigabytes.", }, }, CustomType: StorageType{ ObjectType: types.ObjectType{ AttrTypes: StorageValue{}.AttributeTypes(ctx), }, }, Required: true, Description: "The object containing information about the storage size and class.", MarkdownDescription: "The object containing information about the storage size and class.", }, "version": schema.StringAttribute{ Required: true, Description: "The Postgres version used for the instance. See [Versions Endpoint](/documentation/postgres-flex-service/version/v3alpha1#tag/Version) for supported version parameters.", MarkdownDescription: "The Postgres version used for the instance. See [Versions Endpoint](/documentation/postgres-flex-service/version/v3alpha1#tag/Version) for supported version parameters.", }, }, } } type InstanceModel struct { BackupSchedule types.String `tfsdk:"backup_schedule"` Encryption EncryptionValue `tfsdk:"encryption"` FlavorId types.String `tfsdk:"flavor_id"` Id types.String `tfsdk:"id"` InstanceId types.String `tfsdk:"instance_id"` IsDeletable types.Bool `tfsdk:"is_deletable"` Name types.String `tfsdk:"name"` Network NetworkValue `tfsdk:"network"` ProjectId types.String `tfsdk:"project_id"` Region types.String `tfsdk:"region"` Replicas types.Int64 `tfsdk:"replicas"` RetentionDays types.Int64 `tfsdk:"retention_days"` Status types.String `tfsdk:"status"` Storage StorageValue `tfsdk:"storage"` Version types.String `tfsdk:"version"` } var _ basetypes.ObjectTypable = EncryptionType{} type EncryptionType struct { basetypes.ObjectType } func (t EncryptionType) Equal(o attr.Type) bool { other, ok := o.(EncryptionType) if !ok { return false } return t.ObjectType.Equal(other.ObjectType) } func (t EncryptionType) String() string { return "EncryptionType" } func (t EncryptionType) ValueFromObject(ctx context.Context, in basetypes.ObjectValue) (basetypes.ObjectValuable, diag.Diagnostics) { var diags diag.Diagnostics attributes := in.Attributes() kekKeyIdAttribute, ok := attributes["kek_key_id"] if !ok { diags.AddError( "Attribute Missing", `kek_key_id is missing from object`) return nil, diags } kekKeyIdVal, ok := kekKeyIdAttribute.(basetypes.StringValue) if !ok { diags.AddError( "Attribute Wrong Type", fmt.Sprintf(`kek_key_id expected to be basetypes.StringValue, was: %T`, kekKeyIdAttribute)) } kekKeyRingIdAttribute, ok := attributes["kek_key_ring_id"] if !ok { diags.AddError( "Attribute Missing", `kek_key_ring_id is missing from object`) return nil, diags } kekKeyRingIdVal, ok := kekKeyRingIdAttribute.(basetypes.StringValue) if !ok { diags.AddError( "Attribute Wrong Type", fmt.Sprintf(`kek_key_ring_id expected to be basetypes.StringValue, was: %T`, kekKeyRingIdAttribute)) } kekKeyVersionAttribute, ok := attributes["kek_key_version"] if !ok { diags.AddError( "Attribute Missing", `kek_key_version is missing from object`) return nil, diags } kekKeyVersionVal, ok := kekKeyVersionAttribute.(basetypes.StringValue) if !ok { diags.AddError( "Attribute Wrong Type", fmt.Sprintf(`kek_key_version expected to be basetypes.StringValue, was: %T`, kekKeyVersionAttribute)) } serviceAccountAttribute, ok := attributes["service_account"] if !ok { diags.AddError( "Attribute Missing", `service_account is missing from object`) return nil, diags } serviceAccountVal, ok := serviceAccountAttribute.(basetypes.StringValue) if !ok { diags.AddError( "Attribute Wrong Type", fmt.Sprintf(`service_account expected to be basetypes.StringValue, was: %T`, serviceAccountAttribute)) } if diags.HasError() { return nil, diags } return EncryptionValue{ KekKeyId: kekKeyIdVal, KekKeyRingId: kekKeyRingIdVal, KekKeyVersion: kekKeyVersionVal, ServiceAccount: serviceAccountVal, state: attr.ValueStateKnown, }, diags } func NewEncryptionValueNull() EncryptionValue { return EncryptionValue{ state: attr.ValueStateNull, } } func NewEncryptionValueUnknown() EncryptionValue { return EncryptionValue{ state: attr.ValueStateUnknown, } } func NewEncryptionValue(attributeTypes map[string]attr.Type, attributes map[string]attr.Value) (EncryptionValue, diag.Diagnostics) { var diags diag.Diagnostics // Reference: https://github.com/hashicorp/terraform-plugin-framework/issues/521 ctx := context.Background() for name, attributeType := range attributeTypes { attribute, ok := attributes[name] if !ok { diags.AddError( "Missing EncryptionValue Attribute Value", "While creating a EncryptionValue value, a missing attribute value was detected. "+ "A EncryptionValue must contain values for all attributes, even if null or unknown. "+ "This is always an issue with the provider and should be reported to the provider developers.\n\n"+ fmt.Sprintf("EncryptionValue Attribute Name (%s) Expected Type: %s", name, attributeType.String()), ) continue } if !attributeType.Equal(attribute.Type(ctx)) { diags.AddError( "Invalid EncryptionValue Attribute Type", "While creating a EncryptionValue value, an invalid attribute value was detected. "+ "A EncryptionValue must use a matching attribute type for the value. "+ "This is always an issue with the provider and should be reported to the provider developers.\n\n"+ fmt.Sprintf("EncryptionValue Attribute Name (%s) Expected Type: %s\n", name, attributeType.String())+ fmt.Sprintf("EncryptionValue Attribute Name (%s) Given Type: %s", name, attribute.Type(ctx)), ) } } for name := range attributes { _, ok := attributeTypes[name] if !ok { diags.AddError( "Extra EncryptionValue Attribute Value", "While creating a EncryptionValue value, an extra attribute value was detected. "+ "A EncryptionValue must not contain values beyond the expected attribute types. "+ "This is always an issue with the provider and should be reported to the provider developers.\n\n"+ fmt.Sprintf("Extra EncryptionValue Attribute Name: %s", name), ) } } if diags.HasError() { return NewEncryptionValueUnknown(), diags } kekKeyIdAttribute, ok := attributes["kek_key_id"] if !ok { diags.AddError( "Attribute Missing", `kek_key_id is missing from object`) return NewEncryptionValueUnknown(), diags } kekKeyIdVal, ok := kekKeyIdAttribute.(basetypes.StringValue) if !ok { diags.AddError( "Attribute Wrong Type", fmt.Sprintf(`kek_key_id expected to be basetypes.StringValue, was: %T`, kekKeyIdAttribute)) } kekKeyRingIdAttribute, ok := attributes["kek_key_ring_id"] if !ok { diags.AddError( "Attribute Missing", `kek_key_ring_id is missing from object`) return NewEncryptionValueUnknown(), diags } kekKeyRingIdVal, ok := kekKeyRingIdAttribute.(basetypes.StringValue) if !ok { diags.AddError( "Attribute Wrong Type", fmt.Sprintf(`kek_key_ring_id expected to be basetypes.StringValue, was: %T`, kekKeyRingIdAttribute)) } kekKeyVersionAttribute, ok := attributes["kek_key_version"] if !ok { diags.AddError( "Attribute Missing", `kek_key_version is missing from object`) return NewEncryptionValueUnknown(), diags } kekKeyVersionVal, ok := kekKeyVersionAttribute.(basetypes.StringValue) if !ok { diags.AddError( "Attribute Wrong Type", fmt.Sprintf(`kek_key_version expected to be basetypes.StringValue, was: %T`, kekKeyVersionAttribute)) } serviceAccountAttribute, ok := attributes["service_account"] if !ok { diags.AddError( "Attribute Missing", `service_account is missing from object`) return NewEncryptionValueUnknown(), diags } serviceAccountVal, ok := serviceAccountAttribute.(basetypes.StringValue) if !ok { diags.AddError( "Attribute Wrong Type", fmt.Sprintf(`service_account expected to be basetypes.StringValue, was: %T`, serviceAccountAttribute)) } if diags.HasError() { return NewEncryptionValueUnknown(), diags } return EncryptionValue{ KekKeyId: kekKeyIdVal, KekKeyRingId: kekKeyRingIdVal, KekKeyVersion: kekKeyVersionVal, ServiceAccount: serviceAccountVal, state: attr.ValueStateKnown, }, diags } func NewEncryptionValueMust(attributeTypes map[string]attr.Type, attributes map[string]attr.Value) EncryptionValue { object, diags := NewEncryptionValue(attributeTypes, attributes) if diags.HasError() { // This could potentially be added to the diag package. diagsStrings := make([]string, 0, len(diags)) for _, diagnostic := range diags { diagsStrings = append(diagsStrings, fmt.Sprintf( "%s | %s | %s", diagnostic.Severity(), diagnostic.Summary(), diagnostic.Detail())) } panic("NewEncryptionValueMust received error(s): " + strings.Join(diagsStrings, "\n")) } return object } func (t EncryptionType) ValueFromTerraform(ctx context.Context, in tftypes.Value) (attr.Value, error) { if in.Type() == nil { return NewEncryptionValueNull(), nil } if !in.Type().Equal(t.TerraformType(ctx)) { return nil, fmt.Errorf("expected %s, got %s", t.TerraformType(ctx), in.Type()) } if !in.IsKnown() { return NewEncryptionValueUnknown(), nil } if in.IsNull() { return NewEncryptionValueNull(), nil } attributes := map[string]attr.Value{} val := map[string]tftypes.Value{} err := in.As(&val) if err != nil { return nil, err } for k, v := range val { a, err := t.AttrTypes[k].ValueFromTerraform(ctx, v) if err != nil { return nil, err } attributes[k] = a } return NewEncryptionValueMust(EncryptionValue{}.AttributeTypes(ctx), attributes), nil } func (t EncryptionType) ValueType(ctx context.Context) attr.Value { return EncryptionValue{} } var _ basetypes.ObjectValuable = EncryptionValue{} type EncryptionValue struct { KekKeyId basetypes.StringValue `tfsdk:"kek_key_id"` KekKeyRingId basetypes.StringValue `tfsdk:"kek_key_ring_id"` KekKeyVersion basetypes.StringValue `tfsdk:"kek_key_version"` ServiceAccount basetypes.StringValue `tfsdk:"service_account"` state attr.ValueState } func (v EncryptionValue) ToTerraformValue(ctx context.Context) (tftypes.Value, error) { attrTypes := make(map[string]tftypes.Type, 4) var val tftypes.Value var err error attrTypes["kek_key_id"] = basetypes.StringType{}.TerraformType(ctx) attrTypes["kek_key_ring_id"] = basetypes.StringType{}.TerraformType(ctx) attrTypes["kek_key_version"] = basetypes.StringType{}.TerraformType(ctx) attrTypes["service_account"] = basetypes.StringType{}.TerraformType(ctx) objectType := tftypes.Object{AttributeTypes: attrTypes} switch v.state { case attr.ValueStateKnown: vals := make(map[string]tftypes.Value, 4) val, err = v.KekKeyId.ToTerraformValue(ctx) if err != nil { return tftypes.NewValue(objectType, tftypes.UnknownValue), err } vals["kek_key_id"] = val val, err = v.KekKeyRingId.ToTerraformValue(ctx) if err != nil { return tftypes.NewValue(objectType, tftypes.UnknownValue), err } vals["kek_key_ring_id"] = val val, err = v.KekKeyVersion.ToTerraformValue(ctx) if err != nil { return tftypes.NewValue(objectType, tftypes.UnknownValue), err } vals["kek_key_version"] = val val, err = v.ServiceAccount.ToTerraformValue(ctx) if err != nil { return tftypes.NewValue(objectType, tftypes.UnknownValue), err } vals["service_account"] = val if err := tftypes.ValidateValue(objectType, vals); err != nil { return tftypes.NewValue(objectType, tftypes.UnknownValue), err } return tftypes.NewValue(objectType, vals), nil case attr.ValueStateNull: return tftypes.NewValue(objectType, nil), nil case attr.ValueStateUnknown: return tftypes.NewValue(objectType, tftypes.UnknownValue), nil default: panic(fmt.Sprintf("unhandled Object state in ToTerraformValue: %s", v.state)) } } func (v EncryptionValue) IsNull() bool { return v.state == attr.ValueStateNull } func (v EncryptionValue) IsUnknown() bool { return v.state == attr.ValueStateUnknown } func (v EncryptionValue) String() string { return "EncryptionValue" } func (v EncryptionValue) ToObjectValue(ctx context.Context) (basetypes.ObjectValue, diag.Diagnostics) { var diags diag.Diagnostics attributeTypes := map[string]attr.Type{ "kek_key_id": basetypes.StringType{}, "kek_key_ring_id": basetypes.StringType{}, "kek_key_version": basetypes.StringType{}, "service_account": basetypes.StringType{}, } if v.IsNull() { return types.ObjectNull(attributeTypes), diags } if v.IsUnknown() { return types.ObjectUnknown(attributeTypes), diags } objVal, diags := types.ObjectValue( attributeTypes, map[string]attr.Value{ "kek_key_id": v.KekKeyId, "kek_key_ring_id": v.KekKeyRingId, "kek_key_version": v.KekKeyVersion, "service_account": v.ServiceAccount, }) return objVal, diags } func (v EncryptionValue) Equal(o attr.Value) bool { other, ok := o.(EncryptionValue) if !ok { return false } if v.state != other.state { return false } if v.state != attr.ValueStateKnown { return true } if !v.KekKeyId.Equal(other.KekKeyId) { return false } if !v.KekKeyRingId.Equal(other.KekKeyRingId) { return false } if !v.KekKeyVersion.Equal(other.KekKeyVersion) { return false } if !v.ServiceAccount.Equal(other.ServiceAccount) { return false } return true } func (v EncryptionValue) Type(ctx context.Context) attr.Type { return EncryptionType{ basetypes.ObjectType{ AttrTypes: v.AttributeTypes(ctx), }, } } func (v EncryptionValue) AttributeTypes(ctx context.Context) map[string]attr.Type { return map[string]attr.Type{ "kek_key_id": basetypes.StringType{}, "kek_key_ring_id": basetypes.StringType{}, "kek_key_version": basetypes.StringType{}, "service_account": basetypes.StringType{}, } } var _ basetypes.ObjectTypable = NetworkType{} type NetworkType struct { basetypes.ObjectType } func (t NetworkType) Equal(o attr.Type) bool { other, ok := o.(NetworkType) if !ok { return false } return t.ObjectType.Equal(other.ObjectType) } func (t NetworkType) String() string { return "NetworkType" } func (t NetworkType) ValueFromObject(ctx context.Context, in basetypes.ObjectValue) (basetypes.ObjectValuable, diag.Diagnostics) { var diags diag.Diagnostics attributes := in.Attributes() accessScopeAttribute, ok := attributes["access_scope"] if !ok { diags.AddError( "Attribute Missing", `access_scope is missing from object`) return nil, diags } accessScopeVal, ok := accessScopeAttribute.(basetypes.StringValue) if !ok { diags.AddError( "Attribute Wrong Type", fmt.Sprintf(`access_scope expected to be basetypes.StringValue, was: %T`, accessScopeAttribute)) } aclAttribute, ok := attributes["acl"] if !ok { diags.AddError( "Attribute Missing", `acl is missing from object`) return nil, diags } aclVal, ok := aclAttribute.(basetypes.ListValue) if !ok { diags.AddError( "Attribute Wrong Type", fmt.Sprintf(`acl expected to be basetypes.ListValue, was: %T`, aclAttribute)) } instanceAddressAttribute, ok := attributes["instance_address"] if !ok { diags.AddError( "Attribute Missing", `instance_address is missing from object`) return nil, diags } instanceAddressVal, ok := instanceAddressAttribute.(basetypes.StringValue) if !ok { diags.AddError( "Attribute Wrong Type", fmt.Sprintf(`instance_address expected to be basetypes.StringValue, was: %T`, instanceAddressAttribute)) } routerAddressAttribute, ok := attributes["router_address"] if !ok { diags.AddError( "Attribute Missing", `router_address is missing from object`) return nil, diags } routerAddressVal, ok := routerAddressAttribute.(basetypes.StringValue) if !ok { diags.AddError( "Attribute Wrong Type", fmt.Sprintf(`router_address expected to be basetypes.StringValue, was: %T`, routerAddressAttribute)) } if diags.HasError() { return nil, diags } return NetworkValue{ AccessScope: accessScopeVal, Acl: aclVal, InstanceAddress: instanceAddressVal, RouterAddress: routerAddressVal, state: attr.ValueStateKnown, }, diags } func NewNetworkValueNull() NetworkValue { return NetworkValue{ state: attr.ValueStateNull, } } func NewNetworkValueUnknown() NetworkValue { return NetworkValue{ state: attr.ValueStateUnknown, } } func NewNetworkValue(attributeTypes map[string]attr.Type, attributes map[string]attr.Value) (NetworkValue, diag.Diagnostics) { var diags diag.Diagnostics // Reference: https://github.com/hashicorp/terraform-plugin-framework/issues/521 ctx := context.Background() for name, attributeType := range attributeTypes { attribute, ok := attributes[name] if !ok { diags.AddError( "Missing NetworkValue Attribute Value", "While creating a NetworkValue value, a missing attribute value was detected. "+ "A NetworkValue must contain values for all attributes, even if null or unknown. "+ "This is always an issue with the provider and should be reported to the provider developers.\n\n"+ fmt.Sprintf("NetworkValue Attribute Name (%s) Expected Type: %s", name, attributeType.String()), ) continue } if !attributeType.Equal(attribute.Type(ctx)) { diags.AddError( "Invalid NetworkValue Attribute Type", "While creating a NetworkValue value, an invalid attribute value was detected. "+ "A NetworkValue must use a matching attribute type for the value. "+ "This is always an issue with the provider and should be reported to the provider developers.\n\n"+ fmt.Sprintf("NetworkValue Attribute Name (%s) Expected Type: %s\n", name, attributeType.String())+ fmt.Sprintf("NetworkValue Attribute Name (%s) Given Type: %s", name, attribute.Type(ctx)), ) } } for name := range attributes { _, ok := attributeTypes[name] if !ok { diags.AddError( "Extra NetworkValue Attribute Value", "While creating a NetworkValue value, an extra attribute value was detected. "+ "A NetworkValue must not contain values beyond the expected attribute types. "+ "This is always an issue with the provider and should be reported to the provider developers.\n\n"+ fmt.Sprintf("Extra NetworkValue Attribute Name: %s", name), ) } } if diags.HasError() { return NewNetworkValueUnknown(), diags } accessScopeAttribute, ok := attributes["access_scope"] if !ok { diags.AddError( "Attribute Missing", `access_scope is missing from object`) return NewNetworkValueUnknown(), diags } accessScopeVal, ok := accessScopeAttribute.(basetypes.StringValue) if !ok { diags.AddError( "Attribute Wrong Type", fmt.Sprintf(`access_scope expected to be basetypes.StringValue, was: %T`, accessScopeAttribute)) } aclAttribute, ok := attributes["acl"] if !ok { diags.AddError( "Attribute Missing", `acl is missing from object`) return NewNetworkValueUnknown(), diags } aclVal, ok := aclAttribute.(basetypes.ListValue) if !ok { diags.AddError( "Attribute Wrong Type", fmt.Sprintf(`acl expected to be basetypes.ListValue, was: %T`, aclAttribute)) } instanceAddressAttribute, ok := attributes["instance_address"] if !ok { diags.AddError( "Attribute Missing", `instance_address is missing from object`) return NewNetworkValueUnknown(), diags } instanceAddressVal, ok := instanceAddressAttribute.(basetypes.StringValue) if !ok { diags.AddError( "Attribute Wrong Type", fmt.Sprintf(`instance_address expected to be basetypes.StringValue, was: %T`, instanceAddressAttribute)) } routerAddressAttribute, ok := attributes["router_address"] if !ok { diags.AddError( "Attribute Missing", `router_address is missing from object`) return NewNetworkValueUnknown(), diags } routerAddressVal, ok := routerAddressAttribute.(basetypes.StringValue) if !ok { diags.AddError( "Attribute Wrong Type", fmt.Sprintf(`router_address expected to be basetypes.StringValue, was: %T`, routerAddressAttribute)) } if diags.HasError() { return NewNetworkValueUnknown(), diags } return NetworkValue{ AccessScope: accessScopeVal, Acl: aclVal, InstanceAddress: instanceAddressVal, RouterAddress: routerAddressVal, state: attr.ValueStateKnown, }, diags } func NewNetworkValueMust(attributeTypes map[string]attr.Type, attributes map[string]attr.Value) NetworkValue { object, diags := NewNetworkValue(attributeTypes, attributes) if diags.HasError() { // This could potentially be added to the diag package. diagsStrings := make([]string, 0, len(diags)) for _, diagnostic := range diags { diagsStrings = append(diagsStrings, fmt.Sprintf( "%s | %s | %s", diagnostic.Severity(), diagnostic.Summary(), diagnostic.Detail())) } panic("NewNetworkValueMust received error(s): " + strings.Join(diagsStrings, "\n")) } return object } func (t NetworkType) ValueFromTerraform(ctx context.Context, in tftypes.Value) (attr.Value, error) { if in.Type() == nil { return NewNetworkValueNull(), nil } if !in.Type().Equal(t.TerraformType(ctx)) { return nil, fmt.Errorf("expected %s, got %s", t.TerraformType(ctx), in.Type()) } if !in.IsKnown() { return NewNetworkValueUnknown(), nil } if in.IsNull() { return NewNetworkValueNull(), nil } attributes := map[string]attr.Value{} val := map[string]tftypes.Value{} err := in.As(&val) if err != nil { return nil, err } for k, v := range val { a, err := t.AttrTypes[k].ValueFromTerraform(ctx, v) if err != nil { return nil, err } attributes[k] = a } return NewNetworkValueMust(NetworkValue{}.AttributeTypes(ctx), attributes), nil } func (t NetworkType) ValueType(ctx context.Context) attr.Value { return NetworkValue{} } var _ basetypes.ObjectValuable = NetworkValue{} type NetworkValue struct { AccessScope basetypes.StringValue `tfsdk:"access_scope"` Acl basetypes.ListValue `tfsdk:"acl"` InstanceAddress basetypes.StringValue `tfsdk:"instance_address"` RouterAddress basetypes.StringValue `tfsdk:"router_address"` state attr.ValueState } func (v NetworkValue) ToTerraformValue(ctx context.Context) (tftypes.Value, error) { attrTypes := make(map[string]tftypes.Type, 4) var val tftypes.Value var err error attrTypes["access_scope"] = basetypes.StringType{}.TerraformType(ctx) attrTypes["acl"] = basetypes.ListType{ ElemType: types.StringType, }.TerraformType(ctx) attrTypes["instance_address"] = basetypes.StringType{}.TerraformType(ctx) attrTypes["router_address"] = basetypes.StringType{}.TerraformType(ctx) objectType := tftypes.Object{AttributeTypes: attrTypes} switch v.state { case attr.ValueStateKnown: vals := make(map[string]tftypes.Value, 4) val, err = v.AccessScope.ToTerraformValue(ctx) if err != nil { return tftypes.NewValue(objectType, tftypes.UnknownValue), err } vals["access_scope"] = val val, err = v.Acl.ToTerraformValue(ctx) if err != nil { return tftypes.NewValue(objectType, tftypes.UnknownValue), err } vals["acl"] = val val, err = v.InstanceAddress.ToTerraformValue(ctx) if err != nil { return tftypes.NewValue(objectType, tftypes.UnknownValue), err } vals["instance_address"] = val val, err = v.RouterAddress.ToTerraformValue(ctx) if err != nil { return tftypes.NewValue(objectType, tftypes.UnknownValue), err } vals["router_address"] = val if err := tftypes.ValidateValue(objectType, vals); err != nil { return tftypes.NewValue(objectType, tftypes.UnknownValue), err } return tftypes.NewValue(objectType, vals), nil case attr.ValueStateNull: return tftypes.NewValue(objectType, nil), nil case attr.ValueStateUnknown: return tftypes.NewValue(objectType, tftypes.UnknownValue), nil default: panic(fmt.Sprintf("unhandled Object state in ToTerraformValue: %s", v.state)) } } func (v NetworkValue) IsNull() bool { return v.state == attr.ValueStateNull } func (v NetworkValue) IsUnknown() bool { return v.state == attr.ValueStateUnknown } func (v NetworkValue) String() string { return "NetworkValue" } func (v NetworkValue) ToObjectValue(ctx context.Context) (basetypes.ObjectValue, diag.Diagnostics) { var diags diag.Diagnostics var aclVal basetypes.ListValue switch { case v.Acl.IsUnknown(): aclVal = types.ListUnknown(types.StringType) case v.Acl.IsNull(): aclVal = types.ListNull(types.StringType) default: var d diag.Diagnostics aclVal, d = types.ListValue(types.StringType, v.Acl.Elements()) diags.Append(d...) } if diags.HasError() { return types.ObjectUnknown(map[string]attr.Type{ "access_scope": basetypes.StringType{}, "acl": basetypes.ListType{ ElemType: types.StringType, }, "instance_address": basetypes.StringType{}, "router_address": basetypes.StringType{}, }), diags } attributeTypes := map[string]attr.Type{ "access_scope": basetypes.StringType{}, "acl": basetypes.ListType{ ElemType: types.StringType, }, "instance_address": basetypes.StringType{}, "router_address": basetypes.StringType{}, } if v.IsNull() { return types.ObjectNull(attributeTypes), diags } if v.IsUnknown() { return types.ObjectUnknown(attributeTypes), diags } objVal, diags := types.ObjectValue( attributeTypes, map[string]attr.Value{ "access_scope": v.AccessScope, "acl": aclVal, "instance_address": v.InstanceAddress, "router_address": v.RouterAddress, }) return objVal, diags } func (v NetworkValue) Equal(o attr.Value) bool { other, ok := o.(NetworkValue) if !ok { return false } if v.state != other.state { return false } if v.state != attr.ValueStateKnown { return true } if !v.AccessScope.Equal(other.AccessScope) { return false } if !v.Acl.Equal(other.Acl) { return false } if !v.InstanceAddress.Equal(other.InstanceAddress) { return false } if !v.RouterAddress.Equal(other.RouterAddress) { return false } return true } func (v NetworkValue) Type(ctx context.Context) attr.Type { return NetworkType{ basetypes.ObjectType{ AttrTypes: v.AttributeTypes(ctx), }, } } func (v NetworkValue) AttributeTypes(ctx context.Context) map[string]attr.Type { return map[string]attr.Type{ "access_scope": basetypes.StringType{}, "acl": basetypes.ListType{ ElemType: types.StringType, }, "instance_address": basetypes.StringType{}, "router_address": basetypes.StringType{}, } } var _ basetypes.ObjectTypable = StorageType{} type StorageType struct { basetypes.ObjectType } func (t StorageType) Equal(o attr.Type) bool { other, ok := o.(StorageType) if !ok { return false } return t.ObjectType.Equal(other.ObjectType) } func (t StorageType) String() string { return "StorageType" } func (t StorageType) ValueFromObject(ctx context.Context, in basetypes.ObjectValue) (basetypes.ObjectValuable, diag.Diagnostics) { var diags diag.Diagnostics attributes := in.Attributes() performanceClassAttribute, ok := attributes["performance_class"] if !ok { diags.AddError( "Attribute Missing", `performance_class is missing from object`) return nil, diags } performanceClassVal, ok := performanceClassAttribute.(basetypes.StringValue) if !ok { diags.AddError( "Attribute Wrong Type", fmt.Sprintf(`performance_class expected to be basetypes.StringValue, was: %T`, performanceClassAttribute)) } sizeAttribute, ok := attributes["size"] if !ok { diags.AddError( "Attribute Missing", `size is missing from object`) return nil, diags } sizeVal, ok := sizeAttribute.(basetypes.Int64Value) if !ok { diags.AddError( "Attribute Wrong Type", fmt.Sprintf(`size expected to be basetypes.Int64Value, was: %T`, sizeAttribute)) } if diags.HasError() { return nil, diags } return StorageValue{ PerformanceClass: performanceClassVal, Size: sizeVal, state: attr.ValueStateKnown, }, diags } func NewStorageValueNull() StorageValue { return StorageValue{ state: attr.ValueStateNull, } } func NewStorageValueUnknown() StorageValue { return StorageValue{ state: attr.ValueStateUnknown, } } func NewStorageValue(attributeTypes map[string]attr.Type, attributes map[string]attr.Value) (StorageValue, diag.Diagnostics) { var diags diag.Diagnostics // Reference: https://github.com/hashicorp/terraform-plugin-framework/issues/521 ctx := context.Background() for name, attributeType := range attributeTypes { attribute, ok := attributes[name] if !ok { diags.AddError( "Missing StorageValue Attribute Value", "While creating a StorageValue value, a missing attribute value was detected. "+ "A StorageValue must contain values for all attributes, even if null or unknown. "+ "This is always an issue with the provider and should be reported to the provider developers.\n\n"+ fmt.Sprintf("StorageValue Attribute Name (%s) Expected Type: %s", name, attributeType.String()), ) continue } if !attributeType.Equal(attribute.Type(ctx)) { diags.AddError( "Invalid StorageValue Attribute Type", "While creating a StorageValue value, an invalid attribute value was detected. "+ "A StorageValue must use a matching attribute type for the value. "+ "This is always an issue with the provider and should be reported to the provider developers.\n\n"+ fmt.Sprintf("StorageValue Attribute Name (%s) Expected Type: %s\n", name, attributeType.String())+ fmt.Sprintf("StorageValue Attribute Name (%s) Given Type: %s", name, attribute.Type(ctx)), ) } } for name := range attributes { _, ok := attributeTypes[name] if !ok { diags.AddError( "Extra StorageValue Attribute Value", "While creating a StorageValue value, an extra attribute value was detected. "+ "A StorageValue must not contain values beyond the expected attribute types. "+ "This is always an issue with the provider and should be reported to the provider developers.\n\n"+ fmt.Sprintf("Extra StorageValue Attribute Name: %s", name), ) } } if diags.HasError() { return NewStorageValueUnknown(), diags } performanceClassAttribute, ok := attributes["performance_class"] if !ok { diags.AddError( "Attribute Missing", `performance_class is missing from object`) return NewStorageValueUnknown(), diags } performanceClassVal, ok := performanceClassAttribute.(basetypes.StringValue) if !ok { diags.AddError( "Attribute Wrong Type", fmt.Sprintf(`performance_class expected to be basetypes.StringValue, was: %T`, performanceClassAttribute)) } sizeAttribute, ok := attributes["size"] if !ok { diags.AddError( "Attribute Missing", `size is missing from object`) return NewStorageValueUnknown(), diags } sizeVal, ok := sizeAttribute.(basetypes.Int64Value) if !ok { diags.AddError( "Attribute Wrong Type", fmt.Sprintf(`size expected to be basetypes.Int64Value, was: %T`, sizeAttribute)) } if diags.HasError() { return NewStorageValueUnknown(), diags } return StorageValue{ PerformanceClass: performanceClassVal, Size: sizeVal, state: attr.ValueStateKnown, }, diags } func NewStorageValueMust(attributeTypes map[string]attr.Type, attributes map[string]attr.Value) StorageValue { object, diags := NewStorageValue(attributeTypes, attributes) if diags.HasError() { // This could potentially be added to the diag package. diagsStrings := make([]string, 0, len(diags)) for _, diagnostic := range diags { diagsStrings = append(diagsStrings, fmt.Sprintf( "%s | %s | %s", diagnostic.Severity(), diagnostic.Summary(), diagnostic.Detail())) } panic("NewStorageValueMust received error(s): " + strings.Join(diagsStrings, "\n")) } return object } func (t StorageType) ValueFromTerraform(ctx context.Context, in tftypes.Value) (attr.Value, error) { if in.Type() == nil { return NewStorageValueNull(), nil } if !in.Type().Equal(t.TerraformType(ctx)) { return nil, fmt.Errorf("expected %s, got %s", t.TerraformType(ctx), in.Type()) } if !in.IsKnown() { return NewStorageValueUnknown(), nil } if in.IsNull() { return NewStorageValueNull(), nil } attributes := map[string]attr.Value{} val := map[string]tftypes.Value{} err := in.As(&val) if err != nil { return nil, err } for k, v := range val { a, err := t.AttrTypes[k].ValueFromTerraform(ctx, v) if err != nil { return nil, err } attributes[k] = a } return NewStorageValueMust(StorageValue{}.AttributeTypes(ctx), attributes), nil } func (t StorageType) ValueType(ctx context.Context) attr.Value { return StorageValue{} } var _ basetypes.ObjectValuable = StorageValue{} type StorageValue struct { PerformanceClass basetypes.StringValue `tfsdk:"performance_class"` Size basetypes.Int64Value `tfsdk:"size"` state attr.ValueState } func (v StorageValue) ToTerraformValue(ctx context.Context) (tftypes.Value, error) { attrTypes := make(map[string]tftypes.Type, 2) var val tftypes.Value var err error attrTypes["performance_class"] = basetypes.StringType{}.TerraformType(ctx) attrTypes["size"] = basetypes.Int64Type{}.TerraformType(ctx) objectType := tftypes.Object{AttributeTypes: attrTypes} switch v.state { case attr.ValueStateKnown: vals := make(map[string]tftypes.Value, 2) val, err = v.PerformanceClass.ToTerraformValue(ctx) if err != nil { return tftypes.NewValue(objectType, tftypes.UnknownValue), err } vals["performance_class"] = val val, err = v.Size.ToTerraformValue(ctx) if err != nil { return tftypes.NewValue(objectType, tftypes.UnknownValue), err } vals["size"] = val if err := tftypes.ValidateValue(objectType, vals); err != nil { return tftypes.NewValue(objectType, tftypes.UnknownValue), err } return tftypes.NewValue(objectType, vals), nil case attr.ValueStateNull: return tftypes.NewValue(objectType, nil), nil case attr.ValueStateUnknown: return tftypes.NewValue(objectType, tftypes.UnknownValue), nil default: panic(fmt.Sprintf("unhandled Object state in ToTerraformValue: %s", v.state)) } } func (v StorageValue) IsNull() bool { return v.state == attr.ValueStateNull } func (v StorageValue) IsUnknown() bool { return v.state == attr.ValueStateUnknown } func (v StorageValue) String() string { return "StorageValue" } func (v StorageValue) ToObjectValue(ctx context.Context) (basetypes.ObjectValue, diag.Diagnostics) { var diags diag.Diagnostics attributeTypes := map[string]attr.Type{ "performance_class": basetypes.StringType{}, "size": basetypes.Int64Type{}, } if v.IsNull() { return types.ObjectNull(attributeTypes), diags } if v.IsUnknown() { return types.ObjectUnknown(attributeTypes), diags } objVal, diags := types.ObjectValue( attributeTypes, map[string]attr.Value{ "performance_class": v.PerformanceClass, "size": v.Size, }) return objVal, diags } func (v StorageValue) Equal(o attr.Value) bool { other, ok := o.(StorageValue) if !ok { return false } if v.state != other.state { return false } if v.state != attr.ValueStateKnown { return true } if !v.PerformanceClass.Equal(other.PerformanceClass) { return false } if !v.Size.Equal(other.Size) { return false } return true } func (v StorageValue) Type(ctx context.Context) attr.Type { return StorageType{ basetypes.ObjectType{ AttrTypes: v.AttributeTypes(ctx), }, } } func (v StorageValue) AttributeTypes(ctx context.Context) map[string]attr.Type { return map[string]attr.Type{ "performance_class": basetypes.StringType{}, "size": basetypes.Int64Type{}, } }