Skip to content

Commit 5861354

Browse files
added new task nodemonitor
Added new task to monitor the resources of remote nodes, like ram, swap, number of processes or load average of the system. The task is initiated when the user selects a node, and the data received from the node is added to the right panel of the Nodes tab. The task is stopped when changing to another tab, or when deselecting a node. Particularly useful for monitoring remote nodes.
1 parent aea7517 commit 5861354

File tree

6 files changed

+1195
-670
lines changed

6 files changed

+1195
-670
lines changed

daemon/tasks/nodemonitor/main.go

Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
package nodemonitor
2+
3+
import (
4+
"context"
5+
"encoding/json"
6+
"fmt"
7+
"syscall"
8+
"time"
9+
"unsafe"
10+
11+
"github.com/evilsocket/opensnitch/daemon/log"
12+
"github.com/evilsocket/opensnitch/daemon/tasks"
13+
)
14+
15+
// Name of this task
16+
var Name = "node-monitor"
17+
18+
// Config of this task
19+
type Config struct {
20+
Interval string
21+
Name string
22+
}
23+
24+
// NodeMonitor monitors the resources of a node (ram, swap, load avg, etc).
25+
type NodeMonitor struct {
26+
tasks.TaskBase
27+
Ticker *time.Ticker
28+
29+
Interval string
30+
Node string
31+
}
32+
33+
// New returns a new NodeMonitor
34+
func New(node, interval string, stopOnDisconnect bool) (string, *NodeMonitor) {
35+
return fmt.Sprint(Name, "-", node), &NodeMonitor{
36+
TaskBase: tasks.TaskBase{
37+
Results: make(chan interface{}),
38+
Errors: make(chan error),
39+
StopChan: make(chan struct{}),
40+
},
41+
Node: node,
42+
Interval: interval,
43+
}
44+
}
45+
46+
// Start ...
47+
func (pm *NodeMonitor) Start(ctx context.Context, cancel context.CancelFunc) error {
48+
pm.Ctx = ctx
49+
pm.Cancel = cancel
50+
51+
if pm.Interval == "" {
52+
pm.Interval = "5s"
53+
}
54+
interval, err := time.ParseDuration(pm.Interval)
55+
if err != nil {
56+
return err
57+
}
58+
pm.Ticker = time.NewTicker(interval)
59+
go func(ctx context.Context) {
60+
var info syscall.Sysinfo_t
61+
for {
62+
select {
63+
case <-pm.StopChan:
64+
goto Exit
65+
case <-ctx.Done():
66+
goto Exit
67+
case <-pm.Ticker.C:
68+
// TODO:
69+
// - filesystem stats
70+
// - daemon status (mem && cpu usage, internal/debug pkg, etc)
71+
err := syscall.Sysinfo(&info)
72+
if err != nil {
73+
pm.TaskBase.Errors <- err
74+
continue
75+
}
76+
infoJSON, err := json.Marshal(info)
77+
if err != nil {
78+
pm.TaskBase.Errors <- err
79+
continue
80+
}
81+
pm.TaskBase.Results <- unsafe.String(unsafe.SliceData(infoJSON), len(infoJSON))
82+
}
83+
}
84+
Exit:
85+
log.Debug("[tasks.NodeMonitor] stopped (%s)", pm.Node)
86+
}(ctx)
87+
return err
88+
}
89+
90+
// Pause stops temporarily the task. For example it might be paused when the
91+
// connection with the GUI (server) is closed.
92+
func (pm *NodeMonitor) Pause() error {
93+
// TODO
94+
return nil
95+
}
96+
97+
// Resume stopped tasks.
98+
func (pm *NodeMonitor) Resume() error {
99+
// TODO
100+
return nil
101+
}
102+
103+
// Stop ...
104+
func (pm *NodeMonitor) Stop() error {
105+
if pm.StopOnDisconnect {
106+
return nil
107+
}
108+
pm.Cancel()
109+
close(pm.TaskBase.Results)
110+
close(pm.TaskBase.Errors)
111+
return nil
112+
}
113+
114+
// Results ...
115+
func (pm *NodeMonitor) Results() <-chan interface{} {
116+
return pm.TaskBase.Results
117+
}
118+
119+
// Errors ...
120+
func (pm *NodeMonitor) Errors() <-chan error {
121+
return pm.TaskBase.Errors
122+
}

