Skip to content

Commit 0220117

Browse files
authored
Merge pull request #53 from kubescape/bugfix/memory-leak
Bugfix/memory leak
2 parents 4f9b43f + e138fd3 commit 0220117

File tree

4 files changed

+87
-67
lines changed

4 files changed

+87
-67
lines changed

Makefile

+1-1
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ IMAGE_NAME ?= kapprofiler:latest
1414

1515

1616
$(BINARY_NAME): $(GOFILES) go.mod go.sum Makefile
17-
CGO_ENABLED=1 go build -o $(BINARY_NAME) -v
17+
CGO_ENABLED=0 go build -o $(BINARY_NAME) -v
1818

1919
test:
2020
$(GOTEST_SUDO_PREFIX) $(GOTEST) -v ./...

pkg/collector/types.go

+9-2
Original file line numberDiff line numberDiff line change
@@ -130,8 +130,15 @@ func (a DnsCalls) Equals(b DnsCalls) bool {
130130
if len(a.Addresses) != len(b.Addresses) {
131131
return false
132132
}
133-
for i, addr := range a.Addresses {
134-
if addr != b.Addresses[i] {
133+
for _, addr := range a.Addresses {
134+
found := false
135+
for _, baddr := range b.Addresses {
136+
if addr == baddr {
137+
found = true
138+
break
139+
}
140+
}
141+
if !found {
135142
return false
136143
}
137144
}

pkg/controller/controller.go

+6-8
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,6 @@ func (c *Controller) StartController() {
6363
},
6464
UpdateFunc: func(obj *unstructured.Unstructured) {
6565
c.handleApplicationProfile(obj)
66-
6766
},
6867
DeleteFunc: func(obj *unstructured.Unstructured) {
6968
c.handleApplicationProfile(obj)
@@ -77,7 +76,6 @@ func (c *Controller) StartController() {
7776

7877
// Set the watcher
7978
c.watcher = appProfileWatcher
80-
8179
}
8280

8381
// Stop the AppProfile controller
@@ -112,7 +110,7 @@ func (c *Controller) handleApplicationProfile(applicationProfileUnstructured *un
112110
if err != nil {
113111
return
114112
}
115-
deploymentApplicationProfile := &collector.ApplicationProfile{
113+
deploymentApplicationProfile := collector.ApplicationProfile{
116114
TypeMeta: metav1.TypeMeta{
117115
Kind: collector.ApplicationProfileKind,
118116
APIVersion: collector.ApplicationProfileApiVersion,
@@ -125,7 +123,7 @@ func (c *Controller) handleApplicationProfile(applicationProfileUnstructured *un
125123
Containers: applicationProfile.Spec.Containers,
126124
},
127125
}
128-
deploymentApplicationProfileRaw, err := runtime.DefaultUnstructuredConverter.ToUnstructured(deploymentApplicationProfile)
126+
deploymentApplicationProfileRaw, err := runtime.DefaultUnstructuredConverter.ToUnstructured(&deploymentApplicationProfile)
129127
if err != nil {
130128
return
131129
}
@@ -145,7 +143,7 @@ func (c *Controller) handleApplicationProfile(applicationProfileUnstructured *un
145143
return
146144
}
147145

148-
deploymentApplicationProfile := &collector.ApplicationProfile{}
146+
deploymentApplicationProfile := collector.ApplicationProfile{}
149147
deploymentApplicationProfile.Labels = applicationProfile.GetLabels()
150148
deploymentApplicationProfile.Spec.Containers = applicationProfile.Spec.Containers
151149
deploymentApplicationProfileRaw, _ := json.Marshal(deploymentApplicationProfile)
@@ -357,7 +355,7 @@ func (c *Controller) handleApplicationProfile(applicationProfileUnstructured *un
357355
// Fetch ApplicationProfile of the controller
358356
existingApplicationProfile, err := c.dynamicClient.Resource(collector.AppProfileGvr).Namespace(pod.Namespace).Get(context.TODO(), applicationProfileNameForController, metav1.GetOptions{})
359357
if err != nil { // ApplicationProfile of controller doesn't exist so create a new one
360-
controllerApplicationProfile := &collector.ApplicationProfile{
358+
controllerApplicationProfile := collector.ApplicationProfile{
361359
TypeMeta: metav1.TypeMeta{
362360
Kind: collector.ApplicationProfileKind,
363361
APIVersion: collector.ApplicationProfileApiVersion,
@@ -370,7 +368,7 @@ func (c *Controller) handleApplicationProfile(applicationProfileUnstructured *un
370368
Containers: containers,
371369
},
372370
}
373-
controllerApplicationProfileRaw, err := runtime.DefaultUnstructuredConverter.ToUnstructured(controllerApplicationProfile)
371+
controllerApplicationProfileRaw, err := runtime.DefaultUnstructuredConverter.ToUnstructured(&controllerApplicationProfile)
374372
if err != nil {
375373
log.Printf("Error converting ApplicationProfile of controller %v", err)
376374
return
@@ -386,7 +384,7 @@ func (c *Controller) handleApplicationProfile(applicationProfileUnstructured *un
386384
// Don't update the application profile
387385
return
388386
}
389-
controllerApplicationProfile := &collector.ApplicationProfile{}
387+
controllerApplicationProfile := collector.ApplicationProfile{}
390388
controllerApplicationProfile.Labels = applicationProfileUnstructured.GetLabels()
391389
controllerApplicationProfile.Spec.Containers = containers
392390
controllerApplicationProfileRaw, _ := json.Marshal(controllerApplicationProfile)

pkg/watcher/watcher.go

+71-56
Original file line numberDiff line numberDiff line change
@@ -90,69 +90,84 @@ func (w *Watcher) Start(notifyF WatchNotifyFunctions, gvr schema.GroupVersionRes
9090
}
9191
w.watcher = watcher
9292
w.running = true
93+
94+
// Use a context to gracefully stop the goroutine
95+
ctx, cancel := context.WithCancel(context.Background())
96+
defer cancel()
97+
9398
go func() {
9499
// Watch for events
100+
defer func() {
101+
// Ensure the watcher is closed when the goroutine exits
102+
watcher.Stop()
103+
}()
95104

96105
for {
97-
event, ok := <-watcher.ResultChan()
98-
if !ok {
99-
if w.running {
100-
// Need to restart the watcher: wait a bit and restart
101-
time.Sleep(5 * time.Second)
102-
listOptions.ResourceVersion = resourceVersion
103-
w.watcher, err = w.client.Resource(gvr).Namespace("").Watch(context.Background(), listOptions)
104-
if err != nil {
105-
log.Printf("watcher restart error: %v", err)
106+
select {
107+
case event, ok := <-watcher.ResultChan():
108+
if !ok {
109+
if w.running {
110+
// Need to restart the watcher: wait a bit and restart
111+
time.Sleep(5 * time.Second)
112+
listOptions.ResourceVersion = resourceVersion
113+
newWatcher, err := w.client.Resource(gvr).Namespace("").Watch(context.Background(), listOptions)
114+
if err != nil {
115+
log.Printf("watcher restart error: %v", err)
116+
return
117+
}
118+
w.watcher = newWatcher
119+
// Restart the loop
120+
continue
121+
} else {
122+
// Stop the watcher
123+
return
106124
}
107-
// Restart the loop
108-
continue
109-
} else {
110-
// Stop the watcher
111-
return
112-
}
113-
}
114-
switch event.Type {
115-
case watch.Added:
116-
// Convert the object to unstructured
117-
addedObject := event.Object.(*unstructured.Unstructured)
118-
if addedObject == nil {
119-
log.Printf("watcher error: addedObject is nil")
120-
continue
121-
}
122-
// Update the resourceVersion
123-
if addedObject.GetResourceVersion() > resourceVersion {
124-
resourceVersion = addedObject.GetResourceVersion()
125-
}
126-
notifyF.AddFunc(addedObject)
127-
addedObject = nil // Make sure the item is scraped by the GC
128-
case watch.Modified:
129-
// Convert the object to unstructured
130-
modifiedObject := event.Object.(*unstructured.Unstructured)
131-
if modifiedObject == nil {
132-
log.Printf("watcher error: modifiedObject is nil")
133-
continue
134-
}
135-
// Update the resourceVersion
136-
if modifiedObject.GetResourceVersion() > resourceVersion {
137-
resourceVersion = modifiedObject.GetResourceVersion()
138-
}
139-
notifyF.UpdateFunc(modifiedObject)
140-
modifiedObject = nil // Make sure the item is scraped by the GC
141-
case watch.Deleted:
142-
// Convert the object to unstructured
143-
deletedObject := event.Object.(*unstructured.Unstructured)
144-
if deletedObject == nil {
145-
log.Printf("watcher error: deletedObject is nil")
146-
continue
147125
}
148-
// Update the resourceVersion
149-
if deletedObject.GetResourceVersion() > resourceVersion {
150-
resourceVersion = deletedObject.GetResourceVersion()
126+
127+
switch event.Type {
128+
case watch.Added:
129+
// Convert the object to unstructured
130+
addedObject := event.Object.(*unstructured.Unstructured)
131+
if addedObject == nil {
132+
log.Printf("watcher error: addedObject is nil")
133+
continue
134+
}
135+
// Update the resourceVersion
136+
if addedObject.GetResourceVersion() > resourceVersion {
137+
resourceVersion = addedObject.GetResourceVersion()
138+
}
139+
notifyF.AddFunc(addedObject)
140+
case watch.Modified:
141+
// Convert the object to unstructured
142+
modifiedObject := event.Object.(*unstructured.Unstructured)
143+
if modifiedObject == nil {
144+
log.Printf("watcher error: modifiedObject is nil")
145+
continue
146+
}
147+
// Update the resourceVersion
148+
if modifiedObject.GetResourceVersion() > resourceVersion {
149+
resourceVersion = modifiedObject.GetResourceVersion()
150+
}
151+
notifyF.UpdateFunc(modifiedObject)
152+
case watch.Deleted:
153+
// Convert the object to unstructured
154+
deletedObject := event.Object.(*unstructured.Unstructured)
155+
if deletedObject == nil {
156+
log.Printf("watcher error: deletedObject is nil")
157+
continue
158+
}
159+
// Update the resourceVersion
160+
if deletedObject.GetResourceVersion() > resourceVersion {
161+
resourceVersion = deletedObject.GetResourceVersion()
162+
}
163+
notifyF.DeleteFunc(deletedObject)
164+
case watch.Error:
165+
log.Printf("watcher error: %v", event.Object)
151166
}
152-
notifyF.DeleteFunc(deletedObject)
153-
deletedObject = nil // Make sure the item is scraped by the GC
154-
case watch.Error:
155-
log.Printf("watcher error: %v", event.Object)
167+
168+
case <-ctx.Done():
169+
// Exit the goroutine when the context is canceled
170+
return
156171
}
157172
}
158173
}()

0 commit comments

Comments
 (0)