8000 [Feature] Helm Chart Values merge methods · arangodb/kube-arangodb@c64f7fa · GitHub
[go: up one dir, main page]

Skip to content

Commit c64f7fa

Browse files
committed
[Feature] Helm Chart Values merge methods
1 parent 1868116 commit c64f7fa

File tree

5 files changed

+295
-23
lines changed

5 files changed

+295
-23
lines changed

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@
4444
- (Feature) Migrate Storage V1 to CE
4545
- (Feature) Improve Helm Chart Manager
4646
- (Bugfix) (Platform) Proper Path handler in StorageV2
47+
- (Feature) Helm Chart Values merge methods
4748

4849
## [1.2.43](https://github.com/arangodb/kube-arangodb/tree/1.2.43) (2024-10-14)
4950
- (Feature) ArangoRoute CRD

pkg/util/k8sutil/helm/client.go

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
//
22
// DISCLAIMER
33
//
4-
// Copyright 2024 ArangoDB GmbH, Cologne, Germany
4+
// Copyright 2024-2025 ArangoDB GmbH, Cologne, Germany
55
//
66
// Licensed under the Apache License, Version 2.0 (the "License");
77
// you may not use this file except in compliance with the License.
@@ -184,7 +184,7 @@ func (c *client) Install(ctx context.Context, chart Chart, values Values, mods .
184184
return nil, err
185185
}
186186

187-
result, err := act.Run(chartData.Chart(), valuesData)
187+
result, err := act.RunWithContext(ctx, chartData.Chart(), valuesData)
188188
if err != nil {
189189
return nil, err
190190
}
@@ -230,7 +230,7 @@ func (c *client) Upgrade(ctx context.Context, name string, chart Chart, values V
230230
}
231231
}
232232

233-
result, err := act.Run(name, chartData.Chart(), valuesData)
233+
result, err := act.RunWithContext(ctx, name, chartData.Chart(), valuesData)
234234
if err != nil {
235235
return nil, err
236236
}

pkg/util/k8sutil/helm/values.go

Lines changed: 41 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
//
22
// DISCLAIMER
33
//
4-
// Copyright 2024 ArangoDB GmbH, Cologne, Germany
4+
// Copyright 2024-2025 ArangoDB GmbH, Cologne, Germany
55
//
66
// Licensed under the Apache License, Version 2.0 (the "License");
77
// you may not use this file except in compliance with the License.
@@ -26,6 +26,37 @@ import (
2626
"github.com/arangodb/kube-arangodb/pkg/util"
2727
)
2828