daemon/ui/notifications.go

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import (
1515
"github.com/evilsocket/opensnitch/daemon/procmon/monitor"
1616
"github.com/evilsocket/opensnitch/daemon/rule"
1717
"github.com/evilsocket/opensnitch/daemon/tasks"
18+
"github.com/evilsocket/opensnitch/daemon/tasks/nodemonitor"
1819
"github.com/evilsocket/opensnitch/daemon/tasks/pidmonitor"
1920
"github.com/evilsocket/opensnitch/daemon/ui/config"
2021
"github.com/evilsocket/opensnitch/daemon/ui/protocol"
@@ -58,6 +59,33 @@ func (c *Client) getClientConfig() *protocol.ClientConfig {
5859
}
5960
}
6061

62+
func (c *Client) monitorNode(node, interval string, stream protocol.UI_NotificationsClient, notification *protocol.Notification) {
63+
taskName, nodeMonTask := nodemonitor.New(node, interval, true)
64+
ctxNode, err := TaskMgr.AddTask(taskName, nodeMonTask)
65+
if err != nil {
66+
c.sendNotificationReply(stream, notification.Id, "", err)
67+
return
68+
}
69+
go func(ctx context.Context) {
70+
for {
71+
select {
72+
case <-ctx.Done():
73+
goto Exit
74+
case err := <-nodeMonTask.Errors():
75+
c.sendNotificationReply(stream, notification.Id, "", err)
76+
case temp := <-nodeMonTask.Results():
77+
data, ok := temp.(string)
78+
if !ok {
79+
goto Exit
80+
}
81+
c.sendNotificationReply(stream, notification.Id, data, nil)
82+
}
83+
}
84+
Exit:
85+
TaskMgr.RemoveTask(taskName)
86+
}(ctxNode)
87+
}
88+
6189
func (c *Client) monitorProcessDetails(pid int, interval string, stream protocol.UI_NotificationsClient, notification *protocol.Notification) {
6290
if !core.Exists(fmt.Sprint("/proc/", pid)) {
6391
c.sendNotificationReply(stream, notification.Id, "", fmt.Errorf("The process is no longer running"))
@@ -185,6 +213,8 @@ func (c *Client) handleActionTaskStart(stream protocol.UI_NotificationsClient, n
185213
return
186214
}
187215
c.monitorProcessDetails(pid, taskConf.Data["interval"], stream, notification)
216+
case nodemonitor.Name:
217+
c.monitorNode(taskConf.Data["node"], taskConf.Data["interval"], stream, notification)
188218
default:
189219
log.Debug("TaskStart, unknown task: %v", taskConf)
190220
//c.sendNotificationReply(stream, notification.Id, "", err)
@@ -208,6 +238,8 @@ func (c *Client) handleActionTaskStop(stream protocol.UI_NotificationsClient, no
208238
return
209239
}
210240
TaskMgr.RemoveTask(fmt.Sprint(taskConf.Name, "-", pid))
241+
case nodemonitor.Name:
242+
TaskMgr.RemoveTask(fmt.Sprint(nodemonitor.Name, "-", taskConf.Data["node"]))
211243
default:
212244
log.Debug("TaskStop, unknown task: %v", taskConf)
213245
//c.sendNotificationReply(stream, notification.Id, "", err)

ui/opensnitch/config.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,7 @@ class Config:
140140
STATS_RULES_TREE_EXPANDED_0 = "statsDialog/rules_tree_0_expanded"
141141
STATS_RULES_TREE_EXPANDED_1 = "statsDialog/rules_tree_1_expanded"
142142
STATS_RULES_SPLITTER_POS = "statsDialog/rules_splitter_pos"
143+
STATS_NODES_SPLITTER_POS = "statsDialog/nodes_splitter_pos"
143144
STATS_VIEW_COL_STATE = "statsDialog/view_columns_state"
144145
STATS_VIEW_DETAILS_COL_STATE = "statsDialog/view_details_columns_state"
145146

0 commit comments

Comments
 (0)