Skip to content

Commit b22e43a

Browse files
committed
add set image command
1 parent 2c1be17 commit b22e43a

File tree

7 files changed

+419
-1
lines changed

7 files changed

+419
-1
lines changed

pkg/commands/edit/set/all.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ func NewCmdSet(fsys fs.FileSystem, v ifc.Validator) *cobra.Command {
4343
newCmdSetNameSuffix(fsys),
4444
newCmdSetNamespace(fsys, v),
4545
newCmdSetImageTag(fsys),
46+
newCmdSetImage(fsys),
4647
)
4748
return c
4849
}

pkg/commands/edit/set/setimage.go

Lines changed: 186 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,186 @@
1+
/*
2+
Copyright 2019 The Kubernetes Authors.
3+
4+
Licensed under the Apache License, Version 2.0 (the "License");
5+
you may not use this file except in compliance with the License.
6+
You may obtain a copy of the License at
7+
8+
http://www.apache.org/licenses/LICENSE-2.0
9+
10+
Unless required by applicable law or agreed to in writing, software
11+
distributed under the License is distributed on an "AS IS" BASIS,
12+
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
See the License for the specific language governing permissions and
14+
limitations under the License.
15+
*/
16+
17+
package set
18+
19+
import (
20+
"errors"
21+
"sort"
22+
"strings"
23+
24+
"github.com/spf13/cobra"
25+
"sigs.k8s.io/kustomize/pkg/commands/kustfile"
26+
"sigs.k8s.io/kustomize/pkg/fs"
27+
"sigs.k8s.io/kustomize/pkg/image"
28+
)
29+
30+
type setImageOptions struct {
31+
imageMap map[string]image.Image
32+
}
33+
34+
// errors
35+
36+
var (
37+
errImageNoArgs = errors.New("no image specified")
38+
errImageInvalidArgs = errors.New(`invalid format of image, use one of the following options:
39+
- <image>=<newimage>:<newtag>
40+
- <image>=<newimage>@<newtag>
41+
- <image>:<newtag>
42+
- <image>@<digest>`)
43+
)
44+
45+
const separator = "="
46+
47+
// newCmdSetImage sets the new names, tags or digests for images in the kustomization.
48+
func newCmdSetImage(fsys fs.FileSystem) *cobra.Command {
49+
var o setImageOptions
50+
51+
cmd := &cobra.Command{
52+
Use: "image",
53+
Short: `Sets images and their new names, new tags or digests in the kustomization file`,
54+
Example: `
55+
The command
56+
set image postgres=my-registry/postgres:latest nginx:1.8.0 my-app=my-registry/my-app alpine@sha256:24a0c4b4a4c0eb97a1aabb8e29f18e917d05abfe1b7a7c07857230879ce7d3d3
57+
will add
58+
59+
image:
60+
- name: postgres
61+
newName: my-registry/postgres
62+
newTag: latest
63+
- name: nginx
64+
newTag: 1.8.0
65+
- name: my-app
66+
newName: my-registry/my-app
67+
- digest: sha256:24a0c4b4a4c0eb97a1aabb8e29f18e917d05abfe1b7a7c07857230879ce7d3d3
68+
name: alpine
69+
70+
to the kustomization file if it doesn't exist,
71+
and overwrite the previous ones if the image name exists.
72+
73+
`,
74+
RunE: func(cmd *cobra.Command, args []string) error {
75+
err := o.Validate(args)
76+
if err != nil {
77+
return err
78+
}
79+
return o.RunSetImage(fsys)
80+
},
81+
}
82+
return cmd
83+
}
84+
85+
type overwrite struct {
86+
name string
87+
digest string
88+
tag string
89+
}
90+
91+
// Validate validates setImage command.
92+
func (o *setImageOptions) Validate(args []string) error {
93+
if len(args) == 0 {
94+
return errImageNoArgs
95+
}
96+
97+
o.imageMap = make(map[string]image.Image)
98+
99+
for _, arg := range args {
100+
101+
img, err := parse(arg)
102+
if err != nil {
103+
return err
104+
}
105+
o.imageMap[img.Name] = img
106+
}
107+
return nil
108+
}
109+
110+
// RunSetImage runs setImage command.
111+
func (o *setImageOptions) RunSetImage(fSys fs.FileSystem) error {
112+
mf, err := kustfile.NewKustomizationFile(fSys)
113+
if err != nil {
114+
return err
115+
}
116+
m, err := mf.Read()
117+
if err != nil {
118+
return err
119+
}
120+
121+
// append only new images from ksutomize file
122+
for _, im := range m.Images {
123+
if _, ok := o.imageMap[im.Name]; ok {
124+
continue
125+
}
126+
127+
o.imageMap[im.Name] = im
128+
}
129+
130+
var images []image.Image
131+
for _, v := range o.imageMap {
132+
images = append(images, v)
133+
}
134+
135+
sort.Slice(images, func(i, j int) bool {
136+
return images[i].Name < images[j].Name
137+
})
138+
139+
m.Images = images
140+
return mf.Write(m)
141+
}
142+
143+
func parse(arg string) (image.Image, error) {
144+
145+
// matches if there is an image name to overwrite
146+
// <image>=<new-image><:|@><new-tag>
147+
if s := strings.Split(arg, separator); len(s) == 2 {
148+
p, err := parseOverwrite(s[1])
149+
return image.Image{
150+
Name: s[0],
151+
NewName: p.name,
152+
NewTag: p.tag,
153+
Digest: p.digest,
154+
}, err
155+
}
156+
157+
// matches only for <tag|digest> overwrites
158+
// <image><:|@><new-tag>
159+
p, err := parseOverwrite(arg)
160+
return image.Image{
161+
Name: p.name,
162+
NewTag: p.tag,
163+
Digest: p.digest,
164+
}, err
165+
}
166+
167+
// parseOverwrite parses the overwrite parameters
168+
// from the given arg into a struct
169+
func parseOverwrite(arg string) (overwrite, error) {
170+
// match <image>@<digest>
171+
if d := strings.Split(arg, "@"); len(d) > 1 {
172+
return overwrite{
173+
name: d[0],
174+
digest: d[1],
175+
}, nil
176+
}
177+
178+
// match <image>:<tag>
179+
if t := pattern.FindStringSubmatch(arg); len(t) == 3 {
180+
return overwrite{
181+
name: t[1],
182+
tag: t[2],
183+
}, nil
184+
}
185+
return overwrite{}, errImageInvalidArgs
186+
}

0 commit comments

Comments
 (0)