github.com/pulumi/terraform@v1.4.0/pkg/plugin6/convert/schema.go (about) 1 package convert 2 3 import ( 4 "encoding/json" 5 "reflect" 6 "sort" 7 8 "github.com/pulumi/terraform/pkg/configs/configschema" 9 "github.com/pulumi/terraform/pkg/providers" 10 proto "github.com/pulumi/terraform/pkg/tfplugin6" 11 "github.com/zclconf/go-cty/cty" 12 ) 13 14 // ConfigSchemaToProto takes a *configschema.Block and converts it to a 15 // proto.Schema_Block for a grpc response. 16 func ConfigSchemaToProto(b *configschema.Block) *proto.Schema_Block { 17 block := &proto.Schema_Block{ 18 Description: b.Description, 19 DescriptionKind: protoStringKind(b.DescriptionKind), 20 Deprecated: b.Deprecated, 21 } 22 23 for _, name := range sortedKeys(b.Attributes) { 24 a := b.Attributes[name] 25 26 attr := &proto.Schema_Attribute{ 27 Name: name, 28 Description: a.Description, 29 DescriptionKind: protoStringKind(a.DescriptionKind), 30 Optional: a.Optional, 31 Computed: a.Computed, 32 Required: a.Required, 33 Sensitive: a.Sensitive, 34 Deprecated: a.Deprecated, 35 } 36 37 if a.Type != cty.NilType { 38 ty, err := json.Marshal(a.Type) 39 if err != nil { 40 panic(err) 41 } 42 attr.Type = ty 43 } 44 45 if a.NestedType != nil { 46 attr.NestedType = configschemaObjectToProto(a.NestedType) 47 } 48 49 block.Attributes = append(block.Attributes, attr) 50 } 51 52 for _, name := range sortedKeys(b.BlockTypes) { 53 b := b.BlockTypes[name] 54 block.BlockTypes = append(block.BlockTypes, protoSchemaNestedBlock(name, b)) 55 } 56 57 return block 58 } 59 60 func protoStringKind(k configschema.StringKind) proto.StringKind { 61 switch k { 62 default: 63 return proto.StringKind_PLAIN 64 case configschema.StringMarkdown: 65 return proto.StringKind_MARKDOWN 66 } 67 } 68 69 func protoSchemaNestedBlock(name string, b *configschema.NestedBlock) *proto.Schema_NestedBlock { 70 var nesting proto.Schema_NestedBlock_NestingMode 71 switch b.Nesting { 72 case configschema.NestingSingle: 73 nesting = proto.Schema_NestedBlock_SINGLE 74 case configschema.NestingGroup: 75 nesting = proto.Schema_NestedBlock_GROUP 76 case configschema.NestingList: 77 nesting = proto.Schema_NestedBlock_LIST 78 case configschema.NestingSet: 79 nesting = proto.Schema_NestedBlock_SET 80 case configschema.NestingMap: 81 nesting = proto.Schema_NestedBlock_MAP 82 default: 83 nesting = proto.Schema_NestedBlock_INVALID 84 } 85 return &proto.Schema_NestedBlock{ 86 TypeName: name, 87 Block: ConfigSchemaToProto(&b.Block), 88 Nesting: nesting, 89 MinItems: int64(b.MinItems), 90 MaxItems: int64(b.MaxItems), 91 } 92 } 93 94 // ProtoToProviderSchema takes a proto.Schema and converts it to a providers.Schema. 95 func ProtoToProviderSchema(s *proto.Schema) providers.Schema { 96 return providers.Schema{ 97 Version: s.Version, 98 Block: ProtoToConfigSchema(s.Block), 99 } 100 } 101 102 // ProtoToConfigSchema takes the GetSchcema_Block from a grpc response and converts it 103 // to a terraform *configschema.Block. 104 func ProtoToConfigSchema(b *proto.Schema_Block) *configschema.Block { 105 block := &configschema.Block{ 106 Attributes: make(map[string]*configschema.Attribute), 107 BlockTypes: make(map[string]*configschema.NestedBlock), 108 109 Description: b.Description, 110 DescriptionKind: schemaStringKind(b.DescriptionKind), 111 Deprecated: b.Deprecated, 112 } 113 114 for _, a := range b.Attributes { 115 attr := &configschema.Attribute{ 116 Description: a.Description, 117 DescriptionKind: schemaStringKind(a.DescriptionKind), 118 Required: a.Required, 119 Optional: a.Optional, 120 Computed: a.Computed, 121 Sensitive: a.Sensitive, 122 Deprecated: a.Deprecated, 123 } 124 125 if a.Type != nil { 126 if err := json.Unmarshal(a.Type, &attr.Type); err != nil { 127 panic(err) 128 } 129 } 130 131 if a.NestedType != nil { 132 attr.NestedType = protoObjectToConfigSchema(a.NestedType) 133 } 134 135 block.Attributes[a.Name] = attr 136 } 137 138 for _, b := range b.BlockTypes { 139 block.BlockTypes[b.TypeName] = schemaNestedBlock(b) 140 } 141 142 return block 143 } 144 145 func schemaStringKind(k proto.StringKind) configschema.StringKind { 146 switch k { 147 default: 148 return configschema.StringPlain 149 case proto.StringKind_MARKDOWN: 150 return configschema.StringMarkdown 151 } 152 } 153 154 func schemaNestedBlock(b *proto.Schema_NestedBlock) *configschema.NestedBlock { 155 var nesting configschema.NestingMode 156 switch b.Nesting { 157 case proto.Schema_NestedBlock_SINGLE: 158 nesting = configschema.NestingSingle 159 case proto.Schema_NestedBlock_GROUP: 160 nesting = configschema.NestingGroup 161 case proto.Schema_NestedBlock_LIST: 162 nesting = configschema.NestingList 163 case proto.Schema_NestedBlock_MAP: 164 nesting = configschema.NestingMap 165 case proto.Schema_NestedBlock_SET: 166 nesting = configschema.NestingSet 167 default: 168 // In all other cases we'll leave it as the zero value (invalid) and 169 // let the caller validate it and deal with this. 170 } 171 172 nb := &configschema.NestedBlock{ 173 Nesting: nesting, 174 MinItems: int(b.MinItems), 175 MaxItems: int(b.MaxItems), 176 } 177 178 nested := ProtoToConfigSchema(b.Block) 179 nb.Block = *nested 180 return nb 181 } 182 183 func protoObjectToConfigSchema(b *proto.Schema_Object) *configschema.Object { 184 var nesting configschema.NestingMode 185 switch b.Nesting { 186 case proto.Schema_Object_SINGLE: 187 nesting = configschema.NestingSingle 188 case proto.Schema_Object_LIST: 189 nesting = configschema.NestingList 190 case proto.Schema_Object_MAP: 191 nesting = configschema.NestingMap 192 case proto.Schema_Object_SET: 193 nesting = configschema.NestingSet 194 default: 195 // In all other cases we'll leave it as the zero value (invalid) and 196 // let the caller validate it and deal with this. 197 } 198 199 object := &configschema.Object{ 200 Attributes: make(map[string]*configschema.Attribute), 201 Nesting: nesting, 202 } 203 204 for _, a := range b.Attributes { 205 attr := &configschema.Attribute{ 206 Description: a.Description, 207 DescriptionKind: schemaStringKind(a.DescriptionKind), 208 Required: a.Required, 209 Optional: a.Optional, 210 Computed: a.Computed, 211 Sensitive: a.Sensitive, 212 Deprecated: a.Deprecated, 213 } 214 215 if a.Type != nil { 216 if err := json.Unmarshal(a.Type, &attr.Type); err != nil { 217 panic(err) 218 } 219 } 220 221 if a.NestedType != nil { 222 attr.NestedType = protoObjectToConfigSchema(a.NestedType) 223 } 224 225 object.Attributes[a.Name] = attr 226 } 227 228 return object 229 } 230 231 // sortedKeys returns the lexically sorted keys from the given map. This is 232 // used to make schema conversions are deterministic. This panics if map keys 233 // are not a string. 234 func sortedKeys(m interface{}) []string { 235 v := reflect.ValueOf(m) 236 keys := make([]string, v.Len()) 237 238 mapKeys := v.MapKeys() 239 for i, k := range mapKeys { 240 keys[i] = k.Interface().(string) 241 } 242 243 sort.Strings(keys) 244 return keys 245 } 246 247 func configschemaObjectToProto(b *configschema.Object) *proto.Schema_Object { 248 var nesting proto.Schema_Object_NestingMode 249 switch b.Nesting { 250 case configschema.NestingSingle: 251 nesting = proto.Schema_Object_SINGLE 252 case configschema.NestingList: 253 nesting = proto.Schema_Object_LIST 254 case configschema.NestingSet: 255 nesting = proto.Schema_Object_SET 256 case configschema.NestingMap: 257 nesting = proto.Schema_Object_MAP 258 default: 259 nesting = proto.Schema_Object_INVALID 260 } 261 262 attributes := make([]*proto.Schema_Attribute, 0, len(b.Attributes)) 263 264 for _, name := range sortedKeys(b.Attributes) { 265 a := b.Attributes[name] 266 267 attr := &proto.Schema_Attribute{ 268 Name: name, 269 Description: a.Description, 270 DescriptionKind: protoStringKind(a.DescriptionKind), 271 Optional: a.Optional, 272 Computed: a.Computed, 273 Required: a.Required, 274 Sensitive: a.Sensitive, 275 Deprecated: a.Deprecated, 276 } 277 278 if a.Type != cty.NilType { 279 ty, err := json.Marshal(a.Type) 280 if err != nil { 281 panic(err) 282 } 283 attr.Type = ty 284 } 285 286 if a.NestedType != nil { 287 attr.NestedType = configschemaObjectToProto(a.NestedType) 288 } 289 290 attributes = append(attributes, attr) 291 } 292 293 return &proto.Schema_Object{ 294 Attributes: attributes, 295 Nesting: nesting, 296 } 297 }