@@ -3,6 +3,8 @@ package helm
3
3
import (
4
4
"context"
5
5
"fmt"
6
+ "helm.sh/helm/v3/pkg/chartutil"
7
+ "k8s.io/apimachinery/pkg/util/yaml"
6
8
"sort"
7
9
"strings"
8
10
@@ -19,10 +21,11 @@ import (
19
21
)
20
22
21
23
const (
22
- helmRepositoryCache = "/tmp/.helmcache"
23
- helmRepositoryConfig = "/tmp/.helmrepo"
24
- helmRegistryConfigFile = "/tmp/.helmregistry/config.json"
25
- ociSchemePrefix = string (config .EndpointSchemaOCI + "://" )
24
+ helmRepositoryCache = "/tmp/.helmcache"
25
+ helmRepositoryConfig = "/tmp/.helmrepo"
26
+ helmRegistryConfigFile = "/tmp/.helmregistry/config.json"
27
+ ociSchemePrefix = string (config .EndpointSchemaOCI + "://" )
28
+ helmValuesMetadataFileName = "component-values-metadata.yaml"
26
29
)
27
30
28
31
// HelmClient embeds the client.Client interface for usage in this package.
@@ -67,6 +70,10 @@ func NewClient(namespace string, helmRepoData *config.HelmRepositoryData, debug
67
70
68
71
// InstallOrUpgrade takes a helmChart and applies it.
69
72
func (c * Client ) InstallOrUpgrade (ctx context.Context , chart * client.ChartSpec ) error {
73
+ return c .InstallOrUpgradeWithMappedValues (ctx , chart , nil )
74
+ }
75
+
76
+ func (c * Client ) InstallOrUpgradeWithMappedValues (ctx context.Context , chart * client.ChartSpec , mappedValues map [string ]string ) error {
70
77
// This helm-client currently only works with OCI-Helm-Repositories.
71
78
// Therefore, the chartName has to include the FQDN of the repository (e.g. "oci://my.repo/...")
72
79
// If in the future non-oci-repositories need to be used, this should be done here...
@@ -76,6 +83,10 @@ func (c *Client) InstallOrUpgrade(ctx context.Context, chart *client.ChartSpec)
76
83
return fmt .Errorf ("error patching chart-version for chart %s: %w" , chart .ChartName , err )
77
84
}
78
85
86
+ if err := c .patchMappedValues (ctx , chart , mappedValues ); err != nil {
87
+ return err
88
+ }
89
+
79
90
_ , err := c .helmClient .InstallOrUpgradeChart (ctx , chart )
80
91
if err != nil {
81
92
return fmt .Errorf ("error while installOrUpgrade chart %s: %w" , chart .ChartName , err )
@@ -154,6 +165,107 @@ func (c *Client) GetChartSpecValues(spec *client.ChartSpec) (map[string]interfac
154
165
return c .helmClient .GetChartSpecValues (spec )
155
166
}
156
167
168
+ type helmValuesMetadata struct {
169
+ ApiVersion string `yaml:"apiVersion"`
170
+ Metadata map [string ]helmValuesMetadataEntry `yaml:"metadata"`
171
+ }
172
+
173
+ type helmValuesMetadataEntry struct {
174
+ Name string `yaml:"name"`
175
+ Description string `yaml:"description"`
176
+ Keys []helmValuesMetadataKey `yaml:"keys"`
177
+ }
178
+
179
+ type helmValuesMetadataKey struct {
180
+ Path string `yaml:"path"`
181
+ }
182
+
183
+ func (c * Client ) patchMappedValues (ctx context.Context , chartSpec * client.ChartSpec , mappedValues map [string ]string ) error {
184
+ logger := log .FromContext (ctx )
185
+ if mappedValues == nil {
186
+ logger .Info ("return patching values because mapped values are nil" )
187
+ return nil
188
+ }
189
+
190
+ helmChart , err := c .getChart (ctx , chartSpec )
191
+ if err != nil {
192
+ return err
193
+ }
194
+
195
+ files := helmChart .Files
196
+ var metadataFile * helmValuesMetadata
197
+ for _ , file := range files {
198
+ logger .Info (file .Name )
199
+ if file .Name == helmValuesMetadataFileName {
200
+ err := yaml .Unmarshal (file .Data , & metadataFile )
201
+ if err != nil {
202
+ return fmt .Errorf ("failed to unmarshal %s: %w" , helmValuesMetadataFileName , err )
203
+ }
204
+ logger .Info (fmt .Sprintf ("found metadata file %q for chart %q" , helmValuesMetadataFileName , chartSpec .ChartName ))
205
+ logger .Info (fmt .Sprintf ("%+v" , metadataFile ))
206
+ break
207
+ }
208
+ }
209
+
210
+ if metadataFile == nil {
211
+ logger .Info (fmt .Sprintf ("found no metadata file %q for chart %q" , helmValuesMetadataFileName , chartSpec .ChartName ))
212
+ return nil
213
+ }
214
+
215
+ values , err := chartutil .ReadValues ([]byte (chartSpec .ValuesYaml ))
216
+ if err != nil {
217
+ return fmt .Errorf ("failed to read current values: %w" , err )
218
+ }
219
+
220
+ // TODO Exclude this check because it has to be done if the mappedValues are nil too
221
+ for _ , metadataEntry := range metadataFile .Metadata {
222
+ // Check if metadata values are already set in valuesYamlOverwrite
223
+ for _ , key := range metadataEntry .Keys {
224
+ // key.Path is somethings like controllerManager.env.logLevel (dot-separated)
225
+ path := key .Path
226
+ if isMetadataPathInValuesMap (path , values ) {
227
+ return fmt .Errorf ("values contains path %s which should only be set in field mappedValues" , path )
228
+ }
229
+
230
+ value , ok := mappedValues [metadataEntry .Name ]
231
+ if ! ok {
232
+ // Return nil because metadata is nil in mappedValue
233
+ logger .Info (fmt .Sprintf ("found no value in mappedValues for metadata %q" , metadataEntry .Name ))
234
+ return nil
235
+ }
236
+
237
+ setValueInChartSpec (ctx , chartSpec , path , value )
238
+ }
239
+ }
240
+
241
+ return nil
242
+ }
243
+
244
+ func setValueInChartSpec (ctx context.Context , chartSpec * client.ChartSpec , path string , value interface {}) {
245
+ // TODO Mapping
246
+ // This is easier than reading the current values as string and merging them.
247
+ logger := log .FromContext (ctx )
248
+ option := fmt .Sprintf ("%s=%s" , path , value )
249
+ logger .Info (fmt .Sprintf ("set option %q for chart %q" , option , chartSpec .ChartName ))
250
+ chartSpec .ValuesOptions .Values = append (chartSpec .ValuesOptions .Values , option )
251
+ }
252
+
253
+ func isMetadataPathInValuesMap (path string , values chartutil.Values ) bool {
254
+ before , after , _ := strings .Cut (path , "." )
255
+
256
+ i , ok := values [before ]
257
+ if ! ok {
258
+ return false
259
+ }
260
+
261
+ ii , ok := i .(map [string ]interface {})
262
+ if ! ok && after == "" {
263
+ return true
264
+ }
265
+
266
+ return isMetadataPathInValuesMap (after , ii )
267
+ }
268
+
157
269
func (c * Client ) patchOciEndpoint (chart * client.ChartSpec ) {
158
270
if strings .HasPrefix (chart .ChartName , ociSchemePrefix ) {
159
271
return
@@ -173,7 +285,7 @@ func (c *Client) patchChartVersion(chart *client.ChartSpec) error {
173
285
return fmt .Errorf ("error resolving tags for chart %s: %w" , chart .ChartName , err )
174
286
}
175
287
176
- //sort tags by version
288
+ // sort tags by version
177
289
sortedTags := sortByVersionDescending (tags )
178
290
179
291
if len (sortedTags ) <= 0 {
0 commit comments