7
7
"fmt"
8
8
"sort"
9
9
"strings"
10
+ "sync"
10
11
11
12
"github.com/vmware-tanzu/carvel-kapp-controller/pkg/apis/kappctrl/v1alpha1"
12
13
kcv1alpha1 "github.com/vmware-tanzu/carvel-kapp-controller/pkg/apis/kappctrl/v1alpha1"
@@ -27,6 +28,7 @@ const (
27
28
ExtYttPathsFromSecretNameAnnKey = "ext.packaging.carvel.dev/ytt-paths-from-secret-name"
28
29
ExtHelmPathsFromSecretNameAnnKey = "ext.packaging.carvel.dev/helm-template-values-from-secret-name"
29
30
31
+ // ExtYttDataValuesOverlaysAnnKey if set, adds the pkgi's values secrets as overlays/paths, not as values, to the app
30
32
ExtYttDataValuesOverlaysAnnKey = "ext.packaging.carvel.dev/ytt-data-values-overlays"
31
33
32
34
ExtFetchSecretNameAnnKeyFmt = "ext.packaging.carvel.dev/fetch-%d-secret-name"
@@ -98,88 +100,213 @@ func NewApp(existingApp *v1alpha1.App, pkgInstall *pkgingv1alpha1.PackageInstall
98
100
}
99
101
}
100
102
101
- valuesApplied := false
102
- yttPathsApplied := false
103
- helmPathsApplied := false
104
-
105
- for i , templateStep := range desiredApp .Spec .Template {
106
- if templateStep .HelmTemplate != nil {
107
- if ! helmPathsApplied {
108
- helmPathsApplied = true
109
-
110
- if _ , found := pkgInstall .Annotations [HelmTemplateOverlayNameKey ]; found {
111
- templateStep .HelmTemplate .Name = pkgInstall .Annotations [HelmTemplateOverlayNameKey ]
112
- }
113
- if _ , found := pkgInstall .Annotations [HelmTemplateOverlayNameSpaceKey ]; found {
114
- templateStep .HelmTemplate .Namespace = pkgInstall .Annotations [HelmTemplateOverlayNameSpaceKey ]
115
- }
116
- for _ , secretName := range secretNamesFromAnn (pkgInstall , ExtHelmPathsFromSecretNameAnnKey ) {
117
- templateStep .HelmTemplate .ValuesFrom = append (templateStep .HelmTemplate .ValuesFrom , kcv1alpha1.AppTemplateValuesSource {
118
- SecretRef : & kcv1alpha1.AppTemplateValuesSourceRef {
119
- Name : secretName ,
120
- },
121
- })
122
- }
123
- }
124
- if ! valuesApplied {
125
- valuesApplied = true
126
-
127
- for _ , value := range pkgInstall .Spec .Values {
128
- templateStep .HelmTemplate .ValuesFrom = append (templateStep .HelmTemplate .ValuesFrom , kcv1alpha1.AppTemplateValuesSource {
129
- SecretRef : & kcv1alpha1.AppTemplateValuesSourceRef {
130
- Name : value .SecretRef .Name ,
131
- },
132
- })
133
- }
134
- }
103
+ templatesPatcher := templateStepsPatcher {
104
+ yttPatcher : & yttStepPatcher {
105
+ addValuesAsInlinePaths : pkgiHasAnnotation (pkgInstall , ExtYttDataValuesOverlaysAnnKey ),
106
+ additionalPaths : secretNamesFromAnn (pkgInstall , ExtYttPathsFromSecretNameAnnKey ),
107
+ },
108
+ helmPatcher : & helmStepPatcher {
109
+ additionalPaths : secretNamesFromAnn (pkgInstall , ExtHelmPathsFromSecretNameAnnKey ),
110
+ name : pkgiAnnotationValue (pkgInstall , HelmTemplateOverlayNameKey ),
111
+ namespace : pkgiAnnotationValue (pkgInstall , HelmTemplateOverlayNameSpaceKey ),
112
+ },
113
+ cuePatcher : & cueStepPatcher {},
114
+
115
+ templateSteps : desiredApp .Spec .Template ,
116
+ values : pkgInstall .Spec .Values ,
117
+ }
118
+
119
+ if err := templatesPatcher .patch (); err != nil {
120
+ return & v1alpha1.App {}, err
121
+ }
122
+
123
+ return desiredApp , nil
124
+ }
125
+
126
+ type stepClass string
127
+
128
+ const (
129
+ // anything that can take values
130
+ stepClassValueable stepClass = "valueable"
131
+ // only helm template steps
132
+ stepClassHelm stepClass = "helm"
133
+ // only ytt template steps
134
+ stepClassYtt stepClass = "ytt"
135
+ // only cue template steps
136
+ stepClassCue stepClass = "cue"
137
+ )
138
+
139
+ type yttStepPatcher struct {
140
+ addValuesAsInlinePaths bool // TODO: support multiple ytt steps
141
+ additionalPaths []string // TODO: support multiple ytt steps
142
+ }
143
+
144
+ func (yp * yttStepPatcher ) addValues (yttStep * kcv1alpha1.AppTemplateYtt , value pkgingv1alpha1.PackageInstallValues ) {
145
+ if yp .addValuesAsInlinePaths {
146
+ addSecretAsInlinePath (& yttStep .Inline , value .SecretRef .Name )
147
+ } else {
148
+ addSecretAsValueSource (& yttStep .ValuesFrom , value .SecretRef .Name )
149
+ }
150
+ }
151
+
152
+ func (yp * yttStepPatcher ) addPaths (yttStep * kcv1alpha1.AppTemplateYtt ) {
153
+ for _ , secretName := range yp .additionalPaths {
154
+ addSecretAsInlinePath (& yttStep .Inline , secretName )
155
+ }
156
+ }
157
+
158
+ type helmStepPatcher struct {
159
+ additionalPaths []string
160
+ name string // TODO: support multiple helm steps
161
+ namespace string // TODO: support multiple helm steps
162
+ }
163
+
164
+ func (hp * helmStepPatcher ) addValues (helmStep * kcv1alpha1.AppTemplateHelmTemplate , value pkgingv1alpha1.PackageInstallValues ) {
165
+ addSecretAsValueSource (& helmStep .ValuesFrom , value .SecretRef .Name )
166
+ }
167
+
168
+ func (hp * helmStepPatcher ) addPaths (helmStep * kcv1alpha1.AppTemplateHelmTemplate ) {
169
+ for _ , secretName := range hp .additionalPaths {
170
+ addSecretAsValueSource (& helmStep .ValuesFrom , secretName )
171
+ }
172
+ }
173
+
174
+ func (hp * helmStepPatcher ) setNameAndNamespace (helmStep * kcv1alpha1.AppTemplateHelmTemplate ) {
175
+ if hp .name != "" {
176
+ helmStep .Name = hp .name
177
+ }
178
+ if hp .namespace != "" {
179
+ helmStep .Namespace = hp .namespace
180
+ }
181
+ }
182
+
183
+ type cueStepPatcher struct {}
184
+
185
+ func (cp * cueStepPatcher ) addValues (cueStep * kcv1alpha1.AppTemplateCue , value pkgingv1alpha1.PackageInstallValues ) {
186
+ addSecretAsValueSource (& cueStep .ValuesFrom , value .SecretRef .Name )
187
+ }
188
+
189
+ type templateStepsPatcher struct {
190
+ templateSteps []kcv1alpha1.AppTemplate
191
+ values []pkgingv1alpha1.PackageInstallValues
192
+
193
+ yttPatcher * yttStepPatcher
194
+ helmPatcher * helmStepPatcher
195
+ cuePatcher * cueStepPatcher
196
+
197
+ classifiedSteps [][]stepClass
198
+ once sync.Once
199
+ }
200
+
201
+ func (p * templateStepsPatcher ) classifySteps () {
202
+ p .classifiedSteps = make ([][]stepClass , len (p .templateSteps ))
203
+
204
+ for i , step := range p .templateSteps {
205
+ classes := []stepClass {}
206
+
207
+ if step .HelmTemplate != nil {
208
+ classes = append (classes , stepClassHelm , stepClassValueable )
209
+ }
210
+ if step .Ytt != nil {
211
+ classes = append (classes , stepClassYtt , stepClassValueable )
135
212
}
213
+ if step .Cue != nil {
214
+ classes = append (classes , stepClassCue , stepClassValueable )
215
+ }
216
+
217
+ p .classifiedSteps [i ] = classes
218
+ }
219
+ }
220
+
221
+ func (p * templateStepsPatcher ) stepHasClass (stepIdx int , class stepClass ) bool {
222
+ p .once .Do (p .classifySteps )
223
+
224
+ for _ , stepClass := range p .classifiedSteps [stepIdx ] {
225
+ if stepClass == class {
226
+ return true
227
+ }
228
+ }
229
+
230
+ return false
231
+ }
232
+
233
+ func (p * templateStepsPatcher ) getClassifiedSteps (class stepClass ) []int {
234
+ p .once .Do (p .classifySteps )
136
235
137
- if templateStep .Ytt != nil {
138
- if ! yttPathsApplied {
139
- yttPathsApplied = true
140
-
141
- for _ , secretName := range secretNamesFromAnn (pkgInstall , ExtYttPathsFromSecretNameAnnKey ) {
142
- if templateStep .Ytt .Inline == nil {
143
- templateStep .Ytt .Inline = & kcv1alpha1.AppFetchInline {}
144
- }
145
- templateStep .Ytt .Inline .PathsFrom = append (templateStep .Ytt .Inline .PathsFrom , kcv1alpha1.AppFetchInlineSource {
146
- SecretRef : & kcv1alpha1.AppFetchInlineSourceRef {
147
- Name : secretName ,
148
- },
149
- })
150
- }
236
+ steps := []int {}
237
+ for i := range p .classifiedSteps {
238
+ if p .stepHasClass (i , class ) {
239
+ steps = append (steps , i )
240
+ }
241
+ }
242
+
243
+ return steps
244
+ }
245
+
246
+ func (p * templateStepsPatcher ) firstOf (class stepClass ) (int , bool ) {
247
+ classifiedSteps := p .getClassifiedSteps (class )
248
+ if len (classifiedSteps ) < 1 {
249
+ return 0 , false
250
+ }
251
+
252
+ return classifiedSteps [0 ], true
253
+ }
254
+
255
+ func (p * templateStepsPatcher ) defaultStepIdxs (stepIdxs []int , class stepClass ) ([]int , error ) {
256
+ if len (stepIdxs ) > 0 {
257
+ return stepIdxs , nil
258
+ }
259
+
260
+ first , ok := p .firstOf (class )
261
+ if ok {
262
+ return []int {first }, nil
263
+ }
264
+
265
+ return []int {}, fmt .Errorf ("no template step of class '%s' found" , class )
266
+ }
267
+
268
+ func (p * templateStepsPatcher ) patch () error {
269
+ for _ , values := range p .values {
270
+ stepIdxs , err := p .defaultStepIdxs (values .TemplateSteps , stepClassValueable )
271
+ if err != nil {
272
+ return err
273
+ }
274
+
275
+ for _ , stepIdx := range stepIdxs {
276
+ if stepIdx < 0 || stepIdx >= len (p .templateSteps ) {
277
+ return fmt .Errorf ("template step %d out of range" , stepIdx )
278
+ }
279
+ if ! p .stepHasClass (stepIdx , stepClassValueable ) {
280
+ return fmt .Errorf ("template step %d does not support values" , stepIdx )
151
281
}
152
282
153
- if ! valuesApplied {
154
- valuesApplied = true
155
-
156
- if _ , found := pkgInstall .Annotations [ExtYttDataValuesOverlaysAnnKey ]; found {
157
- if templateStep .Ytt .Inline == nil {
158
- templateStep .Ytt .Inline = & kcv1alpha1.AppFetchInline {}
159
- }
160
- for _ , value := range pkgInstall .Spec .Values {
161
- templateStep .Ytt .Inline .PathsFrom = append (templateStep .Ytt .Inline .PathsFrom , kcv1alpha1.AppFetchInlineSource {
162
- SecretRef : & kcv1alpha1.AppFetchInlineSourceRef {
163
- Name : value .SecretRef .Name ,
164
- },
165
- })
166
- }
167
- } else {
168
- for _ , value := range pkgInstall .Spec .Values {
169
- templateStep .Ytt .ValuesFrom = append (templateStep .Ytt .ValuesFrom , kcv1alpha1.AppTemplateValuesSource {
170
- SecretRef : & kcv1alpha1.AppTemplateValuesSourceRef {
171
- Name : value .SecretRef .Name ,
172
- },
173
- })
174
- }
175
- }
283
+ templateStep := p .templateSteps [stepIdx ]
284
+
285
+ switch {
286
+ case p .stepHasClass (stepIdx , stepClassYtt ):
287
+ p .yttPatcher .addValues (templateStep .Ytt , values )
288
+
289
+ case p .stepHasClass (stepIdx , stepClassHelm ):
290
+ p .helmPatcher .addValues (templateStep .HelmTemplate , values )
291
+
292
+ case p .stepHasClass (stepIdx , stepClassCue ):
293
+ p .cuePatcher .addValues (templateStep .Cue , values )
176
294
}
177
295
}
296
+ }
178
297
179
- desiredApp .Spec .Template [i ] = templateStep
298
+ for _ , stepIdx := range p .getClassifiedSteps (stepClassYtt ) {
299
+ p .yttPatcher .addPaths (p .templateSteps [stepIdx ].Ytt )
300
+ break // TODO: support multiple ytt steps
301
+ }
302
+ for _ , stepIdx := range p .getClassifiedSteps (stepClassHelm ) {
303
+ ts := p .templateSteps [stepIdx ].HelmTemplate
304
+ p .helmPatcher .addPaths (ts )
305
+ p .helmPatcher .setNameAndNamespace (ts )
306
+ break // TODO: support multiple helm steps
180
307
}
181
308
182
- return desiredApp , nil
309
+ return nil
183
310
}
184
311
185
312
func secretNamesFromAnn (installedPkg * pkgingv1alpha1.PackageInstall , annKey string ) []string {
@@ -206,3 +333,38 @@ func secretNamesFromAnn(installedPkg *pkgingv1alpha1.PackageInstall, annKey stri
206
333
}
207
334
return result
208
335
}
336
+
337
+ func pkgiAnnotationValue (pkgi * pkgingv1alpha1.PackageInstall , key string ) string {
338
+ if anno , found := pkgi .Annotations [key ]; found {
339
+ return anno
340
+ }
341
+ return ""
342
+ }
343
+
344
+ func pkgiHasAnnotation (pkgi * pkgingv1alpha1.PackageInstall , key string ) bool {
345
+ _ , found := pkgi .Annotations [key ]
346
+ return found
347
+ }
348
+
349
+ // addSecretAsInlinePath adds a secret as an inline path to the provided inline
350
+ // fetches. If the inline fetch is nil, it is initialized.
351
+ func addSecretAsInlinePath (inline * * kcv1alpha1.AppFetchInline , secretName string ) {
352
+ if * inline == nil {
353
+ * inline = & kcv1alpha1.AppFetchInline {}
354
+ }
355
+ (* inline ).PathsFrom = append ((* inline ).PathsFrom , kcv1alpha1.AppFetchInlineSource {
356
+ SecretRef : & kcv1alpha1.AppFetchInlineSourceRef {
357
+ Name : secretName ,
358
+ },
359
+ })
360
+ }
361
+
362
+ // addSecretAsValueSource adds a secret as a value source to the provided
363
+ // template values sources.
364
+ func addSecretAsValueSource (values * []kcv1alpha1.AppTemplateValuesSource , secretName string ) {
365
+ * values = append (* values , kcv1alpha1.AppTemplateValuesSource {
366
+ SecretRef : & kcv1alpha1.AppTemplateValuesSourceRef {
367
+ Name : secretName ,
368
+ },
369
+ })
370
+ }
0 commit comments