summaryrefslogtreecommitdiff
path: root/internal/probemanager
diff options
context:
space:
mode:
authorPaul Buetow <paul@buetow.org>2026-02-25 21:57:30 +0200
committerPaul Buetow <paul@buetow.org>2026-02-25 21:57:30 +0200
commit67e10f34c92e93343adbd690b3b21e455e863bd3 (patch)
tree5de8f76cea00ea7c70703cb215cb5eb12fd17fa3 /internal/probemanager
parent92dbc37ed6d4b1758fae3fa7ae02dc58b8f81d4d (diff)
Fix probes bulk toggles and stabilize modal row rendering
Diffstat (limited to 'internal/probemanager')
-rw-r--r--internal/probemanager/manager.go38
-rw-r--r--internal/probemanager/manager_test.go31
2 files changed, 60 insertions, 9 deletions
diff --git a/internal/probemanager/manager.go b/internal/probemanager/manager.go
index 5a7e85d..65dd52b 100644
--- a/internal/probemanager/manager.go
+++ b/internal/probemanager/manager.go
@@ -4,6 +4,7 @@ import (
"errors"
"fmt"
"sort"
+ "strings"
"sync"
)
@@ -179,25 +180,44 @@ func (m *Manager) Detach(syscall string) error {
}
enterLink := entry.enterLink
exitLink := entry.exitLink
- entry.enterLink = nil
- entry.exitLink = nil
- entry.active = false
m.mu.Unlock()
+ var errs []string
+ enterErr := error(nil)
if enterLink != nil {
if err := enterLink.Destroy(); err != nil {
- m.setLastError(syscall, fmt.Errorf("detach enter %s: %w", syscall, err))
- return err
+ enterErr = err
+ errs = append(errs, fmt.Sprintf("detach enter %s: %v", syscall, err))
}
}
+ exitErr := error(nil)
if exitLink != nil {
if err := exitLink.Destroy(); err != nil {
- m.setLastError(syscall, fmt.Errorf("detach exit %s: %w", syscall, err))
- return err
+ exitErr = err
+ errs = append(errs, fmt.Sprintf("detach exit %s: %v", syscall, err))
}
}
- m.setLastError(syscall, nil)
- return nil
+
+ m.mu.Lock()
+ defer m.mu.Unlock()
+ entry, err = m.entryLocked(syscall)
+ if err != nil {
+ return err
+ }
+ if enterErr == nil {
+ entry.enterLink = nil
+ }
+ if exitErr == nil {
+ entry.exitLink = nil
+ }
+ entry.active = entry.enterLink != nil || entry.exitLink != nil
+ if len(errs) == 0 {
+ entry.lastErr = nil
+ return nil
+ }
+ combined := errors.New(strings.Join(errs, "; "))
+ entry.lastErr = combined
+ return combined
}
func (m *Manager) States() []ProbeState {
diff --git a/internal/probemanager/manager_test.go b/internal/probemanager/manager_test.go
index f610ea3..1fcce6d 100644
--- a/internal/probemanager/manager_test.go
+++ b/internal/probemanager/manager_test.go
@@ -114,6 +114,37 @@ func TestManagerDetachDestroysLinks(t *testing.T) {
}
}
+func TestManagerDetachFailureKeepsActiveStateForUndetachedLink(t *testing.T) {
+ enter := &fakeLink{err: errors.New("destroy failed")}
+ exit := &fakeLink{}
+ attacher := &fakeAttacher{
+ programs: map[string]*fakeProgram{
+ "handle_sys_enter_close": {link: enter},
+ "handle_sys_exit_close": {link: exit},
+ },
+ errs: map[string]error{},
+ }
+ mgr := NewManager(attacher)
+ if err := mgr.AttachAll(nil, []string{"sys_enter_close", "sys_exit_close"}); err != nil {
+ t.Fatalf("AttachAll returned error: %v", err)
+ }
+
+ err := mgr.Detach("close")
+ if err == nil {
+ t.Fatalf("expected detach error")
+ }
+ states := mgr.States()
+ if len(states) != 1 {
+ t.Fatalf("expected one state, got %+v", states)
+ }
+ if !states[0].Active {
+ t.Fatalf("expected probe to remain active when one link failed to detach")
+ }
+ if states[0].Error == "" {
+ t.Fatalf("expected error to be recorded after detach failure")
+ }
+}
+
func TestManagerClosePreventsFurtherOperations(t *testing.T) {
attacher := &fakeAttacher{
programs: map[string]*fakeProgram{