@@ -7,13 +7,24 @@ package manifests
77
88import (
99 "bytes"
10+ "io"
1011 "io/fs"
1112 "os"
1213 "path/filepath"
1314 "text/template"
1415
1516 "github.com/Masterminds/sprig/v3"
17+ "github.com/drone/envsubst"
18+ "github.com/sap/go-generics/slices"
1619
20+ "k8s.io/apimachinery/pkg/apis/meta/v1/unstructured"
21+ utilyaml "k8s.io/apimachinery/pkg/util/yaml"
22+ "sigs.k8s.io/controller-runtime/pkg/client"
23+ "sigs.k8s.io/kustomize/api/konfig"
24+ "sigs.k8s.io/kustomize/api/krusty"
25+ kusttypes "sigs.k8s.io/kustomize/api/types"
26+ kustfsys "sigs.k8s.io/kustomize/kyaml/filesys"
27+ "sigs.k8s.io/kustomize/kyaml/resid"
1728 kyaml "sigs.k8s.io/yaml"
1829
1930 "github.com/sap/component-operator-runtime/internal/templatex"
@@ -70,3 +81,162 @@ func (t *TemplateParameterTransformer) TransformParameters(namespace string, nam
7081 }
7182 return transformedParameters , nil
7283}
84+
85+ type SubstitutionObjectTransformer struct {
86+ substitutions map [string ]string
87+ selector types.Selector [client.Object ]
88+ }
89+
90+ var _ ObjectTransformer = & SubstitutionObjectTransformer {}
91+
92+ func NewSubstitutionObjectTransformer (substitutions map [string ]string , selector types.Selector [client.Object ]) (* SubstitutionObjectTransformer , error ) {
93+ return & SubstitutionObjectTransformer {
94+ substitutions : substitutions ,
95+ selector : selector ,
96+ }, nil
97+ }
98+
99+ func (t * SubstitutionObjectTransformer ) TransformObjects (namespace string , name string , objects []client.Object ) ([]client.Object , error ) {
100+ if len (t .substitutions ) == 0 {
101+ return objects , nil
102+ }
103+
104+ var transformedObjects []client.Object
105+
106+ for _ , object := range objects {
107+ if ! t .selector .Matches (object ) {
108+ transformedObjects = append (transformedObjects , object )
109+ continue
110+ }
111+ rawObject , err := kyaml .Marshal (object )
112+ if err != nil {
113+ return nil , err
114+ }
115+ stringObject := string (rawObject )
116+ stringObject , err = envsubst .Eval (stringObject , func (s string ) string {
117+ return t .substitutions [s ]
118+ })
119+ if err != nil {
120+ return nil , err
121+ }
122+ rawObject = []byte (stringObject )
123+ if err := kyaml .Unmarshal (rawObject , object ); err != nil {
124+ return nil , err
125+ }
126+ transformedObjects = append (transformedObjects , object )
127+ }
128+
129+ return transformedObjects , nil
130+ }
131+
132+ type KustomizeObjectTransformer struct {
133+ patches []KustomizePatch
134+ images []KustomizeImage
135+ kustomizer * krusty.Kustomizer
136+ }
137+
138+ var _ ObjectTransformer = & KustomizeObjectTransformer {}
139+
140+ func NewKustomizeObjectTransformer (patches []KustomizePatch , images []KustomizeImage ) (* KustomizeObjectTransformer , error ) {
141+ kustomizerOptions := & krusty.Options {
142+ LoadRestrictions : kusttypes .LoadRestrictionsNone ,
143+ PluginConfig : kusttypes .DisabledPluginConfig (),
144+ }
145+ kustomizer := krusty .MakeKustomizer (kustomizerOptions )
146+
147+ return & KustomizeObjectTransformer {
148+ patches : patches ,
149+ images : images ,
150+ kustomizer : kustomizer ,
151+ }, nil
152+ }
153+
154+ func (t * KustomizeObjectTransformer ) TransformObjects (namespace string , name string , objects []client.Object ) ([]client.Object , error ) {
155+ const resourcePath = "objects.yaml"
156+
157+ fsys := kustfsys .MakeFsInMemory ()
158+
159+ var buf bytes.Buffer
160+ for _ , object := range objects {
161+ rawObject , err := kyaml .Marshal (object )
162+ if err != nil {
163+ return nil , err
164+ }
165+ // note: no need to handle write errors below, they are always nil (see documentation)
166+ buf .WriteString ("---\n " )
167+ buf .Write (rawObject )
168+ }
169+ if err := fsys .WriteFile (resourcePath , buf .Bytes ()); err != nil {
170+ return nil , err
171+ }
172+
173+ kustomization := kusttypes.Kustomization {
174+ TypeMeta : kusttypes.TypeMeta {
175+ APIVersion : kusttypes .KustomizationVersion ,
176+ Kind : kusttypes .KustomizationKind ,
177+ },
178+ Resources : []string {resourcePath },
179+ Images : slices .Collect (t .images , func (i KustomizeImage ) kusttypes.Image {
180+ return kusttypes.Image {
181+ Name : i .Name ,
182+ NewName : i .NewName ,
183+ NewTag : i .NewTag ,
184+ Digest : i .Digest ,
185+ }
186+ }),
187+ Patches : slices .Collect (t .patches , func (p KustomizePatch ) kusttypes.Patch {
188+ return kusttypes.Patch {
189+ Patch : p .Patch ,
190+ Target : & kusttypes.Selector {
191+ ResId : resid.ResId {
192+ Gvk : resid.Gvk {
193+ Group : p .Target .Group ,
194+ Version : p .Target .Version ,
195+ Kind : p .Target .Kind ,
196+ },
197+ Name : p .Target .Name ,
198+ Namespace : p .Target .Namespace ,
199+ },
200+ LabelSelector : p .Target .LabelSelector ,
201+ AnnotationSelector : p .Target .AnnotationSelector ,
202+ },
203+ }
204+ }),
205+ }
206+ rawKustomization , err := kyaml .Marshal (kustomization )
207+ if err != nil {
208+ return nil , err
209+ }
210+ if err := fsys .WriteFile (konfig .DefaultKustomizationFileName (), rawKustomization ); err != nil {
211+ return nil , err
212+ }
213+
214+ resmap , err := t .kustomizer .Run (fsys , "." )
215+ if err != nil {
216+ return nil , err
217+ }
218+
219+ raw , err := resmap .AsYaml ()
220+ if err != nil {
221+ return nil , err
222+ }
223+
224+ var transformedObjects []client.Object
225+
226+ decoder := utilyaml .NewYAMLToJSONDecoder (bytes .NewBuffer (raw ))
227+ for {
228+ object := & unstructured.Unstructured {}
229+ if err := decoder .Decode (& object .Object ); err != nil {
230+ if err == io .EOF {
231+ break
232+ }
233+ return nil , err
234+ }
235+ if object .Object == nil {
236+ continue
237+ }
238+ transformedObjects = append (transformedObjects , object )
239+ }
240+
241+ return transformedObjects , nil
242+ }
0 commit comments