29+
func NewMergeValues(opts ValuesMergeMethod, vs ...any) (Values, error) {
30+
if len(vs) == 0 {
31+
return nil, nil
32+
}
33+
34+
o, err := NewValues(vs[0])
35+
if err != nil {
36+
return nil, err
37+
}
38+
39+
if len(vs) == 1 {
40+
return o, nil
41+
}
42+
43+
for _, el := range vs[1:] {
44+
a, err := NewValues(el)
45+
if err != nil {
46+
return nil, err
47+
}
48+
49+
no, err := opts.Merge(o, a)
50+
if err != nil {
51+
return nil, err
52+
}
53+
54+
o = no
55+
}
56+
57+
return o, nil
58+
}
59+
2960
func NewValues(in any) (Values, error) {
3061
data, err := json.Marshal(in)
3162
if err != nil {
@@ -38,35 +69,25 @@ func NewValues(in any) (Values, error) {
3869
type Values []byte
3970

4071
func (v Values) Equals(other Values) bool {
41-
a, err := v.Marshal()
42-
if err != nil {
43-
return false
44-
}
45-
46-
if len(a) == 0 {
47-
a = nil
48-
}
49-
50-
ad, err := json.Marshal(a)
72+
a, err := v.MarshalJSON()
5173
if err != nil {
5274
return false
5375
}
5476

55-
b, err := other.Marshal()
77+
b, err := other.MarshalJSON()
5678
if err != nil {
5779
return false
5880
}
5981

60-
if len(b) == 0 {
61-
b = nil
62-
}
82+
return util.SHA256(a) == util.SHA256(b)
83+
}
6384

64-
bd, err := json.Marshal(b)
65-
if err != nil {
66-
return false
67-
}
85+
func (v Values) MarshalJSON() ([]byte, error) {
86+
return v, nil
87+
}
6888

69-
return util.SHA256(ad) == util.SHA256(bd)
89+
func (v Values) String() string {
90+
return string(v)
7091
}
7192

7293
func (v Values) Marshal() (map[string]interface{}, error) {
Lines changed: 105 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,105 @@
1+
//
2+
// DISCLAIMER
3+
//
4+
// Copyright 2025 ArangoDB GmbH, Cologne, Germany
5+
//
6+
// Licensed under the Apache License, Version 2.0 (the "License");
7+
// you may not use this file except in compliance with the License.
8+
// You may obtain a copy of the License at
9+
//
10+
// http://www.apache.org/licenses/LICENSE-2.0
11+
//
12+
// Unless required by applicable law or agreed to in writing, software
13+
// distributed under the License is distributed on an "AS IS" BASIS,
14+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
// See the License for the specific language governing permissions and
16+
// limitations under the License.
17+
//
18+
// Copyright holder is ArangoDB GmbH, Cologne, Germany
19+
//
20+
21+
package helm
22+
23+
import "github.com/arangodb/kube-arangodb/pkg/util/errors"
24+
25+
type ValuesMergeMethod int
26+
27+
const (
28+
MergeMaps ValuesMergeMethod = 1 << iota
29+
)
30+
31+
func (v ValuesMergeMethod) Has(o ValuesMergeMethod) bool {
32+
return v&o == o
33+
}
34+
35+
func (v ValuesMergeMethod) Merge(a, b Values) (Values, error) {
36+
av, err := a.Marshal()
37+
if err != nil {
38+
return nil, err
39+
}
40+
41+
bv, err := b.Marshal()
42+
if err != nil {
43+
return nil, err
44+
}
45+
46+
z, err := v.mergeMaps(av, bv)
47+
if err != nil {
48+
return nil, err
49+
}
50+
51+
return NewValues(z)
52+
}
53+
54+
func (v ValuesMergeMethod) mergeMaps(a, b map[string]interface{}) (map[string]interface{}, error) {
55+
if len(a) == 0 && len(b) == 0 {
56+
return map[string]interface{}{}, nil
57+
}
58+
if len(a) == 0 {
59+
return b, nil
60+
}
61+
62+
if len(b) == 0 {
63+
return a, nil
64+
}
65+
66+
ret := make(map[string]interface{})
67+
68+
for k, v := range a {
69+
ret[k] = v
70+
}
71+
72+
for k, o := range b {
73+
z, ok := ret[k]
74+
if !ok {
75+
ret[k] = o
76+
continue
77+
}
78+
79+
if v.Has(MergeMaps) {
80+
if z != nil && o != nil {
81+
av, aok := z.(map[string]interface{})
82+
bv, bok := o.(map[string]interface{})
83+
84+
if aok || bok {
85+
if !aok || !bok {
86+
return nil, errors.Errorf("Invalid types during Map merge")
87+
}
88+
89+
rv, err := v.mergeMaps(av, bv)
90+
if err != nil {
91+
return nil, err
92+
}
93+
94+
ret[k] = rv
95+
continue
96+
}
97+
}
98+
}
99+
100+
// Override at the end
101+
ret[k] = o
102+
}
103+
104+
return ret, nil
105+
}
Lines changed: 145 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,145 @@
1+
//
2+
// DISCLAIMER
3+
//
4+
// Copyright 2025 ArangoDB GmbH, Cologne, Germany
5+
//
6+
// Licensed under the Apache License, Version 2.0 (the "License");
7+
// you may not use this file except in compliance with the License.
8+
// You may obtain a copy of the License at
9+
//
10+
// http://www.apache.org/licenses/LICENSE-2.0
11+
//
12+
// Unless required by applicable law or agreed to in writing, software
13+
// distributed under the License is distributed on an "AS IS" BASIS,
14+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
// See the License for the specific language governing permissions and
16+
// limitations under the License.
17+
//
18+
// Copyright holder is ArangoDB GmbH, Cologne, Germany
19+
//
20+
21+
package helm
22+
23+
import (
24+
"testing"
25+
26+
"github.com/stretchr/testify/require"
27+
)
28+
29+
func testValuesMergeMethodMerge(t *testing.T, name string, a, b any, m ValuesMergeMethod, check func(t *testing.T, v Values, err error)) {
30+
t.Run(name, func(t *testing.T) {
31+
av, err := NewValues(a)
32+
require.NoError(t, err)
33+
34+
bv, err := NewValues(b)
35+
require.NoError(t, err)
36+
37+
v, err := m.Merge(av, bv)
38+
if check != nil {
39+
check(t, v, err)
40+
} else {
41+
require.NoError(t, err)
42+
}
43+
})
44+
}
45+
46+
func Test_ValuesMergeMethod_Merge(t *testing.T) {
47+
testValuesMergeMethodMerge(t, "Nils", nil, nil, 0, func(t *testing.T, v Values, err error) {
48+
require.NoError(t, err)
49+
require.EqualValues(t, "{}", v.String())
50+
})
51+
testValuesMergeMethodMerge(t, "Second Nil", map[string]interface{}{
52+
"A": 1,
53+
}, nil, 0, func(t *testing.T, v Values, err error) {
54+
require.NoError(t, err)
55+
require.EqualValues(t, `{"A":1}`, v.String())
56+
})
57+
testValuesMergeMethodMerge(t, "First Nil", nil, map[string]interface{}{
58+
"B": 1,
59+
}, 0, func(t *testing.T, v Values, err error) {
60+
require.NoError(t, err)
61+
require.EqualValues(t, `{"B":1}`, v.String())
62+
})
63+
testValuesMergeMethodMerge(t, "Merge", map[string]interface{}{
64+
"A": 1,
65+
}, map[string]interface{}{
66+
"B": 1,
67+
}, 0, func(t *testing.T, v Values, err error) {
68+
require.NoError(t, err)
69+
require.EqualValues(t, `{"A":1,"B":1}`, v.String())
70+
})
71+
testValuesMergeMethodMerge(t, "Override", map[string]interface{}{
72+
"A": 1,
73+
"S": 0,
74+
}, map[string]interface{}{
75+
"B": 1,
76+
"S": 2,
77+
}, 0, func(t *testing.T, v Values, err error) {
78+
require.NoError(t, err)
79+
require.EqualValues(t, `{"A":1,"B":1,"S":2}`, v.String())
80+
})
81+
testValuesMergeMethodMerge(t, "Map - Default", map[string]interface{}{
82+
"M": map[string]interface{}{
83+
"A": 1,
84+
"S": 0,
85+
},
86+
}, map[string]interface{}{
87+
"M": map[string]interface{}{
88+
"B": 1,
89+
"S": 2,
90+
},
91+
}, 0, func(t *testing.T, v Values, err error) {
92+
require.NoError(t, err)
93+
require.EqualValues(t, `{"M":{"B":1,"S":2}}`, v.String())
94+
})
95+
testValuesMergeMethodMerge(t, "Map - Merge", map[string]interface{}{
96+
"M": map[string]interface{}{
97+
"A": 1,
98+
"S": 0,
99+
},
100+
}, map[string]interface{}{
101+
"M": map[string]interface{}{
102+
"B": 1,
103+
"S": 2,
104+
},
105+
}, MergeMaps, func(t *testing.T, v Values, err error) {
106+
require.NoError(t, err)
107+
require.EqualValues(t, `{"M":{"A":1,"B":1,"S":2}}`, v.String())
108+
})
109+
testValuesMergeMethodMerge(t, "SubMap - Default", map[string]interface{}{
110+
"M": map[string]interface{}{
111+
"M": map[string]interface{}{
112+
"A": 1,
113+
"S": 0,
114+
},
115+
},
116+
}, map[string]interface{}{
117+
"M": map[string]interface{}{
118+
"M": map[string]interface{}{
119+
"B": 1,
120+
"S": 2,
121+
},
122+
},
123+
}, 0, func(t *testing.T, v Values, err error) {
124+
require.NoError(t, err)
125+
require.EqualValues(t, `{"M":{"M":{"B":1,"S":2}}}`, v.String())
126+
})
127+
testValuesMergeMethodMerge(t, "SubMap - Merge", map[string]interface{}{
128+
"M": map[string]interface{}{
129+
"M": map[string]interface{}{
130+
"A": 1,
131+
"S": 0,
132+
},
133+
},
134+
}, map[string]interface{}{
135+
"M": map[string]interface{}{
136+
"M": map[string]interface{}{
137+
"B": 1,
138+
"S": 2,
139+
},
140+
},
141+
}, MergeMaps, func(t *testing.T, v Values, err error) {
142+
require.NoError(t, err)
143+
require.EqualValues(t, `{"M":{"M":{"A":1,"B":1,"S":2}}}`, v.String())
144+
})
145+
}

0 commit comments

Comments
 (0)
0