github.com/cycloidio/terraform@v1.1.10-0.20220513142504-76d5c768dc63/plugin/convert/schema.go (about) 1 package convert 2 3 import ( 4 "encoding/json" 5 "reflect" 6 "sort" 7 8 "github.com/cycloidio/terraform/configs/configschema" 9 "github.com/cycloidio/terraform/providers" 10 proto "github.com/cycloidio/terraform/tfplugin5" 11 ) 12 13 // ConfigSchemaToProto takes a *configschema.Block and converts it to a 14 // proto.Schema_Block for a grpc response. 15 func ConfigSchemaToProto(b *configschema.Block) *proto.Schema_Block { 16 block := &proto.Schema_Block{ 17 Description: b.Description, 18 DescriptionKind: protoStringKind(b.DescriptionKind), 19 Deprecated: b.Deprecated, 20 } 21 22 for _, name := range sortedKeys(b.Attributes) { 23 a := b.Attributes[name] 24 25 attr := &proto.Schema_Attribute{ 26 Name: name, 27 Description: a.Description, 28 DescriptionKind: protoStringKind(a.DescriptionKind), 29 Optional: a.Optional, 30 Computed: a.Computed, 31 Required: a.Required, 32 Sensitive: a.Sensitive, 33 Deprecated: a.Deprecated, 34 } 35 36 ty, err := json.Marshal(a.Type) 37 if err != nil { 38 panic(err) 39 } 40 41 attr.Type = ty 42 43 block.Attributes = append(block.Attributes, attr) 44 } 45 46 for _, name := range sortedKeys(b.BlockTypes) { 47 b := b.BlockTypes[name] 48 block.BlockTypes = append(block.BlockTypes, protoSchemaNestedBlock(name, b)) 49 } 50 51 return block 52 } 53 54 func protoStringKind(k configschema.StringKind) proto.StringKind { 55 switch k { 56 default: 57 return proto.StringKind_PLAIN 58 case configschema.StringMarkdown: 59 return proto.StringKind_MARKDOWN 60 } 61 } 62 63 func protoSchemaNestedBlock(name string, b *configschema.NestedBlock) *proto.Schema_NestedBlock { 64 var nesting proto.Schema_NestedBlock_NestingMode 65 switch b.Nesting { 66 case configschema.NestingSingle: 67 nesting = proto.Schema_NestedBlock_SINGLE 68 case configschema.NestingGroup: 69 nesting = proto.Schema_NestedBlock_GROUP 70 case configschema.NestingList: 71 nesting = proto.Schema_NestedBlock_LIST 72 case configschema.NestingSet: 73 nesting = proto.Schema_NestedBlock_SET 74 case configschema.NestingMap: 75 nesting = proto.Schema_NestedBlock_MAP 76 default: 77 nesting = proto.Schema_NestedBlock_INVALID 78 } 79 return &proto.Schema_NestedBlock{ 80 TypeName: name, 81 Block: ConfigSchemaToProto(&b.Block), 82 Nesting: nesting, 83 MinItems: int64(b.MinItems), 84 MaxItems: int64(b.MaxItems), 85 } 86 } 87 88 // ProtoToProviderSchema takes a proto.Schema and converts it to a providers.Schema. 89 func ProtoToProviderSchema(s *proto.Schema) providers.Schema { 90 return providers.Schema{ 91 Version: s.Version, 92 Block: ProtoToConfigSchema(s.Block), 93 } 94 } 95 96 // ProtoToConfigSchema takes the GetSchcema_Block from a grpc response and converts it 97 // to a terraform *configschema.Block. 98 func ProtoToConfigSchema(b *proto.Schema_Block) *configschema.Block { 99 block := &configschema.Block{ 100 Attributes: make(map[string]*configschema.Attribute), 101 BlockTypes: make(map[string]*configschema.NestedBlock), 102 103 Description: b.Description, 104 DescriptionKind: schemaStringKind(b.DescriptionKind), 105 Deprecated: b.Deprecated, 106 } 107 108 for _, a := range b.Attributes { 109 attr := &configschema.Attribute{ 110 Description: a.Description, 111 DescriptionKind: schemaStringKind(a.DescriptionKind), 112 Required: a.Required, 113 Optional: a.Optional, 114 Computed: a.Computed, 115 Sensitive: a.Sensitive, 116 Deprecated: a.Deprecated, 117 } 118 119 if err := json.Unmarshal(a.Type, &attr.Type); err != nil { 120 panic(err) 121 } 122 123 block.Attributes[a.Name] = attr 124 } 125 126 for _, b := range b.BlockTypes { 127 block.BlockTypes[b.TypeName] = schemaNestedBlock(b) 128 } 129 130 return block 131 } 132 133 func schemaStringKind(k proto.StringKind) configschema.StringKind { 134 switch k { 135 default: 136 return configschema.StringPlain 137 case proto.StringKind_MARKDOWN: 138 return configschema.StringMarkdown 139 } 140 } 141 142 func schemaNestedBlock(b *proto.Schema_NestedBlock) *configschema.NestedBlock { 143 var nesting configschema.NestingMode 144 switch b.Nesting { 145 case proto.Schema_NestedBlock_SINGLE: 146 nesting = configschema.NestingSingle 147 case proto.Schema_NestedBlock_GROUP: 148 nesting = configschema.NestingGroup 149 case proto.Schema_NestedBlock_LIST: 150 nesting = configschema.NestingList 151 case proto.Schema_NestedBlock_MAP: 152 nesting = configschema.NestingMap 153 case proto.Schema_NestedBlock_SET: 154 nesting = configschema.NestingSet 155 default: 156 // In all other cases we'll leave it as the zero value (invalid) and 157 // let the caller validate it and deal with this. 158 } 159 160 nb := &configschema.NestedBlock{ 161 Nesting: nesting, 162 MinItems: int(b.MinItems), 163 MaxItems: int(b.MaxItems), 164 } 165 166 nested := ProtoToConfigSchema(b.Block) 167 nb.Block = *nested 168 return nb 169 } 170 171 // sortedKeys returns the lexically sorted keys from the given map. This is 172 // used to make schema conversions are deterministic. This panics if map keys 173 // are not a string. 174 func sortedKeys(m interface{}) []string { 175 v := reflect.ValueOf(m) 176 keys := make([]string, v.Len()) 177 178 mapKeys := v.MapKeys() 179 for i, k := range mapKeys { 180 keys[i] = k.Interface().(string) 181 } 182 183 sort.Strings(keys) 184 return keys 185 }