opentofu/plugin/convert/schema.go
Martin Atkins 72e279e6b2 providers: Consistently use int64 for schema versions
The rest of Terraform is still using uint64 for this in various spots, but
we'll update that gradually later. We use int64 here because that matches
what's used in our protobuf definition, and unsigned integers are not
portable across all of the protobuf target languages anyway.
2018-11-30 11:22:39 -08:00

123 lines
3.0 KiB
Go

package convert
import (
"encoding/json"
"reflect"
"sort"
"github.com/hashicorp/terraform/configs/configschema"
proto "github.com/hashicorp/terraform/internal/tfplugin5"
"github.com/hashicorp/terraform/providers"
)
// ConfigSchemaToProto takes a *configschema.Block and converts it to a
// proto.Schema_Block for a grpc response.
func ConfigSchemaToProto(b *configschema.Block) *proto.Schema_Block {
block := &proto.Schema_Block{}
for _, name := range sortedKeys(b.Attributes) {
a := b.Attributes[name]
attr := &proto.Schema_Attribute{
Name: name,
Description: a.Description,
Optional: a.Optional,
Computed: a.Computed,
Required: a.Required,
Sensitive: a.Sensitive,
}
ty, err := json.Marshal(a.Type)
if err != nil {
panic(err)
}
attr.Type = ty
block.Attributes = append(block.Attributes, attr)
}
for _, name := range sortedKeys(b.BlockTypes) {
b := b.BlockTypes[name]
block.BlockTypes = append(block.BlockTypes, protoSchemaNestedBlock(name, b))
}
return block
}
func protoSchemaNestedBlock(name string, b *configschema.NestedBlock) *proto.Schema_NestedBlock {
return &proto.Schema_NestedBlock{
TypeName: name,
Block: ConfigSchemaToProto(&b.Block),
Nesting: proto.Schema_NestedBlock_NestingMode(b.Nesting),
MinItems: int64(b.MinItems),
MaxItems: int64(b.MaxItems),
}
}
// ProtoToProviderSchema takes a proto.Schema and converts it to a providers.Schema.
func ProtoToProviderSchema(s *proto.Schema) providers.Schema {
return providers.Schema{
Version: s.Version,
Block: ProtoToConfigSchema(s.Block),
}
}
// ProtoToConfigSchema takes the GetSchcema_Block from a grpc response and converts it
// to a terraform *configschema.Block.
func ProtoToConfigSchema(b *proto.Schema_Block) *configschema.Block {
block := &configschema.Block{
Attributes: make(map[string]*configschema.Attribute),
BlockTypes: make(map[string]*configschema.NestedBlock),
}
for _, a := range b.Attributes {
attr := &configschema.Attribute{
Description: a.Description,
Required: a.Required,
Optional: a.Optional,
Computed: a.Computed,
Sensitive: a.Sensitive,
}
if err := json.Unmarshal(a.Type, &attr.Type); err != nil {
panic(err)
}
block.Attributes[a.Name] = attr
}
for _, b := range b.BlockTypes {
block.BlockTypes[b.TypeName] = schemaNestedBlock(b)
}
return block
}
func schemaNestedBlock(b *proto.Schema_NestedBlock) *configschema.NestedBlock {
nb := &configschema.NestedBlock{
Nesting: configschema.NestingMode(b.Nesting),
MinItems: int(b.MinItems),
MaxItems: int(b.MaxItems),
}
nested := ProtoToConfigSchema(b.Block)
nb.Block = *nested
return nb
}
// sortedKeys returns the lexically sorted keys from the given map. This is
// used to make schema conversions are deterministic. This panics if map keys
// are not a string.
func sortedKeys(m interface{}) []string {
v := reflect.ValueOf(m)
keys := make([]string, v.Len())
mapKeys := v.MapKeys()
for i, k := range mapKeys {
keys[i] = k.Interface().(string)
}
sort.Strings(keys)
return keys
}