mirror of
https://github.com/opentofu/opentofu.git
synced 2025-01-18 04:32:59 -06:00
b40a4fb741
This is part of a general effort to move all of Terraform's non-library package surface under internal in order to reinforce that these are for internal use within Terraform only. If you were previously importing packages under this prefix into an external codebase, you could pin to an earlier release tag as an interim solution until you've make a plan to achieve the same functionality some other way.
302 lines
7.8 KiB
Go
302 lines
7.8 KiB
Go
package convert
|
|
|
|
import (
|
|
"encoding/json"
|
|
"reflect"
|
|
"sort"
|
|
|
|
"github.com/hashicorp/terraform/internal/configs/configschema"
|
|
"github.com/hashicorp/terraform/internal/providers"
|
|
proto "github.com/hashicorp/terraform/internal/tfplugin6"
|
|
"github.com/zclconf/go-cty/cty"
|
|
)
|
|
|
|
// 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{
|
|
Description: b.Description,
|
|
DescriptionKind: protoStringKind(b.DescriptionKind),
|
|
Deprecated: b.Deprecated,
|
|
}
|
|
|
|
for _, name := range sortedKeys(b.Attributes) {
|
|
a := b.Attributes[name]
|
|
|
|
attr := &proto.Schema_Attribute{
|
|
Name: name,
|
|
Description: a.Description,
|
|
DescriptionKind: protoStringKind(a.DescriptionKind),
|
|
Optional: a.Optional,
|
|
Computed: a.Computed,
|
|
Required: a.Required,
|
|
Sensitive: a.Sensitive,
|
|
Deprecated: a.Deprecated,
|
|
}
|
|
|
|
if a.Type != cty.NilType {
|
|
ty, err := json.Marshal(a.Type)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
attr.Type = ty
|
|
}
|
|
|
|
if a.NestedType != nil {
|
|
attr.NestedType = configschemaObjectToProto(a.NestedType)
|
|
}
|
|
|
|
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 protoStringKind(k configschema.StringKind) proto.StringKind {
|
|
switch k {
|
|
default:
|
|
return proto.StringKind_PLAIN
|
|
case configschema.StringMarkdown:
|
|
return proto.StringKind_MARKDOWN
|
|
}
|
|
}
|
|
|
|
func protoSchemaNestedBlock(name string, b *configschema.NestedBlock) *proto.Schema_NestedBlock {
|
|
var nesting proto.Schema_NestedBlock_NestingMode
|
|
switch b.Nesting {
|
|
case configschema.NestingSingle:
|
|
nesting = proto.Schema_NestedBlock_SINGLE
|
|
case configschema.NestingGroup:
|
|
nesting = proto.Schema_NestedBlock_GROUP
|
|
case configschema.NestingList:
|
|
nesting = proto.Schema_NestedBlock_LIST
|
|
case configschema.NestingSet:
|
|
nesting = proto.Schema_NestedBlock_SET
|
|
case configschema.NestingMap:
|
|
nesting = proto.Schema_NestedBlock_MAP
|
|
default:
|
|
nesting = proto.Schema_NestedBlock_INVALID
|
|
}
|
|
return &proto.Schema_NestedBlock{
|
|
TypeName: name,
|
|
Block: ConfigSchemaToProto(&b.Block),
|
|
Nesting: 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),
|
|
|
|
Description: b.Description,
|
|
DescriptionKind: schemaStringKind(b.DescriptionKind),
|
|
Deprecated: b.Deprecated,
|
|
}
|
|
|
|
for _, a := range b.Attributes {
|
|
attr := &configschema.Attribute{
|
|
Description: a.Description,
|
|
DescriptionKind: schemaStringKind(a.DescriptionKind),
|
|
Required: a.Required,
|
|
Optional: a.Optional,
|
|
Computed: a.Computed,
|
|
Sensitive: a.Sensitive,
|
|
Deprecated: a.Deprecated,
|
|
}
|
|
|
|
if a.Type != nil {
|
|
if err := json.Unmarshal(a.Type, &attr.Type); err != nil {
|
|
panic(err)
|
|
}
|
|
}
|
|
|
|
if a.NestedType != nil {
|
|
attr.NestedType = protoObjectToConfigSchema(a.NestedType)
|
|
}
|
|
|
|
block.Attributes[a.Name] = attr
|
|
}
|
|
|
|
for _, b := range b.BlockTypes {
|
|
block.BlockTypes[b.TypeName] = schemaNestedBlock(b)
|
|
}
|
|
|
|
return block
|
|
}
|
|
|
|
func schemaStringKind(k proto.StringKind) configschema.StringKind {
|
|
switch k {
|
|
default:
|
|
return configschema.StringPlain
|
|
case proto.StringKind_MARKDOWN:
|
|
return configschema.StringMarkdown
|
|
}
|
|
}
|
|
|
|
func schemaNestedBlock(b *proto.Schema_NestedBlock) *configschema.NestedBlock {
|
|
var nesting configschema.NestingMode
|
|
switch b.Nesting {
|
|
case proto.Schema_NestedBlock_SINGLE:
|
|
nesting = configschema.NestingSingle
|
|
case proto.Schema_NestedBlock_GROUP:
|
|
nesting = configschema.NestingGroup
|
|
case proto.Schema_NestedBlock_LIST:
|
|
nesting = configschema.NestingList
|
|
case proto.Schema_NestedBlock_MAP:
|
|
nesting = configschema.NestingMap
|
|
case proto.Schema_NestedBlock_SET:
|
|
nesting = configschema.NestingSet
|
|
default:
|
|
// In all other cases we'll leave it as the zero value (invalid) and
|
|
// let the caller validate it and deal with this.
|
|
}
|
|
|
|
nb := &configschema.NestedBlock{
|
|
Nesting: nesting,
|
|
MinItems: int(b.MinItems),
|
|
MaxItems: int(b.MaxItems),
|
|
}
|
|
|
|
nested := ProtoToConfigSchema(b.Block)
|
|
nb.Block = *nested
|
|
return nb
|
|
}
|
|
|
|
func protoObjectToConfigSchema(b *proto.Schema_Object) *configschema.Object {
|
|
var nesting configschema.NestingMode
|
|
switch b.Nesting {
|
|
case proto.Schema_Object_SINGLE:
|
|
nesting = configschema.NestingSingle
|
|
case proto.Schema_Object_LIST:
|
|
nesting = configschema.NestingList
|
|
case proto.Schema_Object_MAP:
|
|
nesting = configschema.NestingMap
|
|
case proto.Schema_Object_SET:
|
|
nesting = configschema.NestingSet
|
|
default:
|
|
// In all other cases we'll leave it as the zero value (invalid) and
|
|
// let the caller validate it and deal with this.
|
|
}
|
|
|
|
object := &configschema.Object{
|
|
Attributes: make(map[string]*configschema.Attribute),
|
|
Nesting: nesting,
|
|
MinItems: int(b.MinItems),
|
|
MaxItems: int(b.MaxItems),
|
|
}
|
|
|
|
for _, a := range b.Attributes {
|
|
attr := &configschema.Attribute{
|
|
Description: a.Description,
|
|
DescriptionKind: schemaStringKind(a.DescriptionKind),
|
|
Required: a.Required,
|
|
Optional: a.Optional,
|
|
Computed: a.Computed,
|
|
Sensitive: a.Sensitive,
|
|
Deprecated: a.Deprecated,
|
|
}
|
|
|
|
if a.Type != nil {
|
|
if err := json.Unmarshal(a.Type, &attr.Type); err != nil {
|
|
panic(err)
|
|
}
|
|
}
|
|
|
|
if a.NestedType != nil {
|
|
attr.NestedType = protoObjectToConfigSchema(a.NestedType)
|
|
}
|
|
|
|
object.Attributes[a.Name] = attr
|
|
}
|
|
|
|
return object
|
|
}
|
|
|
|
// 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
|
|
}
|
|
|
|
func configschemaObjectToProto(b *configschema.Object) *proto.Schema_Object {
|
|
var nesting proto.Schema_Object_NestingMode
|
|
switch b.Nesting {
|
|
case configschema.NestingSingle:
|
|
nesting = proto.Schema_Object_SINGLE
|
|
case configschema.NestingList:
|
|
nesting = proto.Schema_Object_LIST
|
|
case configschema.NestingSet:
|
|
nesting = proto.Schema_Object_SET
|
|
case configschema.NestingMap:
|
|
nesting = proto.Schema_Object_MAP
|
|
default:
|
|
nesting = proto.Schema_Object_INVALID
|
|
}
|
|
|
|
attributes := make([]*proto.Schema_Attribute, len(b.Attributes))
|
|
|
|
for _, name := range sortedKeys(b.Attributes) {
|
|
a := b.Attributes[name]
|
|
|
|
attr := &proto.Schema_Attribute{
|
|
Name: name,
|
|
Description: a.Description,
|
|
DescriptionKind: protoStringKind(a.DescriptionKind),
|
|
Optional: a.Optional,
|
|
Computed: a.Computed,
|
|
Required: a.Required,
|
|
Sensitive: a.Sensitive,
|
|
Deprecated: a.Deprecated,
|
|
}
|
|
|
|
if a.Type != cty.NilType {
|
|
ty, err := json.Marshal(a.Type)
|
|
if err != nil {
|
|
panic(err)
|
|
}
|
|
attr.Type = ty
|
|
}
|
|
|
|
if a.NestedType != nil {
|
|
attr.NestedType = configschemaObjectToProto(a.NestedType)
|
|
}
|
|
|
|
attributes = append(attributes, attr)
|
|
}
|
|
|
|
return &proto.Schema_Object{
|
|
Attributes: attributes,
|
|
Nesting: nesting,
|
|
MinItems: int64(b.MinItems),
|
|
MaxItems: int64(b.MaxItems),
|
|
}
|
|
}
|