@@ -31,17 +31,13 @@ type PtrClientObj[T any] interface {
3131 client.Object
3232}
3333
34- // Translator allows to translate back and forth between a CRD schema version
35- // and SDK API structures of a certain version
34+ // Translator allows to translate back and forth between a CRD schema
35+ // and SDK API structures of a certain version.
36+ // A translator is an immutable configuration object, it can be safely shared
37+ // across threads
3638type Translator struct {
3739 crd CRDInfo
38- majorVersion MajorVersion
39- deps DependencyRepo
40- }
41-
42- // MajorVersion holds the SDK version information
43- type MajorVersion struct {
44- version string
40+ majorVersion string
4541}
4642
4743// APIImporter can translate itself into Kubernetes Objects.
@@ -69,16 +65,15 @@ type APIExporter[T any] interface {
6965// v20250312:
7066//
7167// In the above case crdVersion is "v1" and majorVersion is "v20250312".
72- func NewTranslator (crd * apiextensionsv1.CustomResourceDefinition , crdVersion string , majorVersion string , deps DependencyRepo ) * Translator {
68+ func NewTranslator (crd * apiextensionsv1.CustomResourceDefinition , crdVersion string , majorVersion string ) * Translator {
7369 return & Translator {
7470 crd : CRDInfo {definition : crd , version : crdVersion },
75- majorVersion : MajorVersion {version : majorVersion },
76- deps : deps ,
71+ majorVersion : majorVersion ,
7772 }
7873}
7974
80- // FromAPI translaters a source API structure into a Kubernetes object
81- func FromAPI [S any , T any , P PtrClientObj [T ]](t * Translator , target P , source * S ) ([]client.Object , error ) {
75+ // FromAPI translaters a source API structure into a Kubernetes object.
76+ func FromAPI [S any , T any , P PtrClientObj [T ]](t * Translator , target P , source * S , objs ... client. Object ) ([]client.Object , error ) {
8277 importer , ok := any (source ).(APIImporter [T , P ])
8378 if ok {
8479 return importer .FromAPI (t , target )
@@ -92,7 +87,7 @@ func FromAPI[S any, T any, P PtrClientObj[T]](t *Translator, target P, source *S
9287
9388 versionedSpec := map [string ]any {}
9489 copyFields (versionedSpec , sourceUnstructured )
95- if err := createField (targetUnstructured , versionedSpec , "spec" , t .majorVersion . version ); err != nil {
90+ if err := createField (targetUnstructured , versionedSpec , "spec" , t .majorVersion ); err != nil {
9691 return nil , fmt .Errorf ("failed to create versioned spec object in unstructured target: %w" , err )
9792 }
9893 versionedSpecEntry := map [string ]any {}
@@ -101,11 +96,12 @@ func FromAPI[S any, T any, P PtrClientObj[T]](t *Translator, target P, source *S
10196
10297 versionedStatus := map [string ]any {}
10398 copyFields (versionedStatus , sourceUnstructured )
104- if err := createField (targetUnstructured , versionedStatus , "status" , t .majorVersion . version ); err != nil {
99+ if err := createField (targetUnstructured , versionedStatus , "status" , t .majorVersion ); err != nil {
105100 return nil , fmt .Errorf ("failed to create versioned status object in unsstructured target: %w" , err )
106101 }
107102
108- extraObjects , err := t .expandMappings (targetUnstructured )
103+ deps := NewDependencies (target , objs ... )
104+ extraObjects , err := t .expandMappings (deps , targetUnstructured )
109105 if err != nil {
110106 return nil , fmt .Errorf ("failed to process API mappings: %w" , err )
111107 }
@@ -116,7 +112,7 @@ func FromAPI[S any, T any, P PtrClientObj[T]](t *Translator, target P, source *S
116112}
117113
118114// ToAPI translates a source Kubernetes spec into a target API structure
119- func ToAPI [T any ](t * Translator , target * T , source client.Object ) error {
115+ func ToAPI [T any ](t * Translator , target * T , source client.Object , objs ... client. Object ) error {
120116 exporter , ok := (source ).(APIExporter [T ])
121117 if ok {
122118 return exporter .ToAPI (t , target )
@@ -131,20 +127,21 @@ func ToAPI[T any](t *Translator, target *T, source client.Object) error {
131127 if err != nil {
132128 return fmt .Errorf ("failed to enumerate CRD spec properties: %w" , err )
133129 }
134- if _ , ok := specProps [t .majorVersion . version ]; ! ok {
135- return fmt .Errorf ("failed to match the CRD spec version %q in schema" , t .majorVersion . version )
130+ if _ , ok := specProps [t .majorVersion ]; ! ok {
131+ return fmt .Errorf ("failed to match the CRD spec version %q in schema" , t .majorVersion )
136132 }
137133 unstructuredSrc , err := toUnstructured (source )
138134 if err != nil {
139135 return fmt .Errorf ("failed to convert k8s source value to unstructured: %w" , err )
140136 }
141137 targetUnstructured := map [string ]any {}
142- value , err := accessField [map [string ]any ](unstructuredSrc , "spec" , t .majorVersion . version )
138+ value , err := accessField [map [string ]any ](unstructuredSrc , "spec" , t .majorVersion )
143139 if err != nil {
144140 return fmt .Errorf ("failed to access source spec value: %w" , err )
145141 }
146142
147- if err := t .collapseMappings (value ); err != nil {
143+ deps := NewDependencies (source , objs ... )
144+ if err := t .collapseMappings (deps , value ); err != nil {
148145 return fmt .Errorf ("failed to process API mappings: %w" , err )
149146 }
150147
@@ -176,7 +173,7 @@ func ToAPI[T any](t *Translator, target *T, source client.Object) error {
176173 return nil
177174}
178175
179- func (t * Translator ) expandMappings (obj map [string ]any ) ([]client.Object , error ) {
176+ func (t * Translator ) expandMappings (deps DependencyRepo , obj map [string ]any ) ([]client.Object , error ) {
180177 mappingsYML := t .crd .definition .Annotations [APIMAppingsAnnotation ]
181178 if mappingsYML == "" {
182179 return []client.Object {}, nil
@@ -186,19 +183,19 @@ func (t *Translator) expandMappings(obj map[string]any) ([]client.Object, error)
186183 return nil , fmt .Errorf ("failed to unmarshal mappings YAML: %w" , err )
187184 }
188185
189- if err := t .expandMappingsAt (obj , mappings , "spec" , t .majorVersion . version ); err != nil {
186+ if err := t .expandMappingsAt (deps , obj , mappings , "spec" , t .majorVersion ); err != nil {
190187 return nil , fmt .Errorf ("failed to map properties of spec from API to Kubernetes: %w" , err )
191188 }
192- if err := t .expandMappingsAt (obj , mappings , "spec" , t .majorVersion . version , "entry" ); err != nil {
189+ if err := t .expandMappingsAt (deps , obj , mappings , "spec" , t .majorVersion , "entry" ); err != nil {
193190 return nil , fmt .Errorf ("failed to map properties of spec from API to Kubernetes: %w" , err )
194191 }
195- if err := t .expandMappingsAt (obj , mappings , "status" , t .majorVersion . version ); err != nil {
192+ if err := t .expandMappingsAt (deps , obj , mappings , "status" , t .majorVersion ); err != nil {
196193 return nil , fmt .Errorf ("failed to map properties of status from API to Kubernetes: %w" , err )
197194 }
198- return t . deps .Added (), nil
195+ return deps .Added (), nil
199196}
200197
201- func (t * Translator ) expandMappingsAt (obj , mappings map [string ]any , fields ... string ) error {
198+ func (t * Translator ) expandMappingsAt (deps DependencyRepo , obj , mappings map [string ]any , fields ... string ) error {
202199 expandedPath := []string {"properties" }
203200 for _ , field := range fields {
204201 expandedPath = append (expandedPath , field , "properties" )
@@ -214,14 +211,14 @@ func (t *Translator) expandMappingsAt(obj, mappings map[string]any, fields ...st
214211 if err != nil {
215212 return fmt .Errorf ("failed to access object's %v: %w" , fields , err )
216213 }
217- mapper := Mapper {deps : t . deps , expand : true }
214+ mapper := Mapper {deps : deps , expand : true }
218215 if err := mapper .mapProperties ([]string {}, props , field ); err != nil {
219216 return fmt .Errorf ("failed to process properties from API into %v: %w" , fields , err )
220217 }
221218 return nil
222219}
223220
224- func (t * Translator ) collapseMappings (spec map [string ]any ) error {
221+ func (t * Translator ) collapseMappings (deps DependencyRepo , spec map [string ]any ) error {
225222 mappingsYML := t .crd .definition .Annotations [APIMAppingsAnnotation ]
226223 if mappingsYML == "" {
227224 return nil
@@ -231,14 +228,14 @@ func (t *Translator) collapseMappings(spec map[string]any) error {
231228 return fmt .Errorf ("failed to unmarshal mappings YAML: %w" , err )
232229 }
233230 props , err := accessField [map [string ]any ](mappings ,
234- "properties" , "spec" , "properties" , t .majorVersion . version , "properties" )
231+ "properties" , "spec" , "properties" , t .majorVersion , "properties" )
235232 if errors .Is (err , ErrNotFound ) {
236233 return nil
237234 }
238235 if err != nil {
239236 return fmt .Errorf ("failed to access the API mapping properties for the spec: %w" , err )
240237 }
241- mapper := Mapper {deps : t . deps , expand : false }
238+ mapper := Mapper {deps : deps , expand : false }
242239 return mapper .mapProperties ([]string {}, props , spec )
243240}
244241
0 commit comments