driftctl/pkg/resource/schemas.go

186 lines
5.4 KiB
Go

package resource
import (
"strings"
"github.com/hashicorp/go-version"
"github.com/hashicorp/terraform/configs/configschema"
"github.com/hashicorp/terraform/providers"
"github.com/sirupsen/logrus"
)
type AttributeSchema struct {
ConfigSchema configschema.Attribute
JsonString bool
}
type Flags uint32
const (
FlagDeepMode Flags = 1 << iota
)
func (f Flags) HasFlag(flag Flags) bool {
return f&flag != 0
}
func (f *Flags) AddFlag(flag Flags) {
*f |= flag
}
type Schema struct {
ProviderVersion *version.Version
Flags Flags
SchemaVersion int64
Attributes map[string]AttributeSchema
NormalizeFunc func(res *Resource)
HumanReadableAttributesFunc func(res *Resource) map[string]string
ResolveReadAttributesFunc func(res *Resource) map[string]string
DiscriminantFunc func(*Resource, *Resource) bool
}
func (s *Schema) IsComputedField(path []string) bool {
metadata, exist := s.Attributes[strings.Join(path, ".")]
if !exist {
return false
}
return metadata.ConfigSchema.Computed
}
func (s *Schema) IsJsonStringField(path []string) bool {
metadata, exist := s.Attributes[strings.Join(path, ".")]
if !exist {
return false
}
return metadata.JsonString
}
type SchemaRepositoryInterface interface {
GetSchema(resourceType string) (*Schema, bool)
SetFlags(typ string, flags ...Flags)
UpdateSchema(typ string, schemasMutators map[string]func(attributeSchema *AttributeSchema))
SetNormalizeFunc(typ string, normalizeFunc func(res *Resource))
SetHumanReadableAttributesFunc(typ string, humanReadableAttributesFunc func(res *Resource) map[string]string)
SetResolveReadAttributesFunc(typ string, resolveReadAttributesFunc func(res *Resource) map[string]string)
SetDiscriminantFunc(string, func(*Resource, *Resource) bool)
}
type SchemaRepository struct {
schemas map[string]*Schema
ProviderName string
ProviderVersion *version.Version
}
func NewSchemaRepository() *SchemaRepository {
return &SchemaRepository{
schemas: make(map[string]*Schema),
}
}
func (r *SchemaRepository) GetSchema(resourceType string) (*Schema, bool) {
schema, exist := r.schemas[resourceType]
return schema, exist
}
func (r *SchemaRepository) fetchNestedBlocks(root string, metadata map[string]AttributeSchema, block map[string]*configschema.NestedBlock) {
for s, nestedBlock := range block {
path := s
if root != "" {
path = strings.Join([]string{root, s}, ".")
}
for s2, attr := range nestedBlock.Attributes {
nestedPath := strings.Join([]string{path, s2}, ".")
metadata[nestedPath] = AttributeSchema{
ConfigSchema: *attr,
}
}
r.fetchNestedBlocks(path, metadata, nestedBlock.BlockTypes)
}
}
func (r *SchemaRepository) Init(providerName, providerVersion string, schema map[string]providers.Schema) error {
v, err := version.NewVersion(providerVersion)
if err != nil {
return err
}
r.ProviderVersion = v
r.ProviderName = providerName
for typ, sch := range schema {
attributeMetas := map[string]AttributeSchema{}
for s, attribute := range sch.Block.Attributes {
attributeMetas[s] = AttributeSchema{
ConfigSchema: *attribute,
}
}
r.fetchNestedBlocks("", attributeMetas, sch.Block.BlockTypes)
r.schemas[typ] = &Schema{
ProviderVersion: r.ProviderVersion,
SchemaVersion: sch.Version,
Attributes: attributeMetas,
}
}
return nil
}
func (r SchemaRepository) SetFlags(typ string, flags ...Flags) {
metadata, exist := r.GetSchema(typ)
if !exist {
logrus.WithFields(logrus.Fields{"type": typ}).Warning("Unable to set flags, no schema found")
return
}
for _, flag := range flags {
metadata.Flags.AddFlag(flag)
}
}
func (r *SchemaRepository) UpdateSchema(typ string, schemasMutators map[string]func(attributeSchema *AttributeSchema)) {
for s, f := range schemasMutators {
metadata, exist := r.GetSchema(typ)
if !exist {
logrus.WithFields(logrus.Fields{"type": typ}).Warning("Unable to set metadata, no schema found")
return
}
m := (*metadata).Attributes[s]
f(&m)
(*metadata).Attributes[s] = m
}
}
func (r *SchemaRepository) SetNormalizeFunc(typ string, normalizeFunc func(res *Resource)) {
metadata, exist := r.GetSchema(typ)
if !exist {
logrus.WithFields(logrus.Fields{"type": typ}).Warning("Unable to set normalize func, no schema found")
return
}
(*metadata).NormalizeFunc = normalizeFunc
}
func (r *SchemaRepository) SetHumanReadableAttributesFunc(typ string, humanReadableAttributesFunc func(res *Resource) map[string]string) {
metadata, exist := r.GetSchema(typ)
if !exist {
logrus.WithFields(logrus.Fields{"type": typ}).Warning("Unable to add human readable attributes, no schema found")
return
}
(*metadata).HumanReadableAttributesFunc = humanReadableAttributesFunc
}
func (r *SchemaRepository) SetResolveReadAttributesFunc(typ string, resolveReadAttributesFunc func(res *Resource) map[string]string) {
metadata, exist := r.GetSchema(typ)
if !exist {
logrus.WithFields(logrus.Fields{"type": typ}).Warning("Unable to add read resource attributes, no schema found")
return
}
(*metadata).ResolveReadAttributesFunc = resolveReadAttributesFunc
}
func (r *SchemaRepository) SetDiscriminantFunc(typ string, fn func(self, res *Resource) bool) {
metadata, exist := r.GetSchema(typ)
if !exist {
logrus.WithFields(logrus.Fields{"type": typ}).Warning("Unable to set discriminant function, no schema found")
return
}
(*metadata).DiscriminantFunc = fn
}