inspektor-gadget
243 строки · 6.5 Кб
1// Copyright 2023 The Inspektor Gadget authors
2//
3// Licensed under the Apache License, Version 2.0 (the "License");
4// you may not use this file except in compliance with the License.
5// You may obtain a copy of the License at
6//
7// http://www.apache.org/licenses/LICENSE-2.0
8//
9// Unless required by applicable law or agreed to in writing, software
10// distributed under the License is distributed on an "AS IS" BASIS,
11// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12// See the License for the specific language governing permissions and
13// limitations under the License.
14
15package containercollection
16
17import (
18"fmt"
19"math/rand"
20"testing"
21"time"
22
23"github.com/stretchr/testify/require"
24
25utilstest "github.com/inspektor-gadget/inspektor-gadget/internal/test"
26types "github.com/inspektor-gadget/inspektor-gadget/pkg/types"
27)
28
29type fakeTracerMapsUpdater struct {
30containers map[string]*Container
31}
32
33var r *rand.Rand = rand.New(rand.NewSource(time.Now().UnixNano()))
34
35func (f *fakeTracerMapsUpdater) TracerMapsUpdater() FuncNotify {
36return func(event PubSubEvent) {
37switch event.Type {
38case EventTypeAddContainer:
39f.containers[event.Container.Runtime.ContainerID] = event.Container
40case EventTypeRemoveContainer:
41delete(f.containers, event.Container.Runtime.ContainerID)
42}
43}
44}
45
46func BenchmarkCreateContainerCollection(b *testing.B) {
47b.ReportAllocs()
48
49for n := 0; n < b.N; n++ {
50cc := ContainerCollection{}
51cc.AddContainer(&Container{
52Runtime: RuntimeMetadata{
53BasicRuntimeMetadata: types.BasicRuntimeMetadata{
54ContainerID: fmt.Sprint(n),
55},
56},
57Mntns: uint64(n),
58})
59}
60}
61
62const (
63TestContainerCount = 10000
64)
65
66func BenchmarkLookupContainerByMntns(b *testing.B) {
67cc := ContainerCollection{}
68
69for n := 0; n < TestContainerCount; n++ {
70cc.AddContainer(&Container{
71Runtime: RuntimeMetadata{
72BasicRuntimeMetadata: types.BasicRuntimeMetadata{
73ContainerID: fmt.Sprint(n),
74},
75},
76Mntns: uint64(n),
77})
78}
79
80b.ResetTimer()
81
82for n := 0; n < b.N; n++ {
83mntnsID := uint64(r.Intn(TestContainerCount))
84container := cc.LookupContainerByMntns(mntnsID)
85if container == nil {
86b.Fatalf("there should be a container for mount namespace ID %d", mntnsID)
87}
88}
89}
90
91func BenchmarkLookupContainerByNetns(b *testing.B) {
92cc := ContainerCollection{}
93
94for n := 0; n < TestContainerCount; n++ {
95cc.AddContainer(&Container{
96Runtime: RuntimeMetadata{
97BasicRuntimeMetadata: types.BasicRuntimeMetadata{
98ContainerID: fmt.Sprint(n),
99},
100},
101Netns: uint64(n),
102})
103}
104
105b.ResetTimer()
106
107for n := 0; n < b.N; n++ {
108netnsID := uint64(r.Intn(TestContainerCount))
109container := cc.LookupContainersByNetns(netnsID)
110if len(container) == 0 {
111b.Fatalf("there should be a container for net namespace ID %d", netnsID)
112}
113}
114}
115
116func TestWithTracerCollection(t *testing.T) {
117t.Parallel()
118
119// We need root to create the runners that will act as containers on this test
120utilstest.RequireRoot(t)
121
122cc := ContainerCollection{}
123f := &fakeTracerMapsUpdater{containers: make(map[string]*Container)}
124
125if err := cc.Initialize(WithTracerCollection(f)); err != nil {
126t.Fatalf("Failed to initialize container collection: %s", err)
127}
128
129nContainers := 5
130
131// We have to use real runners here as the WithTracerCollection() will drop the enricher if
132// this doesn't have a valid PID
133runners := make([]*utilstest.Runner, nContainers)
134containers := make([]*Container, nContainers)
135
136for i := 0; i < nContainers; i++ {
137runner, err := utilstest.NewRunner(nil)
138if err != nil {
139t.Fatalf("Creating runner: %s", err)
140}
141t.Cleanup(runner.Close)
142
143runners[i] = runner
144
145containers[i] = &Container{
146Runtime: RuntimeMetadata{
147BasicRuntimeMetadata: types.BasicRuntimeMetadata{
148RuntimeName: types.RuntimeNameDocker,
149ContainerName: fmt.Sprintf("name%d", i),
150ContainerID: fmt.Sprintf("id%d", i),
151},
152},
153Mntns: runner.Info.MountNsID,
154Netns: runner.Info.NetworkNsID,
155Pid: uint32(runner.Info.Pid),
156K8s: K8sMetadata{
157BasicK8sMetadata: types.BasicK8sMetadata{
158ContainerName: fmt.Sprintf("name%d", i),
159Namespace: fmt.Sprintf("namespace%d", i),
160PodName: fmt.Sprintf("pod%d", i),
161},
162},
163}
164cc.AddContainer(containers[i])
165}
166
167require.Equal(t, nContainers, len(f.containers), "number of containers should be equal")
168
169verifyEnrichByMntNs := func() {
170for i := 0; i < nContainers; i++ {
171ev := types.CommonData{}
172expected := types.CommonData{
173Runtime: types.BasicRuntimeMetadata{
174RuntimeName: containers[i].Runtime.RuntimeName,
175ContainerName: containers[i].Runtime.ContainerName,
176ContainerID: containers[i].Runtime.ContainerID,
177},
178K8s: types.K8sMetadata{
179BasicK8sMetadata: types.BasicK8sMetadata{
180Namespace: containers[i].K8s.Namespace,
181PodName: containers[i].K8s.PodName,
182ContainerName: containers[i].K8s.ContainerName,
183},
184},
185}
186
187cc.EnrichByMntNs(&ev, containers[i].Mntns)
188
189require.Equal(t, expected, ev, "events should be equal")
190}
191}
192
193verifyEnrichByNetNs := func() {
194for i := 0; i < nContainers; i++ {
195ev := types.CommonData{}
196expected := types.CommonData{
197Runtime: types.BasicRuntimeMetadata{
198RuntimeName: containers[i].Runtime.RuntimeName,
199ContainerName: containers[i].Runtime.ContainerName,
200ContainerID: containers[i].Runtime.ContainerID,
201},
202K8s: types.K8sMetadata{
203BasicK8sMetadata: types.BasicK8sMetadata{
204Namespace: containers[i].K8s.Namespace,
205PodName: containers[i].K8s.PodName,
206ContainerName: containers[i].K8s.ContainerName,
207},
208},
209}
210
211cc.EnrichByNetNs(&ev, containers[i].Netns)
212
213require.Equal(t, expected, ev, "events should be equal")
214}
215}
216
217// Enrich by should work
218verifyEnrichByMntNs()
219verifyEnrichByNetNs()
220
221cc.RemoveContainer(containers[0].Runtime.ContainerID)
222
223// Pubsub events should be triggered immediately after container removal
224require.Equal(t, nContainers-1, len(f.containers), "number of containers should be equal")
225
226time.Sleep(1 * time.Second)
227
228// Enrich should work 1 second after removing container
229verifyEnrichByMntNs()
230verifyEnrichByNetNs()
231
232time.Sleep(6 * time.Second)
233
234// Enrich should **not** work after removing container more than 6 seconds ago
235ev := types.CommonData{}
236expected := types.CommonData{}
237cc.EnrichByMntNs(&ev, containers[0].Mntns)
238require.Equal(t, expected, ev, "events should be equal")
239
240// This is in a separated line to understand who is causing the issue.
241cc.EnrichByNetNs(&ev, containers[0].Netns)
242require.Equal(t, expected, ev, "events should be equal")
243}
244