mirror of
https://github.com/henrygd/beszel.git
synced 2025-12-17 10:46:16 +01:00
add basic systemd service monitoring (#1153)
Co-authored-by: Shelby Tucker <shelby.tucker@gmail.com>
This commit is contained in:
@@ -7,6 +7,7 @@ import (
|
||||
"github.com/fxamacker/cbor/v2"
|
||||
"github.com/henrygd/beszel/internal/common"
|
||||
"github.com/henrygd/beszel/internal/entities/system"
|
||||
"github.com/henrygd/beszel/internal/entities/systemd"
|
||||
"github.com/lxzan/gws"
|
||||
"golang.org/x/crypto/ssh"
|
||||
)
|
||||
@@ -115,6 +116,44 @@ func (ws *WsConn) RequestContainerInfo(ctx context.Context, containerID string)
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// RequestSystemdInfo requests detailed information about a systemd service via WebSocket.
|
||||
func (ws *WsConn) RequestSystemdInfo(ctx context.Context, serviceName string) (systemd.ServiceDetails, error) {
|
||||
if !ws.IsConnected() {
|
||||
return nil, gws.ErrConnClosed
|
||||
}
|
||||
|
||||
req, err := ws.requestManager.SendRequest(ctx, common.GetSystemdInfo, common.SystemdInfoRequest{ServiceName: serviceName})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
var result systemd.ServiceDetails
|
||||
handler := &systemdInfoHandler{result: &result}
|
||||
if err := ws.handleAgentRequest(req, handler); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// systemdInfoHandler parses ServiceDetails from AgentResponse
|
||||
type systemdInfoHandler struct {
|
||||
BaseHandler
|
||||
result *systemd.ServiceDetails
|
||||
}
|
||||
|
||||
func (h *systemdInfoHandler) Handle(agentResponse common.AgentResponse) error {
|
||||
if agentResponse.ServiceInfo == nil {
|
||||
return errors.New("no systemd info in response")
|
||||
}
|
||||
*h.result = agentResponse.ServiceInfo
|
||||
return nil
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// RequestSmartData requests SMART data via WebSocket.
|
||||
func (ws *WsConn) RequestSmartData(ctx context.Context) (map[string]any, error) {
|
||||
if !ws.IsConnected() {
|
||||
|
||||
75
internal/hub/ws/handlers_test.go
Normal file
75
internal/hub/ws/handlers_test.go
Normal file
@@ -0,0 +1,75 @@
|
||||
//go:build testing
|
||||
|
||||
package ws
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/henrygd/beszel/internal/common"
|
||||
"github.com/henrygd/beszel/internal/entities/systemd"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestSystemdInfoHandlerSuccess(t *testing.T) {
|
||||
handler := &systemdInfoHandler{
|
||||
result: &systemd.ServiceDetails{},
|
||||
}
|
||||
|
||||
// Test successful handling with valid ServiceInfo
|
||||
testDetails := systemd.ServiceDetails{
|
||||
"Id": "nginx.service",
|
||||
"ActiveState": "active",
|
||||
"SubState": "running",
|
||||
"Description": "A high performance web server",
|
||||
"ExecMainPID": 1234,
|
||||
"MemoryCurrent": 1024000,
|
||||
}
|
||||
|
||||
response := common.AgentResponse{
|
||||
ServiceInfo: testDetails,
|
||||
}
|
||||
|
||||
err := handler.Handle(response)
|
||||
assert.NoError(t, err)
|
||||
assert.Equal(t, testDetails, *handler.result)
|
||||
}
|
||||
|
||||
func TestSystemdInfoHandlerError(t *testing.T) {
|
||||
handler := &systemdInfoHandler{
|
||||
result: &systemd.ServiceDetails{},
|
||||
}
|
||||
|
||||
// Test error handling when ServiceInfo is nil
|
||||
response := common.AgentResponse{
|
||||
ServiceInfo: nil,
|
||||
Error: "service not found",
|
||||
}
|
||||
|
||||
err := handler.Handle(response)
|
||||
assert.Error(t, err)
|
||||
assert.Equal(t, "no systemd info in response", err.Error())
|
||||
}
|
||||
|
||||
func TestSystemdInfoHandlerEmptyResponse(t *testing.T) {
|
||||
handler := &systemdInfoHandler{
|
||||
result: &systemd.ServiceDetails{},
|
||||
}
|
||||
|
||||
// Test with completely empty response
|
||||
response := common.AgentResponse{}
|
||||
|
||||
err := handler.Handle(response)
|
||||
assert.Error(t, err)
|
||||
assert.Equal(t, "no systemd info in response", err.Error())
|
||||
}
|
||||
|
||||
func TestSystemdInfoHandlerLegacyNotSupported(t *testing.T) {
|
||||
handler := &systemdInfoHandler{
|
||||
result: &systemd.ServiceDetails{},
|
||||
}
|
||||
|
||||
// Test that legacy format is not supported
|
||||
err := handler.HandleLegacy([]byte("some data"))
|
||||
assert.Error(t, err)
|
||||
assert.Equal(t, "legacy format not supported", err.Error())
|
||||
}
|
||||
Reference in New Issue
Block a user