Skip to content

Commit 4b13043

Browse files
author
noah
authored
fix: use kyaml to preserve kustomization (#274)
* fix: use kyaml to preserve kustomization fixes #250 fixes #268 fixes #247 * chore: linter error * fix: tests and linting * go mod tidy
1 parent 89b10c1 commit 4b13043

File tree

5 files changed

+139
-34
lines changed

5 files changed

+139
-34
lines changed

go.mod

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,8 @@ require (
2626
k8s.io/api v1.21.0
2727
k8s.io/apimachinery v1.21.0
2828
k8s.io/client-go v11.0.1-0.20190816222228-6d55c1b1f1ca+incompatible
29-
sigs.k8s.io/kustomize v2.0.3+incompatible
29+
sigs.k8s.io/kustomize/api v0.8.5
30+
sigs.k8s.io/kustomize/kyaml v0.10.15
3031
)
3132

3233
replace (

go.sum

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1294,8 +1294,6 @@ rsc.io/quote/v3 v3.1.0/go.mod h1:yEA65RcK8LyAZtP9Kv3t0HmxON59tX3rD+tICJqUlj0=
12941294
rsc.io/sampler v1.3.0/go.mod h1:T1hPZKmBbMNahiBKFy5HrXp6adAjACjK9JXDnKaTXpA=
12951295
sigs.k8s.io/apiserver-network-proxy/konnectivity-client v0.0.15/go.mod h1:LEScyzhFmoF5pso/YSeBstl57mOzx9xlU9n85RGrDQg=
12961296
sigs.k8s.io/controller-runtime v0.8.3/go.mod h1:U/l+DUopBc1ecfRZ5aviA9JDmGFQKvLf5YkZNx2e0sU=
1297-
sigs.k8s.io/kustomize v2.0.3+incompatible h1:JUufWFNlI44MdtnjUqVnvh29rR37PQFzPbLXqhyOyX0=
1298-
sigs.k8s.io/kustomize v2.0.3+incompatible/go.mod h1:MkjgH3RdOWrievjo6c9T245dYlB5QeXV4WCbnt/PEpU=
12991297
sigs.k8s.io/kustomize/api v0.8.5 h1:bfCXGXDAbFbb/Jv5AhMj2BB8a5VAJuuQ5/KU69WtDjQ=
13001298
sigs.k8s.io/kustomize/api v0.8.5/go.mod h1:M377apnKT5ZHJS++6H4rQoCHmWtt6qTpp3mbe7p6OLY=
13011299
sigs.k8s.io/kustomize/cmd/config v0.9.7/go.mod h1:MvXCpHs77cfyxRmCNUQjIqCmZyYsbn5PyQpWiq44nW0=

pkg/argocd/git.go

Lines changed: 57 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,9 @@ import (
99
"path/filepath"
1010
"text/template"
1111

12-
"sigs.k8s.io/kustomize/pkg/commands/kustfile"
13-
"sigs.k8s.io/kustomize/pkg/fs"
14-
image2 "sigs.k8s.io/kustomize/pkg/image"
12+
"sigs.k8s.io/kustomize/api/konfig"
13+
"sigs.k8s.io/kustomize/api/types"
14+
kyaml "sigs.k8s.io/kustomize/kyaml/yaml"
1515

1616
"github.com/argoproj-labs/argocd-image-updater/pkg/image"
1717

@@ -221,36 +221,71 @@ func writeKustomization(app *v1alpha1.Application, wbc *WriteBackConfig, gitC gi
221221

222222
log.Infof("updating base %s", base)
223223

224-
kf, err := kustfile.NewKustomizationFile(fs.MakeRealFS())
224+
kustFile := findKustomization(base)
225+
if kustFile == "" {
226+
return fmt.Errorf("could not find kustomization in %s", base), false
227+
}
228+
229+
filterFunc, err := imagesFilter(app.Spec.Source.Kustomize.Images)
225230
if err != nil {
226-
return
231+
return err, false
227232
}
228-
kustomization, err := kf.Read()
233+
err = kyaml.UpdateFile(filterFunc, kustFile)
229234
if err != nil {
230-
return
235+
return err, false
231236
}
232237

233-
Images:
234-
for _, img := range app.Spec.Source.Kustomize.Images {
235-
override := parseImageOverride(img)
236-
for i, imgSet := range kustomization.Images {
237-
if imgSet.Name == override.Name {
238-
kustomization.Images[i] = override
239-
continue Images
240-
}
238+
return nil, false
239+
}
240+
241+
func imagesFilter(images v1alpha1.KustomizeImages) (kyaml.Filter, error) {
242+
var overrides []kyaml.Filter
243+
for _, img := range images {
244+
override, err := imageFilter(parseImageOverride(img))
245+
if err != nil {
246+
return nil, err
241247
}
242-
// wasn't an existing override, add one
243-
kustomization.Images = append(kustomization.Images, override)
248+
overrides = append(overrides, override)
244249
}
245250

246-
if err := kf.Write(kustomization); err != nil {
247-
return err, false
251+
return kyaml.FilterFunc(func(object *kyaml.RNode) (*kyaml.RNode, error) {
252+
err := object.PipeE(append([]kyaml.Filter{kyaml.LookupCreate(
253+
kyaml.SequenceNode, "images",
254+
)}, overrides...)...)
255+
return object, err
256+
}), nil
257+
}
258+
259+
func imageFilter(imgSet types.Image) (kyaml.Filter, error) {
260+
data, err := kyaml.Marshal(imgSet)
261+
if err != nil {
262+
return nil, err
263+
}
264+
update, err := kyaml.Parse(string(data))
265+
if err != nil {
266+
return nil, err
248267
}
268+
setter := kyaml.ElementSetter{
269+
Element: update.YNode(),
270+
Keys: []string{"name"},
271+
Values: []string{imgSet.Name},
272+
}
273+
return kyaml.FilterFunc(func(object *kyaml.RNode) (*kyaml.RNode, error) {
274+
return object, object.PipeE(setter)
275+
}), nil
276+
}
249277

250-
return
278+
func findKustomization(base string) string {
279+
for _, f := range konfig.RecognizedKustomizationFileNames() {
280+
kustFile := path.Join(base, f)
281+
if stat, err := os.Stat(kustFile); err == nil && !stat.IsDir() {
282+
return kustFile
283+
}
284+
}
285+
return ""
251286
}
252287

253-
func parseImageOverride(str v1alpha1.KustomizeImage) image2.Image {
288+
func parseImageOverride(str v1alpha1.KustomizeImage) types.Image {
254289
// TODO is this a valid use? format could diverge
255290
img := image.NewFromIdentifier(string(str))
256291
tagName := ""
@@ -267,7 +302,7 @@ func parseImageOverride(str v1alpha1.KustomizeImage) image2.Image {
267302
img.ImageAlias = img.ImageName
268303
img.ImageName = "" // inside baseball (see return): name isn't changing, just tag, so don't write newName
269304
}
270-
return image2.Image{
305+
return types.Image{
271306
Name: img.ImageAlias,
272307
NewName: img.ImageName,
273308
NewTag: tagName,

pkg/argocd/git_test.go

Lines changed: 74 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,11 @@ import (
99
"github.com/argoproj-labs/argocd-image-updater/pkg/image"
1010
"github.com/argoproj-labs/argocd-image-updater/pkg/tag"
1111

12+
"sigs.k8s.io/kustomize/api/types"
13+
kyaml "sigs.k8s.io/kustomize/kyaml/yaml"
14+
1215
"github.com/argoproj/argo-cd/v2/pkg/apis/application/v1alpha1"
1316
"github.com/stretchr/testify/assert"
14-
image2 "sigs.k8s.io/kustomize/pkg/image"
1517
)
1618

1719
func Test_TemplateCommitMessage(t *testing.T) {
@@ -44,36 +46,36 @@ func Test_parseImageOverride(t *testing.T) {
4446
cases := []struct {
4547
name string
4648
override v1alpha1.KustomizeImage
47-
expected image2.Image
49+
expected types.Image
4850
}{
49-
{"tag update", "ghcr.io:1234/foo/foo:123", image2.Image{
51+
{"tag update", "ghcr.io:1234/foo/foo:123", types.Image{
5052
Name: "ghcr.io:1234/foo/foo",
5153
NewTag: "123",
5254
}},
53-
{"image update", "ghcr.io:1234/foo/foo=ghcr.io:1234/bar", image2.Image{
55+
{"image update", "ghcr.io:1234/foo/foo=ghcr.io:1234/bar", types.Image{
5456
Name: "ghcr.io:1234/foo/foo",
5557
NewName: "ghcr.io:1234/bar",
5658
}},
57-
{"update everything", "ghcr.io:1234/foo/foo=1234.foo.com:9876/bar:123", image2.Image{
59+
{"update everything", "ghcr.io:1234/foo/foo=1234.foo.com:9876/bar:123", types.Image{
5860
Name: "ghcr.io:1234/foo/foo",
5961
NewName: "1234.foo.com:9876/bar",
6062
NewTag: "123",
6163
}},
62-
{"change registry and tag", "ghcr.io:1234/foo/foo=1234.dkr.ecr.us-east-1.amazonaws.com/bar:123", image2.Image{
64+
{"change registry and tag", "ghcr.io:1234/foo/foo=1234.dkr.ecr.us-east-1.amazonaws.com/bar:123", types.Image{
6365
Name: "ghcr.io:1234/foo/foo",
6466
NewName: "1234.dkr.ecr.us-east-1.amazonaws.com/bar",
6567
NewTag: "123",
6668
}},
67-
{"change only registry", "0001.dkr.ecr.us-east-1.amazonaws.com/bar=1234.dkr.ecr.us-east-1.amazonaws.com/bar", image2.Image{
69+
{"change only registry", "0001.dkr.ecr.us-east-1.amazonaws.com/bar=1234.dkr.ecr.us-east-1.amazonaws.com/bar", types.Image{
6870
Name: "0001.dkr.ecr.us-east-1.amazonaws.com/bar",
6971
NewName: "1234.dkr.ecr.us-east-1.amazonaws.com/bar",
7072
}},
71-
{"change image and set digest", "foo=acme/app@sha256:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", image2.Image{
73+
{"change image and set digest", "foo=acme/app@sha256:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", types.Image{
7274
Name: "foo",
7375
NewName: "acme/app",
7476
Digest: "sha256:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
7577
}},
76-
{"set digest", "acme/app@sha256:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", image2.Image{
78+
{"set digest", "acme/app@sha256:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", types.Image{
7779
Name: "acme/app",
7880
Digest: "sha256:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855",
7981
}},
@@ -86,3 +88,66 @@ func Test_parseImageOverride(t *testing.T) {
8688
}
8789

8890
}
91+
92+
func Test_imagesFilter(t *testing.T) {
93+
for _, tt := range []struct {
94+
name string
95+
images v1alpha1.KustomizeImages
96+
expected string
97+
}{
98+
{name: "simple", images: v1alpha1.KustomizeImages{"foo"}, expected: `
99+
images:
100+
- name: foo
101+
`},
102+
{name: "tagged", images: v1alpha1.KustomizeImages{"foo:bar"}, expected: `
103+
images:
104+
- name: foo
105+
newTag: bar
106+
`},
107+
{name: "rename", images: v1alpha1.KustomizeImages{"baz=foo:bar"}, expected: `
108+
images:
109+
- name: baz
110+
newName: foo
111+
newTag: bar
112+
`},
113+
{name: "digest", images: v1alpha1.KustomizeImages{"baz=foo@sha12345"}, expected: `
114+
images:
115+
- name: baz
116+
newName: foo
117+
digest: sha12345
118+
`},
119+
{name: "digest simple", images: v1alpha1.KustomizeImages{"foo@sha12345"}, expected: `
120+
images:
121+
- name: foo
122+
digest: sha12345
123+
`},
124+
{name: "all", images: v1alpha1.KustomizeImages{
125+
"foo",
126+
"foo=bar", // merges with above
127+
"baz@sha12345",
128+
"bar:123",
129+
"foo=bar:123", // merges and overwrites the first two
130+
}, expected: `
131+
images:
132+
- name: foo
133+
newName: bar
134+
newTag: "123"
135+
- name: baz
136+
digest: sha12345
137+
- name: bar
138+
newTag: "123"
139+
`},
140+
} {
141+
t.Run(tt.name, func(t *testing.T) {
142+
filter, err := imagesFilter(tt.images)
143+
assert.NoError(t, err)
144+
145+
node := kyaml.NewRNode(&kyaml.Node{Kind: kyaml.DocumentNode, Content: []*kyaml.Node{
146+
kyaml.NewMapRNode(nil).YNode(),
147+
}})
148+
node, err = filter.Filter(node)
149+
assert.NoError(t, err)
150+
assert.YAMLEq(t, tt.expected, node.MustString())
151+
})
152+
}
153+
}

pkg/argocd/update_test.go

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1737,6 +1737,8 @@ func Test_CommitUpdates(t *testing.T) {
17371737
assert.NoError(t, ioutil.WriteFile(kf, []byte(`
17381738
kind: Kustomization
17391739
apiVersion: kustomize.config.k8s.io/v1beta1
1740+
1741+
replacements: []
17401742
`), os.ModePerm))
17411743

17421744
gitMock.On("Checkout", mock.Anything).Run(func(args mock.Arguments) {
@@ -1765,6 +1767,8 @@ images:
17651767
- name: bar
17661768
newName: baz
17671769
newTag: "123"
1770+
1771+
replacements: []
17681772
`, string(kust))
17691773

17701774
// test the merge case too
@@ -1781,6 +1785,8 @@ images:
17811785
newTag: "123"
17821786
- name: bar
17831787
newName: qux
1788+
1789+
replacements: []
17841790
`, string(kust))
17851791
})
17861792

0 commit comments

Comments
 (0)