Skip to content
This repository was archived by the owner on Jan 30, 2026. It is now read-only.

Commit b7933d8

Browse files
committed
De-duplicate images in final discovery output
This change modifies DiscoveredImage to store the name/type of one or more containers which use the image, and it also adds a new Insert method on Manifest, which acts similarly to the built-in append except duplicate entries are merged into the existing DiscoveredImage instance in the list. Signed-off-by: Caleb Xu <caxu@redhat.com>
1 parent 30d6c29 commit b7933d8

3 files changed

Lines changed: 577 additions & 42 deletions

File tree

discovery/discovery.go

Lines changed: 104 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,115 @@
11
package discovery
22

3+
import (
4+
"encoding/json"
5+
"slices"
6+
)
7+
38
// Manifest represents the discovered components for a given application.
49
type Manifest struct {
510
DiscoveredImages []DiscoveredImage
611
}
712

8-
// DiscoveredImage is a container image that' been discovered based on the
9-
// workload watchers.
13+
func (m *Manifest) Equal(m1 Manifest) bool {
14+
if len(m.DiscoveredImages) != len(m1.DiscoveredImages) {
15+
return false
16+
}
17+
for idx := range m.DiscoveredImages {
18+
if !m.DiscoveredImages[idx].Equal(m1.DiscoveredImages[idx]) {
19+
return false
20+
}
21+
}
22+
23+
return true
24+
}
25+
26+
// Insert inserts images into the manifest. If an image is already present in
27+
// the manifest, the containers from the images to the inserted images are
28+
// inserted into the existing image in the manifest instead, avoiding the
29+
// creation of duplicate images in the manifest.
30+
func (m *Manifest) Insert(images ...DiscoveredImage) {
31+
for _, image := range images {
32+
idx := slices.IndexFunc(m.DiscoveredImages, func(i DiscoveredImage) bool {
33+
return i.Image == image.Image
34+
})
35+
36+
if idx == -1 {
37+
m.DiscoveredImages = append(m.DiscoveredImages, image)
38+
} else {
39+
for _, container := range image.Containers {
40+
containerExists := slices.ContainsFunc(m.DiscoveredImages[idx].Containers, func(c DiscoveredContainer) bool {
41+
return c.Equal(container)
42+
})
43+
44+
if !containerExists {
45+
m.DiscoveredImages[idx].Containers = append(m.DiscoveredImages[idx].Containers, container)
46+
}
47+
}
48+
}
49+
}
50+
}
51+
52+
// DiscoveredImage is a container image which was discovered in one or more workloads.
1053
type DiscoveredImage struct {
11-
// PodName is the pod.metadata.name value where the image was discovered.
12-
PodName string
13-
// ContainerName represents the container in the pod that had the image.
14-
ContainerName string
1554
// Image is a fully qualified container image name and tag or digest.
1655
Image string
56+
57+
// Containers is a list of DiscoveredContainer objects which are using
58+
// the discovered image.
59+
Containers []DiscoveredContainer
60+
}
61+
62+
func (i *DiscoveredImage) Equal(i1 DiscoveredImage) bool {
63+
return i.Image == i1.Image && slices.Equal(i.Containers, i1.Containers)
64+
}
65+
66+
// DiscoveredContainer is a container which was observed during the discovery process.
67+
type DiscoveredContainer struct {
68+
// Name is the name of a container in a pod.
69+
Name string
70+
71+
// Type is the ContainerType of the container in its pod.
72+
Type ContainerType
73+
74+
// Pod is the DiscoveredPod which this container is a part of.
75+
Pod DiscoveredPod
76+
}
77+
78+
func (c *DiscoveredContainer) Equal(c1 DiscoveredContainer) bool {
79+
return c.Name == c1.Name && c.Type == c1.Type && c.Pod.Name == c1.Pod.Name && c.Pod.Namespace == c1.Pod.Namespace
80+
}
81+
82+
// ContainerType is the type of a container in a pod.
83+
type ContainerType int
84+
85+
const (
86+
Container ContainerType = iota
87+
InitContainer
88+
EphemeralContainer
89+
)
90+
91+
func (c ContainerType) String() string {
92+
switch c {
93+
case Container:
94+
return "Container"
95+
case InitContainer:
96+
return "InitContainer"
97+
case EphemeralContainer:
98+
return "EphemeralContainer"
99+
}
100+
101+
return ""
102+
}
103+
104+
func (c ContainerType) MarshalJSON() ([]byte, error) {
105+
return json.Marshal(c.String())
106+
}
107+
108+
// DiscoveredPod is a pod that contains a discovered image.
109+
type DiscoveredPod struct {
110+
// Name is the pod.metadata.name value where the image was discovered.
111+
Name string
112+
113+
// Namespace is the pod.metadata.namespace value of the pod.
114+
Namespace string
17115
}

internal/discover/processor.go

Lines changed: 34 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ func NewManifestJSONProcessorFn(out io.Writer) ProcessingFunction {
2828
continueRunning = false
2929
break
3030
}
31-
m.DiscoveredImages = append(m.DiscoveredImages, processContainers(p, logger)...)
31+
m.Insert(processContainers(p, logger)...)
3232
case <-ctx.Done():
3333
logger.Debug("processorFn completing because the context completed")
3434
continueRunning = false
@@ -64,9 +64,17 @@ func processContainers(
6464
found = append(
6565
found,
6666
discovery.DiscoveredImage{
67-
PodName: p.Name,
68-
ContainerName: c.Name,
69-
Image: c.Image,
67+
Image: c.Image,
68+
Containers: []discovery.DiscoveredContainer{
69+
{
70+
Name: c.Name,
71+
Type: discovery.Container,
72+
Pod: discovery.DiscoveredPod{
73+
Name: p.Name,
74+
Namespace: p.Namespace,
75+
},
76+
},
77+
},
7078
},
7179
)
7280
}
@@ -76,9 +84,17 @@ func processContainers(
7684
found = append(
7785
found,
7886
discovery.DiscoveredImage{
79-
PodName: p.Name,
80-
ContainerName: c.Name,
81-
Image: c.Image,
87+
Image: c.Image,
88+
Containers: []discovery.DiscoveredContainer{
89+
{
90+
Name: c.Name,
91+
Type: discovery.InitContainer,
92+
Pod: discovery.DiscoveredPod{
93+
Name: p.Name,
94+
Namespace: p.Namespace,
95+
},
96+
},
97+
},
8298
},
8399
)
84100
}
@@ -88,9 +104,17 @@ func processContainers(
88104
found = append(
89105
found,
90106
discovery.DiscoveredImage{
91-
PodName: p.Name,
92-
ContainerName: c.Name,
93-
Image: c.Image,
107+
Image: c.Image,
108+
Containers: []discovery.DiscoveredContainer{
109+
{
110+
Name: c.Name,
111+
Type: discovery.EphemeralContainer,
112+
Pod: discovery.DiscoveredPod{
113+
Name: p.Name,
114+
Namespace: p.Namespace,
115+
},
116+
},
117+
},
94118
},
95119
)
96120
}

0 commit comments

Comments
 (0)