Compare commits

...

1 Commits

Author SHA1 Message Date
Henry Dollman
8de2dee4e9 built-in agent 2024-10-07 18:58:57 -04:00
5 changed files with 80 additions and 33 deletions

View File

@@ -70,13 +70,15 @@ func (a *Agent) Run(pubKey []byte, addr string) {
// if debugging, print stats // if debugging, print stats
if a.debug { if a.debug {
slog.Debug("Stats", "data", a.gatherStats()) slog.Debug("Stats", "data", a.GatherStats())
} }
a.startServer(pubKey, addr) if pubKey != nil {
a.startServer(pubKey, addr)
}
} }
func (a *Agent) gatherStats() system.CombinedData { func (a *Agent) GatherStats() system.CombinedData {
systemData := system.CombinedData{ systemData := system.CombinedData{
Stats: a.getSystemStats(), Stats: a.getSystemStats(),
Info: a.systemInfo, Info: a.systemInfo,

View File

@@ -24,7 +24,7 @@ func (a *Agent) startServer(pubKey []byte, addr string) {
} }
func (a *Agent) handleSession(s sshServer.Session) { func (a *Agent) handleSession(s sshServer.Session) {
stats := a.gatherStats() stats := a.GatherStats()
slog.Debug("Sending stats", "data", stats) slog.Debug("Sending stats", "data", stats)
if err := json.NewEncoder(s).Encode(stats); err != nil { if err := json.NewEncoder(s).Encode(stats); err != nil {
slog.Error("Error encoding stats", "err", err) slog.Error("Error encoding stats", "err", err)

View File

@@ -3,6 +3,7 @@ package hub
import ( import (
"beszel" "beszel"
"beszel/internal/agent"
"beszel/internal/alerts" "beszel/internal/alerts"
"beszel/internal/entities/system" "beszel/internal/entities/system"
"beszel/internal/records" "beszel/internal/records"
@@ -42,6 +43,7 @@ type Hub struct {
am *alerts.AlertManager am *alerts.AlertManager
um *users.UserManager um *users.UserManager
rm *records.RecordManager rm *records.RecordManager
hubAgent *agent.Agent
} }
func NewHub(app *pocketbase.PocketBase) *Hub { func NewHub(app *pocketbase.PocketBase) *Hub {
@@ -56,10 +58,6 @@ func NewHub(app *pocketbase.PocketBase) *Hub {
} }
func (h *Hub) Run() { func (h *Hub) Run() {
// rm := records.NewRecordManager(h.app)
// am := alerts.NewAlertManager(h.app)
// um := users.NewUserManager(h.app)
// loosely check if it was executed using "go run" // loosely check if it was executed using "go run"
isGoRun := strings.HasPrefix(os.Args[0], os.TempDir()) isGoRun := strings.HasPrefix(os.Args[0], os.TempDir())
@@ -73,25 +71,22 @@ func (h *Hub) Run() {
// initial setup // initial setup
h.app.OnBeforeServe().Add(func(e *core.ServeEvent) error { h.app.OnBeforeServe().Add(func(e *core.ServeEvent) error {
// create ssh client config // create ssh client config
err := h.createSSHClientConfig() if err := h.createSSHClientConfig(); err != nil {
if err != nil {
log.Fatal(err) log.Fatal(err)
} }
// set auth settings // set auth settings
usersCollection, err := h.app.Dao().FindCollectionByNameOrId("users") if usersCollection, err := h.app.Dao().FindCollectionByNameOrId("users"); err == nil {
if err != nil { usersAuthOptions := usersCollection.AuthOptions()
return err usersAuthOptions.AllowUsernameAuth = false
} if os.Getenv("DISABLE_PASSWORD_AUTH") == "true" {
usersAuthOptions := usersCollection.AuthOptions() usersAuthOptions.AllowEmailAuth = false
usersAuthOptions.AllowUsernameAuth = false } else {
if os.Getenv("DISABLE_PASSWORD_AUTH") == "true" { usersAuthOptions.AllowEmailAuth = true
usersAuthOptions.AllowEmailAuth = false }
} else { usersCollection.SetOptions(usersAuthOptions)
usersAuthOptions.AllowEmailAuth = true if err := h.app.Dao().SaveCollection(usersCollection); err != nil {
} return err
usersCollection.SetOptions(usersAuthOptions) }
if err := h.app.Dao().SaveCollection(usersCollection); err != nil {
return err
} }
return nil return nil
}) })
@@ -159,6 +154,16 @@ func (h *Hub) Run() {
// system creation defaults // system creation defaults
h.app.OnModelBeforeCreate("systems").Add(func(e *core.ModelEvent) error { h.app.OnModelBeforeCreate("systems").Add(func(e *core.ModelEvent) error {
record := e.Model.(*models.Record) record := e.Model.(*models.Record)
if record.GetString("host") == "hubsys" {
// todo: check for hubsys existance and return error if exists (or make sure user is admin)
if record.GetString("name") == "x" {
hostname, _ := os.Hostname()
if hostname == "" {
hostname = "localhost"
}
record.Set("name", hostname)
}
}
record.Set("info", system.Info{}) record.Set("info", system.Info{})
record.Set("status", "pending") record.Set("status", "pending")
return nil return nil
@@ -246,6 +251,26 @@ func (h *Hub) updateSystems() {
} }
func (h *Hub) updateSystem(record *models.Record) { func (h *Hub) updateSystem(record *models.Record) {
switch record.GetString("host") {
case "hubsys":
h.updateHubSystem(record)
default:
h.updateRemoteSystem(record)
}
}
// Update hub system stats with built-in agent
func (h *Hub) updateHubSystem(record *models.Record) {
if h.hubAgent == nil {
h.hubAgent = agent.NewAgent()
h.hubAgent.Run(nil, "")
}
systemData := h.hubAgent.GatherStats()
h.saveSystemStats(record, &systemData)
}
// Connect to remote system and update system stats
func (h *Hub) updateRemoteSystem(record *models.Record) {
var client *ssh.Client var client *ssh.Client
var err error var err error
@@ -273,7 +298,7 @@ func (h *Hub) updateSystem(record *models.Record) {
// if previous connection was closed, try again // if previous connection was closed, try again
h.app.Logger().Error("Existing SSH connection closed. Retrying...", "host", record.GetString("host"), "port", record.GetString("port")) h.app.Logger().Error("Existing SSH connection closed. Retrying...", "host", record.GetString("host"), "port", record.GetString("port"))
h.deleteSystemConnection(record) h.deleteSystemConnection(record)
h.updateSystem(record) h.updateRemoteSystem(record)
return return
} }
h.app.Logger().Error("Failed to get system stats: ", "err", err.Error()) h.app.Logger().Error("Failed to get system stats: ", "err", err.Error())
@@ -281,6 +306,11 @@ func (h *Hub) updateSystem(record *models.Record) {
return return
} }
// update system record // update system record
h.saveSystemStats(record, &systemData)
}
// Update system record with provided system.CombinedData
func (h *Hub) saveSystemStats(record *models.Record, systemData *system.CombinedData) {
record.Set("status", "up") record.Set("status", "up")
record.Set("info", systemData.Info) record.Set("info", systemData.Info)
if err := h.app.Dao().SaveRecord(record); err != nil { if err := h.app.Dao().SaveRecord(record); err != nil {
@@ -320,14 +350,20 @@ func (h *Hub) updateSystemStatus(record *models.Record, status string) {
} }
} }
// Deletes the SSH connection (remote) or built-in agent reference
func (h *Hub) deleteSystemConnection(record *models.Record) { func (h *Hub) deleteSystemConnection(record *models.Record) {
if _, ok := h.systemConnections[record.Id]; ok { switch record.GetString("host") {
if h.systemConnections[record.Id] != nil { case "hubsys":
h.systemConnections[record.Id].Close() h.hubAgent = nil
default:
if _, ok := h.systemConnections[record.Id]; ok {
if h.systemConnections[record.Id] != nil {
h.systemConnections[record.Id].Close()
}
h.connectionLock.Lock()
defer h.connectionLock.Unlock()
delete(h.systemConnections, record.Id)
} }
h.connectionLock.Lock()
defer h.connectionLock.Unlock()
delete(h.systemConnections, record.Id)
} }
} }

View File

@@ -94,13 +94,15 @@ export function UserAuthForm({
setErrors({ passwordConfirm: msg }) setErrors({ passwordConfirm: msg })
return return
} }
// create admin user
await pb.admins.create({ await pb.admins.create({
email, email,
password, password,
passwordConfirm: password, passwordConfirm: password,
}) })
await pb.admins.authWithPassword(email, password) await pb.admins.authWithPassword(email, password)
await pb.collection('users').create({ // create regular user
const user = await pb.collection('users').create({
username, username,
email, email,
password, password,
@@ -108,6 +110,13 @@ export function UserAuthForm({
role: 'admin', role: 'admin',
verified: true, verified: true,
}) })
// create hubsys
await pb.collection('systems').create({
name: 'x',
port: 'x',
host: 'hubsys',
users: user.id,
})
await pb.collection('users').authWithPassword(email, password) await pb.collection('users').authWithPassword(email, password)
} else { } else {
await pb.collection('users').authWithPassword(email, password) await pb.collection('users').authWithPassword(email, password)

View File

@@ -197,7 +197,7 @@ export default function SystemDetail({ name }: { name: string }) {
uptime = `${Math.trunc(system.info?.u / 86400)} days` uptime = `${Math.trunc(system.info?.u / 86400)} days`
} }
return [ return [
{ value: system.host, Icon: GlobeIcon }, { value: system.host, Icon: GlobeIcon, hide: system.host === 'hubsys' },
{ {
value: system.info.h, value: system.info.h,
Icon: MonitorIcon, Icon: MonitorIcon,