kubeform.dev/terraform-backend-sdk@v0.0.0-20220310143633-45f07fe731c5/plugin6/convert/schema.go (about) 1 package convert 2 3 import ( 4 "encoding/json" 5 "reflect" 6 "sort" 7 8 "kubeform.dev/terraform-backend-sdk/configs/configschema" 9 "kubeform.dev/terraform-backend-sdk/providers" 10 proto "kubeform.dev/terraform-backend-sdk/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 MinItems: int(b.MinItems), 203 MaxItems: int(b.MaxItems), 204 } 205 206 for _, a := range b.Attributes { 207 attr := &configschema.Attribute{ 208 Description: a.Description, 209 DescriptionKind: schemaStringKind(a.DescriptionKind), 210 Required: a.Required, 211 Optional: a.Optional, 212 Computed: a.Computed, 213 Sensitive: a.Sensitive, 214 Deprecated: a.Deprecated, 215 } 216 217 if a.Type != nil { 218 if err := json.Unmarshal(a.Type, &attr.Type); err != nil { 219 panic(err) 220 } 221 } 222 223 if a.NestedType != nil { 224 attr.NestedType = protoObjectToConfigSchema(a.NestedType) 225 } 226 227 object.Attributes[a.Name] = attr 228 } 229 230 return object 231 } 232 233 // sortedKeys returns the lexically sorted keys from the given map. This is 234 // used to make schema conversions are deterministic. This panics if map keys 235 // are not a string. 236 func sortedKeys(m interface{}) []string { 237 v := reflect.ValueOf(m) 238 keys := make([]string, v.Len()) 239 240 mapKeys := v.MapKeys() 241 for i, k := range mapKeys { 242 keys[i] = k.Interface().(string) 243 } 244 245 sort.Strings(keys) 246 return keys 247 } 248 249 func configschemaObjectToProto(b *configschema.Object) *proto.Schema_Object { 250 var nesting proto.Schema_Object_NestingMode 251 switch b.Nesting { 252 case configschema.NestingSingle: 253 nesting = proto.Schema_Object_SINGLE 254 case configschema.NestingList: 255 nesting = proto.Schema_Object_LIST 256 case configschema.NestingSet: 257 nesting = proto.Schema_Object_SET 258 case configschema.NestingMap: 259 nesting = proto.Schema_Object_MAP 260 default: 261 nesting = proto.Schema_Object_INVALID 262 } 263 264 attributes := make([]*proto.Schema_Attribute, len(b.Attributes)) 265 266 for _, name := range sortedKeys(b.Attributes) { 267 a := b.Attributes[name] 268 269 attr := &proto.Schema_Attribute{ 270 Name: name, 271 Description: a.Description, 272 DescriptionKind: protoStringKind(a.DescriptionKind), 273 Optional: a.Optional, 274 Computed: a.Computed, 275 Required: a.Required, 276 Sensitive: a.Sensitive, 277 Deprecated: a.Deprecated, 278 } 279 280 if a.Type != cty.NilType { 281 ty, err := json.Marshal(a.Type) 282 if err != nil { 283 panic(err) 284 } 285 attr.Type = ty 286 } 287 288 if a.NestedType != nil { 289 attr.NestedType = configschemaObjectToProto(a.NestedType) 290 } 291 292 attributes = append(attributes, attr) 293 } 294 295 return &proto.Schema_Object{ 296 Attributes: attributes, 297 Nesting: nesting, 298 MinItems: int64(b.MinItems), 299 MaxItems: int64(b.MaxItems), 300 } 301 }