@@ -42,7 +42,7 @@ var kindMap = map[reflect.Kind]string{
4242// Global registry for ResoureProvider, the goal is to make StructToSchema able to find pre-registered ResourceProvider for a
4343// given struct so that we don't have to specify aliases and customizations redundantly if one schema references the another
4444// schema.
45- var resourceProviderRegistry map [string ]ResourceProvider
45+ var resourceProviderRegistry map [reflect. Type ]ResourceProvider
4646
4747// Pre-registered ResourceProvider for a given struct into resourceProviderRegistry.
4848// This function should be called in the init() function in packages with ResourceProvider.
@@ -53,14 +53,27 @@ var resourceProviderRegistry map[string]ResourceProvider
5353// }
5454func RegisterResourceProvider (v any , r ResourceProvider ) {
5555 if resourceProviderRegistry == nil {
56- resourceProviderRegistry = make (map [string ]ResourceProvider )
56+ resourceProviderRegistry = make (map [reflect. Type ]ResourceProvider )
5757 }
58- typeName := getNameForType ( reflect . ValueOf ( v ). Type () )
59- if _ , ok := resourceProviderRegistry [typeName ]; ok {
60- errMsg := fmt .Sprintf ("%s has already been registered, please avoid registering the same type repeatedly." , typeName )
58+ t := getResourceProviderRegistryKey ( v )
59+ if _ , ok := resourceProviderRegistry [t ]; ok {
60+ errMsg := fmt .Sprintf ("%s has already been registered, please avoid registering the same type repeatedly." , getNameForType ( t ) )
6161 panic (errMsg )
6262 }
63- resourceProviderRegistry [typeName ] = r
63+ resourceProviderRegistry [t ] = r
64+ }
65+
66+ func getResourceProviderRegistryKey (v any ) reflect.Type {
67+ t := reflect .ValueOf (v ).Type ()
68+ return getNonPointerType (t )
69+ }
70+
71+ func getNonPointerType (t reflect.Type ) reflect.Type {
72+ if t .Kind () == reflect .Ptr {
73+ return t .Elem ()
74+ } else {
75+ return t
76+ }
6477}
6578
6679// Generic interface for ResourceProvider. Using CustomizeSchema function to keep track of additional information
@@ -69,6 +82,19 @@ type ResourceProvider interface {
6982 CustomizeSchema (* CustomizableSchema ) * CustomizableSchema
7083}
7184
85+ // Interface for ResourcePrivider that needs certain customizaitons that shouldn't be shared.
86+ type ResourceProviderWithResourceSpecificCustomization interface {
87+ ResourceProvider
88+ // Customizations in this function will not be applied when this type is referenced from another resource by resourceProviderRegistry.
89+ // Example use case:
90+ // // autotermination_minutes should only have a default value of 60 for the clusters resource, but not in the nested cluster schema in jobs
91+ // func (ClusterSpec) CustomizeSchemaResourceSpecific(s *common.CustomizableSchema) *common.CustomizableSchema {
92+ // s.SchemaPath("autotermination_minutes").SetDefault(60)
93+ // return s
94+ // }
95+ CustomizeSchemaResourceSpecific (* CustomizableSchema ) * CustomizableSchema
96+ }
97+
7298// Interface for ResourceProvider instances that need aliases for fields.
7399type ResourceProviderWithAlias interface {
74100 ResourceProvider
@@ -100,8 +126,19 @@ type RecursiveResourceProvider interface {
100126 MaxDepthForTypes () map [string ]int
101127}
102128
103- // Takes in a ResourceProvider and converts that into a map from string to schema.
129+ // Used by StructToSchema, after executing typeToSchema and applying the standard customizations,
130+ // it also applies the resource specific customizations, if applicable.
104131func resourceProviderStructToSchema (v ResourceProvider , scp schemaPathContext ) map [string ]* schema.Schema {
132+ customizedScm := resourceProviderStructToSchemaInternal (v , scp )
133+ if rps , ok := v .(ResourceProviderWithResourceSpecificCustomization ); ok {
134+ // Apply resource specific customizations, if applicable.
135+ return rps .CustomizeSchemaResourceSpecific (customizedScm ).GetSchemaMap ()
136+ } else {
137+ return customizedScm .GetSchemaMap ()
138+ }
139+ }
140+
141+ func resourceProviderStructToSchemaInternal (v ResourceProvider , scp schemaPathContext ) * CustomizableSchema {
105142 rv := reflect .ValueOf (v )
106143 var scm map [string ]* schema.Schema
107144 aliases := map [string ]map [string ]string {}
@@ -115,8 +152,7 @@ func resourceProviderStructToSchema(v ResourceProvider, scp schemaPathContext) m
115152 }
116153 cs := CustomizeSchemaPath (scm )
117154 cs .context = scp
118- scm = v .CustomizeSchema (cs ).GetSchemaMap ()
119- return scm
155+ return v .CustomizeSchema (cs )
120156}
121157
122158func reflectKind (k reflect.Kind ) string {
@@ -372,6 +408,9 @@ func listAllFields(v reflect.Value) []field {
372408}
373409
374410func typeToSchema (v reflect.Value , aliases map [string ]map [string ]string , tc trackingContext ) map [string ]* schema.Schema {
411+ if rpStruct , ok := resourceProviderRegistry [getNonPointerType (v .Type ())]; ok {
412+ return resourceProviderStructToSchemaInternal (rpStruct , tc .pathCtx ).GetSchemaMap ()
413+ }
375414 scm := map [string ]* schema.Schema {}
376415 rk := v .Kind ()
377416 if rk == reflect .Ptr {
0 commit comments