Skip to content

Commit c74333c

Browse files
committed
Add method for deduping images
This is helpful with Nomad because some images end up used as sidecars for many jobs. Also periodic jobs spawn many tasks with the same image.
1 parent 931eb3c commit c74333c

File tree

8 files changed

+103
-11
lines changed

8 files changed

+103
-11
lines changed

internal/model/image.go

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
package model
22

33
import (
4+
"encoding/json"
5+
46
"github.com/crazy-max/diun/v4/pkg/registry"
7+
"github.com/pkg/errors"
58
)
69

710
// Image holds image configuration
@@ -20,6 +23,38 @@ type Image struct {
2023
Metadata map[string]string `yaml:"metadata,omitempty" json:",omitempty"`
2124
}
2225

26+
func (i Image) hash() (string, error) {
27+
// Return json serialized image to use as a hashable key
28+
b, err := json.Marshal(i)
29+
if err != nil {
30+
return "", errors.Errorf("cannot hash image: %v", err)
31+
}
32+
33+
return string(b), nil
34+
}
35+
36+
type ImageList []Image
37+
38+
// Dedupe removes duplicate images from the list and returns a new list
39+
func (il ImageList) Dedupe() []Image {
40+
keys := make(map[string]bool)
41+
list := []Image{}
42+
for _, entry := range il {
43+
hash, err := entry.hash()
44+
if err != nil {
45+
// If we couldn't hash the entry, we can't dedupe it so we add it anyway
46+
list = append(list, entry)
47+
} else {
48+
if _, value := keys[hash]; !value {
49+
keys[hash] = true
50+
list = append(list, entry)
51+
}
52+
}
53+
}
54+
55+
return list
56+
}
57+
2358
// ImagePlatform holds image platform configuration
2459
type ImagePlatform struct {
2560
OS string `yaml:"os,omitempty" json:",omitempty"`

internal/model/image_test.go

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,55 @@
1+
package model_test
2+
3+
import (
4+
"testing"
5+
6+
"github.com/crazy-max/diun/v4/internal/model"
7+
"github.com/stretchr/testify/assert"
8+
)
9+
10+
func TestDedupeImageList(t *testing.T) {
11+
testCases := []struct {
12+
desc string
13+
input []model.Image
14+
expected []model.Image
15+
}{
16+
{
17+
desc: "dedupe",
18+
input: []model.Image{
19+
{
20+
Name: "alpine",
21+
IncludeTags: []string{"latest"},
22+
},
23+
{
24+
Name: "alpine",
25+
IncludeTags: []string{"latest"},
26+
},
27+
{
28+
Name: "alpine",
29+
IncludeTags: []string{"oldest"},
30+
},
31+
},
32+
expected: []model.Image{
33+
{
34+
Name: "alpine",
35+
IncludeTags: []string{"latest"},
36+
},
37+
{
38+
Name: "alpine",
39+
IncludeTags: []string{"oldest"},
40+
},
41+
},
42+
},
43+
}
44+
45+
for _, tt := range testCases {
46+
tt := tt
47+
48+
t.Run(tt.desc, func(t *testing.T) {
49+
t.Parallel()
50+
51+
result := model.ImageList(tt.input).Dedupe()
52+
assert.Equal(t, tt.expected, result)
53+
})
54+
}
55+
}

internal/provider/docker/container.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ func (c *Client) listContainerImage() []model.Image {
4040
return []model.Image{}
4141
}
4242

43-
var list []model.Image
43+
var list model.ImageList
4444
for _, ctn := range ctns {
4545
imageName := ctn.Image
4646
imageRaw, err := cli.ImageInspectWithRaw(imageName)
@@ -112,7 +112,7 @@ func (c *Client) listContainerImage() []model.Image {
112112
list = append(list, image)
113113
}
114114

115-
return list
115+
return list.Dedupe()
116116
}
117117

118118
func metadata(ctn types.Container) map[string]string {

internal/provider/dockerfile/image.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ import (
1111
"github.com/crazy-max/diun/v4/pkg/utl"
1212
)
1313

14-
func (c *Client) listExtImage() (list []model.Image) {
14+
func (c *Client) listExtImage() (list model.ImageList) {
1515
for _, filename := range c.listDockerfiles(c.config.Patterns) {
1616
dfile, err := dockerfile.New(dockerfile.Options{
1717
Filename: filename,
@@ -50,7 +50,9 @@ func (c *Client) listExtImage() (list []model.Image) {
5050
Msg("Watch disabled")
5151
continue
5252
}
53+
5354
list = append(list, image)
55+
list = list.Dedupe()
5456
}
5557
}
5658
return

internal/provider/file/image.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import (
1212
)
1313

1414
func (c *Client) listFileImage() []model.Image {
15-
var images []model.Image
15+
var images model.ImageList
1616

1717
files := c.getFiles()
1818
if len(files) == 0 {
@@ -99,7 +99,7 @@ func (c *Client) listFileImage() []model.Image {
9999
}
100100
}
101101

102-
return images
102+
return images.Dedupe()
103103
}
104104

105105
func (c *Client) getFiles() []string {

internal/provider/kubernetes/pod.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ func (c *Client) listPodImage() []model.Image {
3131
return []model.Image{}
3232
}
3333

34-
var list []model.Image
34+
var list model.ImageList
3535
for _, pod := range pods {
3636
for _, ctn := range pod.Spec.Containers {
3737
c.logger.Debug().
@@ -64,7 +64,7 @@ func (c *Client) listPodImage() []model.Image {
6464
}
6565
}
6666

67-
return list
67+
return list.Dedupe()
6868
}
6969

7070
func metadata(pod v1.Pod, ctn v1.Container) map[string]string {

internal/provider/nomad/task.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ func (c *Client) listTaskImages() []model.Image {
5050
c.logger.Error().Err(err).Msg("Cannot list Nomad jobs")
5151
}
5252

53-
var list []model.Image
53+
var list model.ImageList
5454

5555
for _, job := range jobs {
5656
jobInfo, _, err := client.Jobs().Info(job.ID, nil)
@@ -129,7 +129,7 @@ func (c *Client) listTaskImages() []model.Image {
129129
}
130130
}
131131

132-
return list
132+
return list.Dedupe()
133133
}
134134

135135
func metadata(job *nomad.JobListStub, taskGroup *nomad.TaskGroup, task *nomad.Task) map[string]string {

internal/provider/swarm/service.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ func (c *Client) listServiceImage() []model.Image {
2929
return []model.Image{}
3030
}
3131

32-
var list []model.Image
32+
var list model.ImageList
3333
for _, svc := range svcs {
3434
c.logger.Debug().
3535
Str("svc_name", svc.Spec.Name).
@@ -57,7 +57,7 @@ func (c *Client) listServiceImage() []model.Image {
5757
list = append(list, image)
5858
}
5959

60-
return list
60+
return list.Dedupe()
6161
}
6262

6363
func metadata(svc swarm.Service) map[string]string {

0 commit comments

Comments
 (0)