Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 35 additions & 0 deletions internal/model/image.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,10 @@
package model

import (
"encoding/json"

"github.com/crazy-max/diun/v4/pkg/registry"
"github.com/pkg/errors"
)

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

func (i Image) hash() (string, error) {
// Return json serialized image to use as a hashable key
b, err := json.Marshal(i)
if err != nil {
return "", errors.Errorf("cannot hash image: %v", err)
}

return string(b), nil
}

type ImageList []Image

// Dedupe removes duplicate images from the list and returns a new list
func (il ImageList) Dedupe() []Image {
keys := make(map[string]bool)
list := []Image{}
for _, entry := range il {
hash, err := entry.hash()
if err != nil {
// If we couldn't hash the entry, we can't dedupe it so we add it anyway
list = append(list, entry)
} else {
if _, value := keys[hash]; !value {
keys[hash] = true
list = append(list, entry)
}
}
}

return list
}

// ImagePlatform holds image platform configuration
type ImagePlatform struct {
OS string `yaml:"os,omitempty" json:",omitempty"`
Expand Down
55 changes: 55 additions & 0 deletions internal/model/image_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
package model_test

import (
"testing"

"github.com/crazy-max/diun/v4/internal/model"
"github.com/stretchr/testify/assert"
)

func TestDedupeImageList(t *testing.T) {
testCases := []struct {
desc string
input []model.Image
expected []model.Image
}{
{
desc: "dedupe",
input: []model.Image{
{
Name: "alpine",
IncludeTags: []string{"latest"},
},
{
Name: "alpine",
IncludeTags: []string{"latest"},
},
{
Name: "alpine",
IncludeTags: []string{"oldest"},
},
},
expected: []model.Image{
{
Name: "alpine",
IncludeTags: []string{"latest"},
},
{
Name: "alpine",
IncludeTags: []string{"oldest"},
},
},
},
}

for _, tt := range testCases {
tt := tt

t.Run(tt.desc, func(t *testing.T) {
t.Parallel()

result := model.ImageList(tt.input).Dedupe()
assert.Equal(t, tt.expected, result)
})
}
}
4 changes: 2 additions & 2 deletions internal/provider/docker/container.go
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,7 @@ func (c *Client) listContainerImage() []model.Image {
return []model.Image{}
}

var list []model.Image
var list model.ImageList
for _, ctn := range ctns {
imageName := ctn.Image
imageRaw, err := cli.ImageInspectWithRaw(imageName)
Expand Down Expand Up @@ -112,7 +112,7 @@ func (c *Client) listContainerImage() []model.Image {
list = append(list, image)
}

return list
return list.Dedupe()
}

func metadata(ctn types.Container) map[string]string {
Expand Down
4 changes: 3 additions & 1 deletion internal/provider/dockerfile/image.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ import (
"github.com/crazy-max/diun/v4/pkg/utl"
)

func (c *Client) listExtImage() (list []model.Image) {
func (c *Client) listExtImage() (list model.ImageList) {
for _, filename := range c.listDockerfiles(c.config.Patterns) {
dfile, err := dockerfile.New(dockerfile.Options{
Filename: filename,
Expand Down Expand Up @@ -50,7 +50,9 @@ func (c *Client) listExtImage() (list []model.Image) {
Msg("Watch disabled")
continue
}

list = append(list, image)
list = list.Dedupe()
}
}
return
Expand Down
4 changes: 2 additions & 2 deletions internal/provider/file/image.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import (
)

func (c *Client) listFileImage() []model.Image {
var images []model.Image
var images model.ImageList

files := c.getFiles()
if len(files) == 0 {
Expand Down Expand Up @@ -99,7 +99,7 @@ func (c *Client) listFileImage() []model.Image {
}
}

return images
return images.Dedupe()
}

func (c *Client) getFiles() []string {
Expand Down
4 changes: 2 additions & 2 deletions internal/provider/kubernetes/pod.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ func (c *Client) listPodImage() []model.Image {
return []model.Image{}
}

var list []model.Image
var list model.ImageList
for _, pod := range pods {
for _, ctn := range pod.Spec.Containers {
c.logger.Debug().
Expand Down Expand Up @@ -64,7 +64,7 @@ func (c *Client) listPodImage() []model.Image {
}
}

return list
return list.Dedupe()
}

func metadata(pod v1.Pod, ctn v1.Container) map[string]string {
Expand Down
4 changes: 2 additions & 2 deletions internal/provider/nomad/task.go
Original file line number Diff line number Diff line change
Expand Up @@ -50,7 +50,7 @@ func (c *Client) listTaskImages() []model.Image {
c.logger.Error().Err(err).Msg("Cannot list Nomad jobs")
}

var list []model.Image
var list model.ImageList

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

return list
return list.Dedupe()
}

func metadata(job *nomad.JobListStub, taskGroup *nomad.TaskGroup, task *nomad.Task) map[string]string {
Expand Down
4 changes: 2 additions & 2 deletions internal/provider/swarm/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ func (c *Client) listServiceImage() []model.Image {
return []model.Image{}
}

var list []model.Image
var list model.ImageList
for _, svc := range svcs {
c.logger.Debug().
Str("svc_name", svc.Spec.Name).
Expand Down Expand Up @@ -57,7 +57,7 @@ func (c *Client) listServiceImage() []model.Image {
list = append(list, image)
}

return list
return list.Dedupe()
}

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