mirror of
https://github.com/henrygd/beszel.git
synced 2026-03-22 13:36:16 +01:00
Compare commits
16 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
79e79079bc | ||
|
|
1811ebdee4 | ||
|
|
137f3f3e24 | ||
|
|
ed1d1e77c0 | ||
|
|
8c36dd1caa | ||
|
|
57bfe72486 | ||
|
|
75f66b0246 | ||
|
|
ce93d54aa7 | ||
|
|
39dbe0eac5 | ||
|
|
7282044f80 | ||
|
|
d77c37c0b0 | ||
|
|
e362cbbca5 | ||
|
|
118544926b | ||
|
|
d4bb0a0a30 | ||
|
|
fe5e35d1a9 | ||
|
|
60a6ae2caa |
2
.github/workflows/docker-images.yml
vendored
2
.github/workflows/docker-images.yml
vendored
@@ -3,7 +3,7 @@ name: Make docker images
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- "v*"
|
||||
- "xv*"
|
||||
|
||||
jobs:
|
||||
build:
|
||||
|
||||
15
.github/workflows/release.yml
vendored
15
.github/workflows/release.yml
vendored
@@ -3,7 +3,7 @@ name: Make release and binaries
|
||||
on:
|
||||
push:
|
||||
tags:
|
||||
- 'v*'
|
||||
- "v*"
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
@@ -29,7 +29,17 @@ jobs:
|
||||
- name: Set up Go
|
||||
uses: actions/setup-go@v5
|
||||
with:
|
||||
go-version: '^1.22.1'
|
||||
go-version: "^1.22.1"
|
||||
|
||||
- name: Set up .NET
|
||||
uses: actions/setup-dotnet@v4
|
||||
with:
|
||||
dotnet-version: "9.0.x"
|
||||
|
||||
- name: Build .NET LHM executable for Windows sensors
|
||||
run: |
|
||||
dotnet build -c Release ./beszel/internal/agent/lhm/beszel_lhm.csproj
|
||||
shell: bash
|
||||
|
||||
- name: GoReleaser beszel
|
||||
uses: goreleaser/goreleaser-action@v6
|
||||
@@ -40,3 +50,4 @@ jobs:
|
||||
args: release --clean
|
||||
env:
|
||||
GITHUB_TOKEN: ${{ secrets.TOKEN || secrets.GITHUB_TOKEN }}
|
||||
WINGET_TOKEN: ${{ secrets.WINGET_TOKEN }}
|
||||
|
||||
2
.gitignore
vendored
2
.gitignore
vendored
@@ -17,3 +17,5 @@ beszel/build
|
||||
beszel/site/src/locales/**/*.ts
|
||||
*.bak
|
||||
__debug_*
|
||||
beszel/internal/agent/lhm/obj
|
||||
beszel/internal/agent/lhm/bin
|
||||
|
||||
@@ -202,6 +202,7 @@ winget:
|
||||
owner: henrygd
|
||||
name: beszel-winget
|
||||
branch: henrygd.beszel-agent-{{ .Version }}
|
||||
token: "{{ .Env.WINGET_TOKEN }}"
|
||||
pull_request:
|
||||
enabled: true
|
||||
draft: false
|
||||
|
||||
@@ -4,6 +4,9 @@ ARCH ?= $(shell go env GOARCH)
|
||||
# Skip building the web UI if true
|
||||
SKIP_WEB ?= false
|
||||
|
||||
# Set executable extension based on target OS
|
||||
EXE_EXT := $(if $(filter windows,$(OS)),.exe,)
|
||||
|
||||
.PHONY: tidy build-agent build-hub build clean lint dev-server dev-agent dev-hub dev generate-locales
|
||||
.DEFAULT_GOAL := build
|
||||
|
||||
@@ -30,11 +33,25 @@ build-web-ui:
|
||||
npm run --prefix ./site build; \
|
||||
fi
|
||||
|
||||
build-agent: tidy
|
||||
GOOS=$(OS) GOARCH=$(ARCH) go build -o ./build/beszel-agent_$(OS)_$(ARCH) -ldflags "-w -s" beszel/cmd/agent
|
||||
# Conditional .NET build - only for Windows
|
||||
build-dotnet-conditional:
|
||||
@if [ "$(OS)" = "windows" ]; then \
|
||||
echo "Building .NET executable for Windows..."; \
|
||||
if command -v dotnet >/dev/null 2>&1; then \
|
||||
rm -rf ./internal/agent/lhm/bin; \
|
||||
dotnet build -c Release ./internal/agent/lhm/beszel_lhm.csproj; \
|
||||
else \
|
||||
echo "Error: dotnet not found. Install .NET SDK to build Windows agent."; \
|
||||
exit 1; \
|
||||
fi; \
|
||||
fi
|
||||
|
||||
# Update build-agent to include conditional .NET build
|
||||
build-agent: tidy build-dotnet-conditional
|
||||
GOOS=$(OS) GOARCH=$(ARCH) go build -o ./build/beszel-agent_$(OS)_$(ARCH)$(EXE_EXT) -ldflags "-w -s" beszel/cmd/agent
|
||||
|
||||
build-hub: tidy $(if $(filter false,$(SKIP_WEB)),build-web-ui)
|
||||
GOOS=$(OS) GOARCH=$(ARCH) go build -o ./build/beszel_$(OS)_$(ARCH) -ldflags "-w -s" beszel/cmd/hub
|
||||
GOOS=$(OS) GOARCH=$(ARCH) go build -o ./build/beszel_$(OS)_$(ARCH)$(EXE_EXT) -ldflags "-w -s" beszel/cmd/hub
|
||||
|
||||
build: build-agent build-hub
|
||||
|
||||
@@ -67,6 +84,15 @@ dev-agent:
|
||||
else \
|
||||
go run beszel/cmd/agent; \
|
||||
fi
|
||||
|
||||
build-dotnet:
|
||||
@if command -v dotnet >/dev/null 2>&1; then \
|
||||
rm -rf ./internal/agent/lhm/bin; \
|
||||
dotnet build -c Release ./internal/agent/lhm/beszel_lhm.csproj; \
|
||||
else \
|
||||
echo "dotnet not found"; \
|
||||
fi
|
||||
|
||||
|
||||
# KEY="..." make -j dev
|
||||
dev: dev-server dev-hub dev-agent
|
||||
|
||||
@@ -111,7 +111,7 @@ func main() {
|
||||
serverConfig.Addr = addr
|
||||
serverConfig.Network = agent.GetNetwork(addr)
|
||||
|
||||
agent, err := agent.NewAgent("")
|
||||
agent, err := agent.NewAgent()
|
||||
if err != nil {
|
||||
log.Fatal("Failed to create agent: ", err)
|
||||
}
|
||||
|
||||
@@ -40,13 +40,13 @@ type Agent struct {
|
||||
|
||||
// NewAgent creates a new agent with the given data directory for persisting data.
|
||||
// If the data directory is not set, it will attempt to find the optimal directory.
|
||||
func NewAgent(dataDir string) (agent *Agent, err error) {
|
||||
func NewAgent(dataDir ...string) (agent *Agent, err error) {
|
||||
agent = &Agent{
|
||||
fsStats: make(map[string]*system.FsStats),
|
||||
cache: NewSessionCache(69 * time.Second),
|
||||
}
|
||||
|
||||
agent.dataDir, err = getDataDir(dataDir)
|
||||
agent.dataDir, err = getDataDir(dataDir...)
|
||||
if err != nil {
|
||||
slog.Warn("Data directory not found")
|
||||
} else {
|
||||
|
||||
80
beszel/internal/agent/lhm/beszel_lhm.cs
Normal file
80
beszel/internal/agent/lhm/beszel_lhm.cs
Normal file
@@ -0,0 +1,80 @@
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using LibreHardwareMonitor.Hardware;
|
||||
|
||||
class Program
|
||||
{
|
||||
static void Main()
|
||||
{
|
||||
var computer = new Computer
|
||||
{
|
||||
IsCpuEnabled = true,
|
||||
IsGpuEnabled = true,
|
||||
IsMemoryEnabled = true,
|
||||
IsMotherboardEnabled = true,
|
||||
IsStorageEnabled = true,
|
||||
// IsPsuEnabled = true,
|
||||
// IsNetworkEnabled = true,
|
||||
};
|
||||
computer.Open();
|
||||
|
||||
var reader = Console.In;
|
||||
var writer = Console.Out;
|
||||
|
||||
string line;
|
||||
while ((line = reader.ReadLine()) != null)
|
||||
{
|
||||
if (line.Trim().Equals("getTemps", StringComparison.OrdinalIgnoreCase))
|
||||
{
|
||||
foreach (var hw in computer.Hardware)
|
||||
{
|
||||
// process main hardware sensors
|
||||
ProcessSensors(hw, writer);
|
||||
|
||||
// process subhardware sensors
|
||||
foreach (var subhardware in hw.SubHardware)
|
||||
{
|
||||
ProcessSensors(subhardware, writer);
|
||||
}
|
||||
}
|
||||
// send empty line to signal end of sensor data
|
||||
writer.WriteLine();
|
||||
writer.Flush();
|
||||
}
|
||||
}
|
||||
|
||||
computer.Close();
|
||||
}
|
||||
|
||||
static void ProcessSensors(IHardware hardware, System.IO.TextWriter writer)
|
||||
{
|
||||
var updated = false;
|
||||
foreach (var sensor in hardware.Sensors)
|
||||
{
|
||||
var validTemp = sensor.SensorType == SensorType.Temperature && sensor.Value.HasValue;
|
||||
if (!validTemp || sensor.Name.Contains("Distance"))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!updated)
|
||||
{
|
||||
hardware.Update();
|
||||
updated = true;
|
||||
}
|
||||
|
||||
var name = sensor.Name;
|
||||
// if sensor.Name starts with "Temperature" replace with hardware.Identifier but retain the rest of the name.
|
||||
// usually this is a number like Temperature 3
|
||||
if (sensor.Name.StartsWith("Temperature"))
|
||||
{
|
||||
name = hardware.Identifier.ToString().Replace("/", "_").TrimStart('_') + sensor.Name.Substring(11);
|
||||
}
|
||||
|
||||
// invariant culture assures the value is parsable as a float
|
||||
var value = sensor.Value.Value.ToString("0.##", CultureInfo.InvariantCulture);
|
||||
// write the name and value to the writer
|
||||
writer.WriteLine($"{name}|{value}");
|
||||
}
|
||||
}
|
||||
}
|
||||
11
beszel/internal/agent/lhm/beszel_lhm.csproj
Normal file
11
beszel/internal/agent/lhm/beszel_lhm.csproj
Normal file
@@ -0,0 +1,11 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
<PropertyGroup>
|
||||
<OutputType>Exe</OutputType>
|
||||
<TargetFramework>net48</TargetFramework>
|
||||
<Platforms>x64</Platforms>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="LibreHardwareMonitorLib" Version="0.9.4" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
@@ -84,10 +84,10 @@ func (a *Agent) updateTemperatures(systemStats *system.Stats) {
|
||||
// reset high temp
|
||||
a.systemInfo.DashboardTemp = 0
|
||||
|
||||
temps, err := a.getTempsWithPanicRecovery(sensors.TemperaturesWithContext)
|
||||
temps, err := a.getTempsWithPanicRecovery(getSensorTemps)
|
||||
if err != nil {
|
||||
// retry once on panic (gopsutil/issues/1832)
|
||||
temps, err = a.getTempsWithPanicRecovery(sensors.TemperaturesWithContext)
|
||||
temps, err = a.getTempsWithPanicRecovery(getSensorTemps)
|
||||
if err != nil {
|
||||
slog.Warn("Error updating temperatures", "err", err)
|
||||
if len(systemStats.Temperatures) > 0 {
|
||||
|
||||
9
beszel/internal/agent/sensors_default.go
Normal file
9
beszel/internal/agent/sensors_default.go
Normal file
@@ -0,0 +1,9 @@
|
||||
//go:build !windows
|
||||
|
||||
package agent
|
||||
|
||||
import (
|
||||
"github.com/shirou/gopsutil/v4/sensors"
|
||||
)
|
||||
|
||||
var getSensorTemps = sensors.TemperaturesWithContext
|
||||
281
beszel/internal/agent/sensors_windows.go
Normal file
281
beszel/internal/agent/sensors_windows.go
Normal file
@@ -0,0 +1,281 @@
|
||||
//go:build windows
|
||||
|
||||
//go:generate dotnet build -c Release lhm/beszel_lhm.csproj
|
||||
|
||||
package agent
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"context"
|
||||
"embed"
|
||||
"errors"
|
||||
"fmt"
|
||||
"io"
|
||||
"log/slog"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"strconv"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/shirou/gopsutil/v4/sensors"
|
||||
)
|
||||
|
||||
// Note: This is always called from Agent.gatherStats() which holds Agent.Lock(),
|
||||
// so no internal concurrency protection is needed.
|
||||
|
||||
// lhmProcess is a wrapper around the LHM .NET process.
|
||||
type lhmProcess struct {
|
||||
cmd *exec.Cmd
|
||||
stdin io.WriteCloser
|
||||
stdout io.ReadCloser
|
||||
scanner *bufio.Scanner
|
||||
isRunning bool
|
||||
stoppedNoSensors bool
|
||||
consecutiveNoSensors uint8
|
||||
execPath string
|
||||
tempDir string
|
||||
}
|
||||
|
||||
//go:embed all:lhm/bin/Release/net48
|
||||
var lhmFs embed.FS
|
||||
|
||||
var (
|
||||
beszelLhm *lhmProcess
|
||||
beszelLhmOnce sync.Once
|
||||
)
|
||||
|
||||
var errNoSensors = errors.New("no sensors found (try running as admin)")
|
||||
|
||||
// newlhmProcess copies the embedded LHM executable to a temporary directory and starts it.
|
||||
func newlhmProcess() (*lhmProcess, error) {
|
||||
destDir := filepath.Join(os.TempDir(), "beszel")
|
||||
execPath := filepath.Join(destDir, "beszel_lhm.exe")
|
||||
|
||||
if err := os.MkdirAll(destDir, 0755); err != nil {
|
||||
return nil, fmt.Errorf("failed to create temp directory: %w", err)
|
||||
}
|
||||
|
||||
// Only copy if executable doesn't exist
|
||||
if _, err := os.Stat(execPath); os.IsNotExist(err) {
|
||||
if err := copyEmbeddedDir(lhmFs, "lhm/bin/Release/net48", destDir); err != nil {
|
||||
return nil, fmt.Errorf("failed to copy embedded directory: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
lhm := &lhmProcess{
|
||||
execPath: execPath,
|
||||
tempDir: destDir,
|
||||
}
|
||||
|
||||
if err := lhm.startProcess(); err != nil {
|
||||
return nil, fmt.Errorf("failed to start process: %w", err)
|
||||
}
|
||||
|
||||
return lhm, nil
|
||||
}
|
||||
|
||||
// startProcess starts the external LHM process
|
||||
func (lhm *lhmProcess) startProcess() error {
|
||||
// Clean up any existing process
|
||||
lhm.cleanupProcess()
|
||||
|
||||
cmd := exec.Command(lhm.execPath)
|
||||
stdin, err := cmd.StdinPipe()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
stdout, err := cmd.StdoutPipe()
|
||||
if err != nil {
|
||||
stdin.Close()
|
||||
return err
|
||||
}
|
||||
|
||||
if err := cmd.Start(); err != nil {
|
||||
stdin.Close()
|
||||
stdout.Close()
|
||||
return err
|
||||
}
|
||||
|
||||
// Update process state
|
||||
lhm.cmd = cmd
|
||||
lhm.stdin = stdin
|
||||
lhm.stdout = stdout
|
||||
lhm.scanner = bufio.NewScanner(stdout)
|
||||
lhm.isRunning = true
|
||||
|
||||
// Give process a moment to initialize
|
||||
time.Sleep(100 * time.Millisecond)
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// cleanupProcess terminates the process and closes resources but preserves files
|
||||
func (lhm *lhmProcess) cleanupProcess() {
|
||||
lhm.isRunning = false
|
||||
|
||||
if lhm.cmd != nil && lhm.cmd.Process != nil {
|
||||
lhm.cmd.Process.Kill()
|
||||
lhm.cmd.Wait()
|
||||
}
|
||||
|
||||
if lhm.stdin != nil {
|
||||
lhm.stdin.Close()
|
||||
lhm.stdin = nil
|
||||
}
|
||||
if lhm.stdout != nil {
|
||||
lhm.stdout.Close()
|
||||
lhm.stdout = nil
|
||||
}
|
||||
|
||||
lhm.cmd = nil
|
||||
lhm.scanner = nil
|
||||
lhm.stoppedNoSensors = false
|
||||
lhm.consecutiveNoSensors = 0
|
||||
}
|
||||
|
||||
func (lhm *lhmProcess) getTemps(ctx context.Context) (temps []sensors.TemperatureStat, err error) {
|
||||
if lhm.stoppedNoSensors {
|
||||
// Fall back to gopsutil if we can't get sensors from LHM
|
||||
return sensors.TemperaturesWithContext(ctx)
|
||||
}
|
||||
|
||||
// Start process if it's not running
|
||||
if !lhm.isRunning || lhm.stdin == nil || lhm.scanner == nil {
|
||||
err := lhm.startProcess()
|
||||
if err != nil {
|
||||
return temps, err
|
||||
}
|
||||
}
|
||||
|
||||
// Send command to process
|
||||
_, err = fmt.Fprintln(lhm.stdin, "getTemps")
|
||||
if err != nil {
|
||||
lhm.isRunning = false
|
||||
return temps, fmt.Errorf("failed to send command: %w", err)
|
||||
}
|
||||
|
||||
// Read all sensor lines until we hit an empty line or EOF
|
||||
for lhm.scanner.Scan() {
|
||||
line := strings.TrimSpace(lhm.scanner.Text())
|
||||
if line == "" {
|
||||
break
|
||||
}
|
||||
|
||||
parts := strings.Split(line, "|")
|
||||
if len(parts) != 2 {
|
||||
slog.Debug("Invalid sensor format", "line", line)
|
||||
continue
|
||||
}
|
||||
|
||||
name := strings.TrimSpace(parts[0])
|
||||
valueStr := strings.TrimSpace(parts[1])
|
||||
|
||||
value, err := strconv.ParseFloat(valueStr, 64)
|
||||
if err != nil {
|
||||
slog.Debug("Failed to parse sensor", "err", err, "line", line)
|
||||
continue
|
||||
}
|
||||
|
||||
if name == "" || value <= 0 || value > 150 {
|
||||
slog.Debug("Invalid sensor", "name", name, "val", value, "line", line)
|
||||
continue
|
||||
}
|
||||
|
||||
temps = append(temps, sensors.TemperatureStat{
|
||||
SensorKey: name,
|
||||
Temperature: value,
|
||||
})
|
||||
}
|
||||
|
||||
if err := lhm.scanner.Err(); err != nil {
|
||||
lhm.isRunning = false
|
||||
return temps, err
|
||||
}
|
||||
|
||||
// Handle no sensors case
|
||||
if len(temps) == 0 {
|
||||
lhm.consecutiveNoSensors++
|
||||
if lhm.consecutiveNoSensors >= 3 {
|
||||
lhm.stoppedNoSensors = true
|
||||
slog.Warn(errNoSensors.Error())
|
||||
lhm.cleanup()
|
||||
}
|
||||
return sensors.TemperaturesWithContext(ctx)
|
||||
}
|
||||
|
||||
lhm.consecutiveNoSensors = 0
|
||||
|
||||
return temps, nil
|
||||
}
|
||||
|
||||
// getSensorTemps attempts to pull sensor temperatures from the embedded LHM process.
|
||||
// NB: LibreHardwareMonitorLib requires admin privileges to access all available sensors.
|
||||
func getSensorTemps(ctx context.Context) (temps []sensors.TemperatureStat, err error) {
|
||||
defer func() {
|
||||
if err != nil {
|
||||
slog.Debug("Error reading sensors", "err", err)
|
||||
}
|
||||
}()
|
||||
|
||||
// Initialize process once
|
||||
beszelLhmOnce.Do(func() {
|
||||
beszelLhm, err = newlhmProcess()
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return temps, fmt.Errorf("failed to initialize lhm: %w", err)
|
||||
}
|
||||
|
||||
if beszelLhm == nil {
|
||||
return temps, fmt.Errorf("lhm not available")
|
||||
}
|
||||
|
||||
return beszelLhm.getTemps(ctx)
|
||||
}
|
||||
|
||||
// cleanup terminates the process and closes resources
|
||||
func (lhm *lhmProcess) cleanup() {
|
||||
lhm.cleanupProcess()
|
||||
if lhm.tempDir != "" {
|
||||
os.RemoveAll(lhm.tempDir)
|
||||
}
|
||||
}
|
||||
|
||||
// copyEmbeddedDir copies the embedded directory to the destination path
|
||||
func copyEmbeddedDir(fs embed.FS, srcPath, destPath string) error {
|
||||
entries, err := fs.ReadDir(srcPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if err := os.MkdirAll(destPath, 0755); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
for _, entry := range entries {
|
||||
srcEntryPath := path.Join(srcPath, entry.Name())
|
||||
destEntryPath := filepath.Join(destPath, entry.Name())
|
||||
|
||||
if entry.IsDir() {
|
||||
if err := copyEmbeddedDir(fs, srcEntryPath, destEntryPath); err != nil {
|
||||
return err
|
||||
}
|
||||
continue
|
||||
}
|
||||
|
||||
data, err := fs.ReadFile(srcEntryPath)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := os.WriteFile(destEntryPath, data, 0755); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
4
beszel/site/package-lock.json
generated
4
beszel/site/package-lock.json
generated
@@ -1,12 +1,12 @@
|
||||
{
|
||||
"name": "beszel",
|
||||
"version": "0.12.1",
|
||||
"version": "0.12.2",
|
||||
"lockfileVersion": 3,
|
||||
"requires": true,
|
||||
"packages": {
|
||||
"": {
|
||||
"name": "beszel",
|
||||
"version": "0.12.1",
|
||||
"version": "0.12.2",
|
||||
"dependencies": {
|
||||
"@henrygd/queue": "^1.0.7",
|
||||
"@henrygd/semaphore": "^0.0.2",
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "beszel",
|
||||
"private": true,
|
||||
"version": "0.12.1",
|
||||
"version": "0.12.2",
|
||||
"type": "module",
|
||||
"scripts": {
|
||||
"dev": "vite",
|
||||
|
||||
@@ -87,5 +87,5 @@ export default function AreaChartDefault({
|
||||
</ChartContainer>
|
||||
</div>
|
||||
)
|
||||
}, [chartData.systemStats.length, yAxisWidth, maxToggled])
|
||||
}, [chartData.systemStats.at(-1), yAxisWidth, maxToggled])
|
||||
}
|
||||
|
||||
@@ -174,17 +174,11 @@ export default function SystemsTable() {
|
||||
invertSorting: false,
|
||||
Icon: ServerIcon,
|
||||
cell: (info) => (
|
||||
<span className="flex gap-0.5 items-center text-base md:ps-1 md:pe-5">
|
||||
<span className="flex gap-2 items-center md:ps-1 md:pe-5">
|
||||
<IndicatorDot system={info.row.original} />
|
||||
<Button
|
||||
data-nolink
|
||||
variant={"ghost"}
|
||||
className="text-primary/90 h-7 px-1.5 gap-1.5"
|
||||
onClick={() => copyToClipboard(info.getValue() as string)}
|
||||
>
|
||||
<span className="font-medium text-sm">
|
||||
{info.getValue() as string}
|
||||
<CopyIcon className="size-2.5" />
|
||||
</Button>
|
||||
</span>
|
||||
</span>
|
||||
),
|
||||
header: sortableHeader,
|
||||
@@ -721,6 +715,10 @@ const ActionsButton = memo(({ system }: { system: SystemRecord }) => {
|
||||
</>
|
||||
)}
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem onClick={() => copyToClipboard(name)}>
|
||||
<CopyIcon className="me-2.5 size-4" />
|
||||
<Trans>Copy name</Trans>
|
||||
</DropdownMenuItem>
|
||||
<DropdownMenuItem onClick={() => copyToClipboard(host)}>
|
||||
<CopyIcon className="me-2.5 size-4" />
|
||||
<Trans>Copy host</Trans>
|
||||
|
||||
@@ -296,6 +296,10 @@ msgstr "نسخ المضيف"
|
||||
msgid "Copy Linux command"
|
||||
msgstr "نسخ أمر لينكس"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx
|
||||
msgid "Copy name"
|
||||
msgstr "نسخ الاسم"
|
||||
|
||||
#: src/components/copy-to-clipboard.tsx
|
||||
msgid "Copy text"
|
||||
msgstr "نسخ النص"
|
||||
|
||||
@@ -296,6 +296,10 @@ msgstr "Копирай хоста"
|
||||
msgid "Copy Linux command"
|
||||
msgstr "Копирай linux командата"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx
|
||||
msgid "Copy name"
|
||||
msgstr "Копирай име"
|
||||
|
||||
#: src/components/copy-to-clipboard.tsx
|
||||
msgid "Copy text"
|
||||
msgstr "Копирай текста"
|
||||
|
||||
@@ -296,6 +296,10 @@ msgstr "Kopírovat hostitele"
|
||||
msgid "Copy Linux command"
|
||||
msgstr "Kopírovat příkaz Linux"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx
|
||||
msgid "Copy name"
|
||||
msgstr "Kopírovat název"
|
||||
|
||||
#: src/components/copy-to-clipboard.tsx
|
||||
msgid "Copy text"
|
||||
msgstr "Kopírovat text"
|
||||
|
||||
@@ -296,6 +296,10 @@ msgstr "Kopier host"
|
||||
msgid "Copy Linux command"
|
||||
msgstr "Kopier Linux kommando"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx
|
||||
msgid "Copy name"
|
||||
msgstr "Kopier navn"
|
||||
|
||||
#: src/components/copy-to-clipboard.tsx
|
||||
msgid "Copy text"
|
||||
msgstr "Kopier tekst"
|
||||
|
||||
@@ -296,6 +296,10 @@ msgstr "Host kopieren"
|
||||
msgid "Copy Linux command"
|
||||
msgstr "Linux-Befehl kopieren"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx
|
||||
msgid "Copy name"
|
||||
msgstr "Name kopieren"
|
||||
|
||||
#: src/components/copy-to-clipboard.tsx
|
||||
msgid "Copy text"
|
||||
msgstr "Text kopieren"
|
||||
|
||||
@@ -291,6 +291,10 @@ msgstr "Copy host"
|
||||
msgid "Copy Linux command"
|
||||
msgstr "Copy Linux command"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx
|
||||
msgid "Copy name"
|
||||
msgstr "Copy name"
|
||||
|
||||
#: src/components/copy-to-clipboard.tsx
|
||||
msgid "Copy text"
|
||||
msgstr "Copy text"
|
||||
|
||||
@@ -296,6 +296,10 @@ msgstr "Copiar host"
|
||||
msgid "Copy Linux command"
|
||||
msgstr "Copiar comando de Linux"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx
|
||||
msgid "Copy name"
|
||||
msgstr "Copiar nombre"
|
||||
|
||||
#: src/components/copy-to-clipboard.tsx
|
||||
msgid "Copy text"
|
||||
msgstr "Copiar texto"
|
||||
|
||||
@@ -296,6 +296,10 @@ msgstr "کپی میزبان"
|
||||
msgid "Copy Linux command"
|
||||
msgstr "کپی دستور لینوکس"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx
|
||||
msgid "Copy name"
|
||||
msgstr "کپی نام"
|
||||
|
||||
#: src/components/copy-to-clipboard.tsx
|
||||
msgid "Copy text"
|
||||
msgstr "کپی متن"
|
||||
|
||||
@@ -296,6 +296,10 @@ msgstr "Copier l'hôte"
|
||||
msgid "Copy Linux command"
|
||||
msgstr "Copier la commande Linux"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx
|
||||
msgid "Copy name"
|
||||
msgstr "Copier le nom"
|
||||
|
||||
#: src/components/copy-to-clipboard.tsx
|
||||
msgid "Copy text"
|
||||
msgstr "Copier le texte"
|
||||
|
||||
@@ -296,6 +296,10 @@ msgstr "Kopiraj hosta"
|
||||
msgid "Copy Linux command"
|
||||
msgstr "Kopiraj Linux komandu"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx
|
||||
msgid "Copy name"
|
||||
msgstr "Kopiraj naziv"
|
||||
|
||||
#: src/components/copy-to-clipboard.tsx
|
||||
msgid "Copy text"
|
||||
msgstr "Kopiraj tekst"
|
||||
|
||||
@@ -296,6 +296,10 @@ msgstr "Hoszt másolása"
|
||||
msgid "Copy Linux command"
|
||||
msgstr "Linux parancs másolása"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx
|
||||
msgid "Copy name"
|
||||
msgstr "Név másolása"
|
||||
|
||||
#: src/components/copy-to-clipboard.tsx
|
||||
msgid "Copy text"
|
||||
msgstr "Szöveg másolása"
|
||||
|
||||
@@ -296,6 +296,10 @@ msgstr "Afrita host"
|
||||
msgid "Copy Linux command"
|
||||
msgstr "Afrita Linux aðgerð"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx
|
||||
msgid "Copy name"
|
||||
msgstr "Afrita nafn"
|
||||
|
||||
#: src/components/copy-to-clipboard.tsx
|
||||
msgid "Copy text"
|
||||
msgstr "Afrita texta"
|
||||
|
||||
@@ -296,6 +296,10 @@ msgstr "Copia host"
|
||||
msgid "Copy Linux command"
|
||||
msgstr "Copia comando Linux"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx
|
||||
msgid "Copy name"
|
||||
msgstr "Copia nome"
|
||||
|
||||
#: src/components/copy-to-clipboard.tsx
|
||||
msgid "Copy text"
|
||||
msgstr "Copia testo"
|
||||
|
||||
@@ -296,6 +296,10 @@ msgstr "ホストをコピー"
|
||||
msgid "Copy Linux command"
|
||||
msgstr "Linuxコマンドをコピー"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx
|
||||
msgid "Copy name"
|
||||
msgstr "名前をコピー"
|
||||
|
||||
#: src/components/copy-to-clipboard.tsx
|
||||
msgid "Copy text"
|
||||
msgstr "テキストをコピー"
|
||||
|
||||
@@ -296,6 +296,10 @@ msgstr "호스트 복사"
|
||||
msgid "Copy Linux command"
|
||||
msgstr "리눅스 명령어 복사"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx
|
||||
msgid "Copy name"
|
||||
msgstr "이름 복사"
|
||||
|
||||
#: src/components/copy-to-clipboard.tsx
|
||||
msgid "Copy text"
|
||||
msgstr "텍스트 복사"
|
||||
|
||||
@@ -296,6 +296,10 @@ msgstr "Kopieer host"
|
||||
msgid "Copy Linux command"
|
||||
msgstr "Kopieer Linux-opdracht"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx
|
||||
msgid "Copy name"
|
||||
msgstr "Kopieer naam"
|
||||
|
||||
#: src/components/copy-to-clipboard.tsx
|
||||
msgid "Copy text"
|
||||
msgstr "Kopieer tekst"
|
||||
|
||||
@@ -296,6 +296,10 @@ msgstr "Kopier vert"
|
||||
msgid "Copy Linux command"
|
||||
msgstr "Kopier Linux-kommando"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx
|
||||
msgid "Copy name"
|
||||
msgstr "Kopier navn"
|
||||
|
||||
#: src/components/copy-to-clipboard.tsx
|
||||
msgid "Copy text"
|
||||
msgstr "Kopier tekst"
|
||||
|
||||
@@ -296,6 +296,10 @@ msgstr "Kopiuj host"
|
||||
msgid "Copy Linux command"
|
||||
msgstr "Kopiuj polecenie Linux"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx
|
||||
msgid "Copy name"
|
||||
msgstr "Kopiuj nazwę"
|
||||
|
||||
#: src/components/copy-to-clipboard.tsx
|
||||
msgid "Copy text"
|
||||
msgstr "Kopiuj tekst"
|
||||
|
||||
@@ -296,6 +296,10 @@ msgstr "Copiar host"
|
||||
msgid "Copy Linux command"
|
||||
msgstr "Copiar comando Linux"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx
|
||||
msgid "Copy name"
|
||||
msgstr "Copiar nome"
|
||||
|
||||
#: src/components/copy-to-clipboard.tsx
|
||||
msgid "Copy text"
|
||||
msgstr "Copiar texto"
|
||||
|
||||
@@ -296,6 +296,10 @@ msgstr "Копировать хост"
|
||||
msgid "Copy Linux command"
|
||||
msgstr "Копировать команду Linux"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx
|
||||
msgid "Copy name"
|
||||
msgstr "Копировать имя"
|
||||
|
||||
#: src/components/copy-to-clipboard.tsx
|
||||
msgid "Copy text"
|
||||
msgstr "Копировать текст"
|
||||
|
||||
@@ -296,6 +296,10 @@ msgstr "Kopiraj gostitelja"
|
||||
msgid "Copy Linux command"
|
||||
msgstr "Kopiraj Linux ukaz"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx
|
||||
msgid "Copy name"
|
||||
msgstr "Kopiraj ime"
|
||||
|
||||
#: src/components/copy-to-clipboard.tsx
|
||||
msgid "Copy text"
|
||||
msgstr "Kopiraj besedilo"
|
||||
|
||||
@@ -8,7 +8,7 @@ msgstr ""
|
||||
"Language: sv\n"
|
||||
"Project-Id-Version: beszel\n"
|
||||
"Report-Msgid-Bugs-To: \n"
|
||||
"PO-Revision-Date: 2025-07-25 22:44\n"
|
||||
"PO-Revision-Date: 2025-08-01 23:21\n"
|
||||
"Last-Translator: \n"
|
||||
"Language-Team: Swedish\n"
|
||||
"Plural-Forms: nplurals=2; plural=(n != 1);\n"
|
||||
@@ -27,7 +27,7 @@ msgstr "{0, plural, one {# dag} other {# dagar}}"
|
||||
#. placeholder {1}: table.getFilteredRowModel().rows.length
|
||||
#: src/components/routes/settings/alerts-history-data-table.tsx
|
||||
msgid "{0} of {1} row(s) selected."
|
||||
msgstr ""
|
||||
msgstr "{0} av {1} rad(er) valda."
|
||||
|
||||
#: src/components/routes/system.tsx
|
||||
msgid "{hours, plural, one {# hour} other {# hours}}"
|
||||
@@ -40,7 +40,7 @@ msgstr "1 timme"
|
||||
#. Load average
|
||||
#: src/components/charts/load-average-chart.tsx
|
||||
msgid "1 min"
|
||||
msgstr ""
|
||||
msgstr "1 min"
|
||||
|
||||
#: src/lib/utils.ts
|
||||
msgid "1 week"
|
||||
@@ -53,7 +53,7 @@ msgstr "12 timmar"
|
||||
#. Load average
|
||||
#: src/components/charts/load-average-chart.tsx
|
||||
msgid "15 min"
|
||||
msgstr ""
|
||||
msgstr "15 min"
|
||||
|
||||
#: src/lib/utils.ts
|
||||
msgid "24 hours"
|
||||
@@ -66,7 +66,7 @@ msgstr "30 dagar"
|
||||
#. Load average
|
||||
#: src/components/charts/load-average-chart.tsx
|
||||
msgid "5 min"
|
||||
msgstr ""
|
||||
msgstr "5 min"
|
||||
|
||||
#. Table column
|
||||
#: src/components/systems-table/systems-table.tsx
|
||||
@@ -77,7 +77,7 @@ msgstr "Åtgärder"
|
||||
#: src/components/alerts-history-columns.tsx
|
||||
#: src/components/routes/settings/alerts-history-data-table.tsx
|
||||
msgid "Active"
|
||||
msgstr ""
|
||||
msgstr "Aktiv"
|
||||
|
||||
#: src/components/routes/home.tsx
|
||||
msgid "Active Alerts"
|
||||
@@ -134,7 +134,7 @@ msgstr "Är du säker på att du vill ta bort {name}?"
|
||||
|
||||
#: src/components/routes/settings/alerts-history-data-table.tsx
|
||||
msgid "Are you sure?"
|
||||
msgstr ""
|
||||
msgstr "Är du säker?"
|
||||
|
||||
#: src/components/copy-to-clipboard.tsx
|
||||
msgid "Automatic copy requires a secure context."
|
||||
@@ -191,12 +191,12 @@ msgstr "Binär"
|
||||
#: src/components/routes/settings/general.tsx
|
||||
#: src/components/routes/settings/general.tsx
|
||||
msgid "Bits (Kbps, Mbps, Gbps)"
|
||||
msgstr ""
|
||||
msgstr "Bits (Kbps, Mbps, Gbps)"
|
||||
|
||||
#: src/components/routes/settings/general.tsx
|
||||
#: src/components/routes/settings/general.tsx
|
||||
msgid "Bytes (KB/s, MB/s, GB/s)"
|
||||
msgstr ""
|
||||
msgstr "Bytes (KB/s, MB/s, GB/S)"
|
||||
|
||||
#: src/components/charts/mem-chart.tsx
|
||||
msgid "Cache / Buffers"
|
||||
@@ -213,11 +213,11 @@ msgstr "Varning - potentiell dataförlust"
|
||||
|
||||
#: src/components/routes/settings/general.tsx
|
||||
msgid "Celsius (°C)"
|
||||
msgstr ""
|
||||
msgstr "Celsius (°C)"
|
||||
|
||||
#: src/components/routes/settings/general.tsx
|
||||
msgid "Change display units for metrics."
|
||||
msgstr ""
|
||||
msgstr "Ändra enheter för mätvärden."
|
||||
|
||||
#: src/components/routes/settings/general.tsx
|
||||
msgid "Change general application options."
|
||||
@@ -259,7 +259,7 @@ msgstr "Bekräfta lösenord"
|
||||
|
||||
#: src/components/routes/home.tsx
|
||||
msgid "Connection is down"
|
||||
msgstr ""
|
||||
msgstr "Ej ansluten"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx
|
||||
#: src/components/routes/settings/alerts-history-data-table.tsx
|
||||
@@ -296,6 +296,10 @@ msgstr "Kopiera värd"
|
||||
msgid "Copy Linux command"
|
||||
msgstr "Kopiera Linux-kommando"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx
|
||||
msgid "Copy name"
|
||||
msgstr "Kopiera namn"
|
||||
|
||||
#: src/components/copy-to-clipboard.tsx
|
||||
msgid "Copy text"
|
||||
msgstr "Kopiera text"
|
||||
@@ -310,7 +314,7 @@ msgstr ""
|
||||
|
||||
#: src/components/routes/settings/tokens-fingerprints.tsx
|
||||
msgid "Copy YAML"
|
||||
msgstr ""
|
||||
msgstr "Kopiera YAML"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx
|
||||
msgid "CPU"
|
||||
@@ -329,7 +333,7 @@ msgstr "Skapa konto"
|
||||
#. Context: date created
|
||||
#: src/components/alerts-history-columns.tsx
|
||||
msgid "Created"
|
||||
msgstr ""
|
||||
msgstr "Skapad"
|
||||
|
||||
#. Dark theme
|
||||
#: src/components/mode-toggle.tsx
|
||||
|
||||
@@ -296,6 +296,10 @@ msgstr "Ana bilgisayarı kopyala"
|
||||
msgid "Copy Linux command"
|
||||
msgstr "Linux komutunu kopyala"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx
|
||||
msgid "Copy name"
|
||||
msgstr "Adı kopyala"
|
||||
|
||||
#: src/components/copy-to-clipboard.tsx
|
||||
msgid "Copy text"
|
||||
msgstr "Metni kopyala"
|
||||
|
||||
@@ -296,6 +296,10 @@ msgstr "Копіювати хост"
|
||||
msgid "Copy Linux command"
|
||||
msgstr "Копіювати команду Linux"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx
|
||||
msgid "Copy name"
|
||||
msgstr "Копіювати імʼя"
|
||||
|
||||
#: src/components/copy-to-clipboard.tsx
|
||||
msgid "Copy text"
|
||||
msgstr "Копіювати текст"
|
||||
|
||||
@@ -296,6 +296,10 @@ msgstr "Sao chép máy chủ"
|
||||
msgid "Copy Linux command"
|
||||
msgstr "Sao chép lệnh Linux"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx
|
||||
msgid "Copy name"
|
||||
msgstr "Sao chép tên"
|
||||
|
||||
#: src/components/copy-to-clipboard.tsx
|
||||
msgid "Copy text"
|
||||
msgstr "Sao chép văn bản"
|
||||
|
||||
@@ -296,6 +296,10 @@ msgstr "复制主机名"
|
||||
msgid "Copy Linux command"
|
||||
msgstr "复制 Linux 安装命令"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx
|
||||
msgid "Copy name"
|
||||
msgstr "复制名称"
|
||||
|
||||
#: src/components/copy-to-clipboard.tsx
|
||||
msgid "Copy text"
|
||||
msgstr "复制文本"
|
||||
|
||||
@@ -296,6 +296,10 @@ msgstr "複製主機"
|
||||
msgid "Copy Linux command"
|
||||
msgstr "複製 Linux 指令"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx
|
||||
msgid "Copy name"
|
||||
msgstr "複製名稱"
|
||||
|
||||
#: src/components/copy-to-clipboard.tsx
|
||||
msgid "Copy text"
|
||||
msgstr "複製文本"
|
||||
|
||||
@@ -296,6 +296,10 @@ msgstr "複製主機"
|
||||
msgid "Copy Linux command"
|
||||
msgstr "複製 Linux 指令"
|
||||
|
||||
#: src/components/systems-table/systems-table.tsx
|
||||
msgid "Copy name"
|
||||
msgstr "複製名稱"
|
||||
|
||||
#: src/components/copy-to-clipboard.tsx
|
||||
msgid "Copy text"
|
||||
msgstr "複製文字"
|
||||
|
||||
@@ -3,7 +3,7 @@ package beszel
|
||||
import "github.com/blang/semver"
|
||||
|
||||
const (
|
||||
Version = "0.12.1"
|
||||
Version = "0.12.2"
|
||||
AppName = "beszel"
|
||||
)
|
||||
|
||||
|
||||
@@ -16,7 +16,7 @@ It has a friendly web interface, simple configuration, and is ready to use out o
|
||||
- **Lightweight**: Smaller and less resource-intensive than leading solutions.
|
||||
- **Simple**: Easy setup with little manual configuration required.
|
||||
- **Docker stats**: Tracks CPU, memory, and network usage history for each container.
|
||||
- **Alerts**: Configurable alerts for CPU, memory, disk, bandwidth, temperature, and status.
|
||||
- **Alerts**: Configurable alerts for CPU, memory, disk, bandwidth, temperature, load average, and status.
|
||||
- **Multi-user**: Users manage their own systems. Admins can share systems across users.
|
||||
- **OAuth / OIDC**: Supports many OAuth2 providers. Password auth can be disabled.
|
||||
- **Automatic backups**: Save to and restore from disk or S3-compatible storage.
|
||||
|
||||
@@ -31,10 +31,12 @@ if ! getent passwd "$SERVICE_USER" >/dev/null; then
|
||||
--gecos "System user for $SERVICE"
|
||||
fi
|
||||
|
||||
# Enable docker
|
||||
if ! getent group docker | grep -q "$SERVICE_USER"; then
|
||||
echo "Adding $SERVICE_USER to docker group"
|
||||
usermod -aG docker "$SERVICE_USER"
|
||||
# Enable docker (only if docker group exists)
|
||||
if getent group docker >/dev/null 2>&1; then
|
||||
if ! getent group docker | grep -q "$SERVICE_USER"; then
|
||||
echo "Adding $SERVICE_USER to docker group"
|
||||
usermod -aG docker "$SERVICE_USER"
|
||||
fi
|
||||
fi
|
||||
|
||||
# Create config file if it doesn't already exist
|
||||
|
||||
373
supplemental/licenses/LibreHardwareMonitor/LICENSE
Normal file
373
supplemental/licenses/LibreHardwareMonitor/LICENSE
Normal file
@@ -0,0 +1,373 @@
|
||||
Mozilla Public License Version 2.0
|
||||
==================================
|
||||
|
||||
1. Definitions
|
||||
--------------
|
||||
|
||||
1.1. "Contributor"
|
||||
means each individual or legal entity that creates, contributes to
|
||||
the creation of, or owns Covered Software.
|
||||
|
||||
1.2. "Contributor Version"
|
||||
means the combination of the Contributions of others (if any) used
|
||||
by a Contributor and that particular Contributor's Contribution.
|
||||
|
||||
1.3. "Contribution"
|
||||
means Covered Software of a particular Contributor.
|
||||
|
||||
1.4. "Covered Software"
|
||||
means Source Code Form to which the initial Contributor has attached
|
||||
the notice in Exhibit A, the Executable Form of such Source Code
|
||||
Form, and Modifications of such Source Code Form, in each case
|
||||
including portions thereof.
|
||||
|
||||
1.5. "Incompatible With Secondary Licenses"
|
||||
means
|
||||
|
||||
(a) that the initial Contributor has attached the notice described
|
||||
in Exhibit B to the Covered Software; or
|
||||
|
||||
(b) that the Covered Software was made available under the terms of
|
||||
version 1.1 or earlier of the License, but not also under the
|
||||
terms of a Secondary License.
|
||||
|
||||
1.6. "Executable Form"
|
||||
means any form of the work other than Source Code Form.
|
||||
|
||||
1.7. "Larger Work"
|
||||
means a work that combines Covered Software with other material, in
|
||||
a separate file or files, that is not Covered Software.
|
||||
|
||||
1.8. "License"
|
||||
means this document.
|
||||
|
||||
1.9. "Licensable"
|
||||
means having the right to grant, to the maximum extent possible,
|
||||
whether at the time of the initial grant or subsequently, any and
|
||||
all of the rights conveyed by this License.
|
||||
|
||||
1.10. "Modifications"
|
||||
means any of the following:
|
||||
|
||||
(a) any file in Source Code Form that results from an addition to,
|
||||
deletion from, or modification of the contents of Covered
|
||||
Software; or
|
||||
|
||||
(b) any new file in Source Code Form that contains any Covered
|
||||
Software.
|
||||
|
||||
1.11. "Patent Claims" of a Contributor
|
||||
means any patent claim(s), including without limitation, method,
|
||||
process, and apparatus claims, in any patent Licensable by such
|
||||
Contributor that would be infringed, but for the grant of the
|
||||
License, by the making, using, selling, offering for sale, having
|
||||
made, import, or transfer of either its Contributions or its
|
||||
Contributor Version.
|
||||
|
||||
1.12. "Secondary License"
|
||||
means either the GNU General Public License, Version 2.0, the GNU
|
||||
Lesser General Public License, Version 2.1, the GNU Affero General
|
||||
Public License, Version 3.0, or any later versions of those
|
||||
licenses.
|
||||
|
||||
1.13. "Source Code Form"
|
||||
means the form of the work preferred for making modifications.
|
||||
|
||||
1.14. "You" (or "Your")
|
||||
means an individual or a legal entity exercising rights under this
|
||||
License. For legal entities, "You" includes any entity that
|
||||
controls, is controlled by, or is under common control with You. For
|
||||
purposes of this definition, "control" means (a) the power, direct
|
||||
or indirect, to cause the direction or management of such entity,
|
||||
whether by contract or otherwise, or (b) ownership of more than
|
||||
fifty percent (50%) of the outstanding shares or beneficial
|
||||
ownership of such entity.
|
||||
|
||||
2. License Grants and Conditions
|
||||
--------------------------------
|
||||
|
||||
2.1. Grants
|
||||
|
||||
Each Contributor hereby grants You a world-wide, royalty-free,
|
||||
non-exclusive license:
|
||||
|
||||
(a) under intellectual property rights (other than patent or trademark)
|
||||
Licensable by such Contributor to use, reproduce, make available,
|
||||
modify, display, perform, distribute, and otherwise exploit its
|
||||
Contributions, either on an unmodified basis, with Modifications, or
|
||||
as part of a Larger Work; and
|
||||
|
||||
(b) under Patent Claims of such Contributor to make, use, sell, offer
|
||||
for sale, have made, import, and otherwise transfer either its
|
||||
Contributions or its Contributor Version.
|
||||
|
||||
2.2. Effective Date
|
||||
|
||||
The licenses granted in Section 2.1 with respect to any Contribution
|
||||
become effective for each Contribution on the date the Contributor first
|
||||
distributes such Contribution.
|
||||
|
||||
2.3. Limitations on Grant Scope
|
||||
|
||||
The licenses granted in this Section 2 are the only rights granted under
|
||||
this License. No additional rights or licenses will be implied from the
|
||||
distribution or licensing of Covered Software under this License.
|
||||
Notwithstanding Section 2.1(b) above, no patent license is granted by a
|
||||
Contributor:
|
||||
|
||||
(a) for any code that a Contributor has removed from Covered Software;
|
||||
or
|
||||
|
||||
(b) for infringements caused by: (i) Your and any other third party's
|
||||
modifications of Covered Software, or (ii) the combination of its
|
||||
Contributions with other software (except as part of its Contributor
|
||||
Version); or
|
||||
|
||||
(c) under Patent Claims infringed by Covered Software in the absence of
|
||||
its Contributions.
|
||||
|
||||
This License does not grant any rights in the trademarks, service marks,
|
||||
or logos of any Contributor (except as may be necessary to comply with
|
||||
the notice requirements in Section 3.4).
|
||||
|
||||
2.4. Subsequent Licenses
|
||||
|
||||
No Contributor makes additional grants as a result of Your choice to
|
||||
distribute the Covered Software under a subsequent version of this
|
||||
License (see Section 10.2) or under the terms of a Secondary License (if
|
||||
permitted under the terms of Section 3.3).
|
||||
|
||||
2.5. Representation
|
||||
|
||||
Each Contributor represents that the Contributor believes its
|
||||
Contributions are its original creation(s) or it has sufficient rights
|
||||
to grant the rights to its Contributions conveyed by this License.
|
||||
|
||||
2.6. Fair Use
|
||||
|
||||
This License is not intended to limit any rights You have under
|
||||
applicable copyright doctrines of fair use, fair dealing, or other
|
||||
equivalents.
|
||||
|
||||
2.7. Conditions
|
||||
|
||||
Sections 3.1, 3.2, 3.3, and 3.4 are conditions of the licenses granted
|
||||
in Section 2.1.
|
||||
|
||||
3. Responsibilities
|
||||
-------------------
|
||||
|
||||
3.1. Distribution of Source Form
|
||||
|
||||
All distribution of Covered Software in Source Code Form, including any
|
||||
Modifications that You create or to which You contribute, must be under
|
||||
the terms of this License. You must inform recipients that the Source
|
||||
Code Form of the Covered Software is governed by the terms of this
|
||||
License, and how they can obtain a copy of this License. You may not
|
||||
attempt to alter or restrict the recipients' rights in the Source Code
|
||||
Form.
|
||||
|
||||
3.2. Distribution of Executable Form
|
||||
|
||||
If You distribute Covered Software in Executable Form then:
|
||||
|
||||
(a) such Covered Software must also be made available in Source Code
|
||||
Form, as described in Section 3.1, and You must inform recipients of
|
||||
the Executable Form how they can obtain a copy of such Source Code
|
||||
Form by reasonable means in a timely manner, at a charge no more
|
||||
than the cost of distribution to the recipient; and
|
||||
|
||||
(b) You may distribute such Executable Form under the terms of this
|
||||
License, or sublicense it under different terms, provided that the
|
||||
license for the Executable Form does not attempt to limit or alter
|
||||
the recipients' rights in the Source Code Form under this License.
|
||||
|
||||
3.3. Distribution of a Larger Work
|
||||
|
||||
You may create and distribute a Larger Work under terms of Your choice,
|
||||
provided that You also comply with the requirements of this License for
|
||||
the Covered Software. If the Larger Work is a combination of Covered
|
||||
Software with a work governed by one or more Secondary Licenses, and the
|
||||
Covered Software is not Incompatible With Secondary Licenses, this
|
||||
License permits You to additionally distribute such Covered Software
|
||||
under the terms of such Secondary License(s), so that the recipient of
|
||||
the Larger Work may, at their option, further distribute the Covered
|
||||
Software under the terms of either this License or such Secondary
|
||||
License(s).
|
||||
|
||||
3.4. Notices
|
||||
|
||||
You may not remove or alter the substance of any license notices
|
||||
(including copyright notices, patent notices, disclaimers of warranty,
|
||||
or limitations of liability) contained within the Source Code Form of
|
||||
the Covered Software, except that You may alter any license notices to
|
||||
the extent required to remedy known factual inaccuracies.
|
||||
|
||||
3.5. Application of Additional Terms
|
||||
|
||||
You may choose to offer, and to charge a fee for, warranty, support,
|
||||
indemnity or liability obligations to one or more recipients of Covered
|
||||
Software. However, You may do so only on Your own behalf, and not on
|
||||
behalf of any Contributor. You must make it absolutely clear that any
|
||||
such warranty, support, indemnity, or liability obligation is offered by
|
||||
You alone, and You hereby agree to indemnify every Contributor for any
|
||||
liability incurred by such Contributor as a result of warranty, support,
|
||||
indemnity or liability terms You offer. You may include additional
|
||||
disclaimers of warranty and limitations of liability specific to any
|
||||
jurisdiction.
|
||||
|
||||
4. Inability to Comply Due to Statute or Regulation
|
||||
---------------------------------------------------
|
||||
|
||||
If it is impossible for You to comply with any of the terms of this
|
||||
License with respect to some or all of the Covered Software due to
|
||||
statute, judicial order, or regulation then You must: (a) comply with
|
||||
the terms of this License to the maximum extent possible; and (b)
|
||||
describe the limitations and the code they affect. Such description must
|
||||
be placed in a text file included with all distributions of the Covered
|
||||
Software under this License. Except to the extent prohibited by statute
|
||||
or regulation, such description must be sufficiently detailed for a
|
||||
recipient of ordinary skill to be able to understand it.
|
||||
|
||||
5. Termination
|
||||
--------------
|
||||
|
||||
5.1. The rights granted under this License will terminate automatically
|
||||
if You fail to comply with any of its terms. However, if You become
|
||||
compliant, then the rights granted under this License from a particular
|
||||
Contributor are reinstated (a) provisionally, unless and until such
|
||||
Contributor explicitly and finally terminates Your grants, and (b) on an
|
||||
ongoing basis, if such Contributor fails to notify You of the
|
||||
non-compliance by some reasonable means prior to 60 days after You have
|
||||
come back into compliance. Moreover, Your grants from a particular
|
||||
Contributor are reinstated on an ongoing basis if such Contributor
|
||||
notifies You of the non-compliance by some reasonable means, this is the
|
||||
first time You have received notice of non-compliance with this License
|
||||
from such Contributor, and You become compliant prior to 30 days after
|
||||
Your receipt of the notice.
|
||||
|
||||
5.2. If You initiate litigation against any entity by asserting a patent
|
||||
infringement claim (excluding declaratory judgment actions,
|
||||
counter-claims, and cross-claims) alleging that a Contributor Version
|
||||
directly or indirectly infringes any patent, then the rights granted to
|
||||
You by any and all Contributors for the Covered Software under Section
|
||||
2.1 of this License shall terminate.
|
||||
|
||||
5.3. In the event of termination under Sections 5.1 or 5.2 above, all
|
||||
end user license agreements (excluding distributors and resellers) which
|
||||
have been validly granted by You or Your distributors under this License
|
||||
prior to termination shall survive termination.
|
||||
|
||||
************************************************************************
|
||||
* *
|
||||
* 6. Disclaimer of Warranty *
|
||||
* ------------------------- *
|
||||
* *
|
||||
* Covered Software is provided under this License on an "as is" *
|
||||
* basis, without warranty of any kind, either expressed, implied, or *
|
||||
* statutory, including, without limitation, warranties that the *
|
||||
* Covered Software is free of defects, merchantable, fit for a *
|
||||
* particular purpose or non-infringing. The entire risk as to the *
|
||||
* quality and performance of the Covered Software is with You. *
|
||||
* Should any Covered Software prove defective in any respect, You *
|
||||
* (not any Contributor) assume the cost of any necessary servicing, *
|
||||
* repair, or correction. This disclaimer of warranty constitutes an *
|
||||
* essential part of this License. No use of any Covered Software is *
|
||||
* authorized under this License except under this disclaimer. *
|
||||
* *
|
||||
************************************************************************
|
||||
|
||||
************************************************************************
|
||||
* *
|
||||
* 7. Limitation of Liability *
|
||||
* -------------------------- *
|
||||
* *
|
||||
* Under no circumstances and under no legal theory, whether tort *
|
||||
* (including negligence), contract, or otherwise, shall any *
|
||||
* Contributor, or anyone who distributes Covered Software as *
|
||||
* permitted above, be liable to You for any direct, indirect, *
|
||||
* special, incidental, or consequential damages of any character *
|
||||
* including, without limitation, damages for lost profits, loss of *
|
||||
* goodwill, work stoppage, computer failure or malfunction, or any *
|
||||
* and all other commercial damages or losses, even if such party *
|
||||
* shall have been informed of the possibility of such damages. This *
|
||||
* limitation of liability shall not apply to liability for death or *
|
||||
* personal injury resulting from such party's negligence to the *
|
||||
* extent applicable law prohibits such limitation. Some *
|
||||
* jurisdictions do not allow the exclusion or limitation of *
|
||||
* incidental or consequential damages, so this exclusion and *
|
||||
* limitation may not apply to You. *
|
||||
* *
|
||||
************************************************************************
|
||||
|
||||
8. Litigation
|
||||
-------------
|
||||
|
||||
Any litigation relating to this License may be brought only in the
|
||||
courts of a jurisdiction where the defendant maintains its principal
|
||||
place of business and such litigation shall be governed by laws of that
|
||||
jurisdiction, without reference to its conflict-of-law provisions.
|
||||
Nothing in this Section shall prevent a party's ability to bring
|
||||
cross-claims or counter-claims.
|
||||
|
||||
9. Miscellaneous
|
||||
----------------
|
||||
|
||||
This License represents the complete agreement concerning the subject
|
||||
matter hereof. If any provision of this License is held to be
|
||||
unenforceable, such provision shall be reformed only to the extent
|
||||
necessary to make it enforceable. Any law or regulation which provides
|
||||
that the language of a contract shall be construed against the drafter
|
||||
shall not be used to construe this License against a Contributor.
|
||||
|
||||
10. Versions of the License
|
||||
---------------------------
|
||||
|
||||
10.1. New Versions
|
||||
|
||||
Mozilla Foundation is the license steward. Except as provided in Section
|
||||
10.3, no one other than the license steward has the right to modify or
|
||||
publish new versions of this License. Each version will be given a
|
||||
distinguishing version number.
|
||||
|
||||
10.2. Effect of New Versions
|
||||
|
||||
You may distribute the Covered Software under the terms of the version
|
||||
of the License under which You originally received the Covered Software,
|
||||
or under the terms of any subsequent version published by the license
|
||||
steward.
|
||||
|
||||
10.3. Modified Versions
|
||||
|
||||
If you create software not governed by this License, and you want to
|
||||
create a new license for such software, you may create and use a
|
||||
modified version of this License if you rename the license and remove
|
||||
any references to the name of the license steward (except to note that
|
||||
such modified license differs from this License).
|
||||
|
||||
10.4. Distributing Source Code Form that is Incompatible With Secondary
|
||||
Licenses
|
||||
|
||||
If You choose to distribute Source Code Form that is Incompatible With
|
||||
Secondary Licenses under the terms of this version of the License, the
|
||||
notice described in Exhibit B of this License must be attached.
|
||||
|
||||
Exhibit A - Source Code Form License Notice
|
||||
-------------------------------------------
|
||||
|
||||
This Source Code Form is subject to the terms of the Mozilla Public
|
||||
License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
file, You can obtain one at http://mozilla.org/MPL/2.0/.
|
||||
|
||||
If it is not possible or desirable to put the notice in a particular
|
||||
file, then You may include the notice in a location (such as a LICENSE
|
||||
file in a relevant directory) where a recipient would be likely to look
|
||||
for such a notice.
|
||||
|
||||
You may add additional accurate notices of copyright ownership.
|
||||
|
||||
Exhibit B - "Incompatible With Secondary Licenses" Notice
|
||||
---------------------------------------------------------
|
||||
|
||||
This Source Code Form is "Incompatible With Secondary Licenses", as
|
||||
defined by the Mozilla Public License, v. 2.0.
|
||||
@@ -5,7 +5,7 @@ is_alpine() {
|
||||
}
|
||||
|
||||
is_openwrt() {
|
||||
cat /etc/os-release | grep -q "OpenWrt"
|
||||
grep -qi "OpenWrt" /etc/os-release
|
||||
}
|
||||
|
||||
# If SELinux is enabled, set the context of the binary
|
||||
@@ -227,8 +227,8 @@ if [ "$UNINSTALL" = true ]; then
|
||||
rm -f /var/log/beszel-agent.log /var/log/beszel-agent.err
|
||||
elif is_openwrt; then
|
||||
echo "Stopping and disabling the agent service..."
|
||||
service beszel-agent stop
|
||||
service beszel-agent disable
|
||||
/etc/init.d/beszel-agent stop
|
||||
/etc/init.d/beszel-agent disable
|
||||
|
||||
echo "Removing the OpenWRT service files..."
|
||||
rm -f /etc/init.d/beszel-agent
|
||||
@@ -288,13 +288,13 @@ package_installed() {
|
||||
}
|
||||
|
||||
# Check for package manager and install necessary packages if not installed
|
||||
if is_alpine; then
|
||||
if ! package_installed tar || ! package_installed curl || ! package_installed coreutils; then
|
||||
if package_installed apk; then
|
||||
if ! package_installed tar || ! package_installed curl || ! package_installed sha256sum; then
|
||||
apk update
|
||||
apk add tar curl coreutils shadow
|
||||
fi
|
||||
elif is_openwrt; then
|
||||
if ! package_installed tar || ! package_installed curl || ! package_installed coreutils; then
|
||||
elif package_installed opkg; then
|
||||
if ! package_installed tar || ! package_installed curl || ! package_installed sha256sum; then
|
||||
opkg update
|
||||
opkg install tar curl coreutils
|
||||
fi
|
||||
@@ -335,11 +335,10 @@ else
|
||||
fi
|
||||
|
||||
# Create a dedicated user for the service if it doesn't exist
|
||||
echo "Creating a dedicated user for the Beszel Agent service..."
|
||||
if is_alpine; then
|
||||
if ! id -u beszel >/dev/null 2>&1; then
|
||||
echo "Creating a dedicated group for the Beszel Agent service..."
|
||||
addgroup beszel
|
||||
echo "Creating a dedicated user for the Beszel Agent service..."
|
||||
adduser -S -D -H -s /sbin/nologin -G beszel beszel
|
||||
fi
|
||||
# Add the user to the docker group to allow access to the Docker socket if group docker exists
|
||||
@@ -347,10 +346,37 @@ if is_alpine; then
|
||||
echo "Adding beszel to docker group"
|
||||
usermod -aG docker beszel
|
||||
fi
|
||||
|
||||
elif is_openwrt; then
|
||||
# Create beszel group first if it doesn't exist (check /etc/group directly)
|
||||
if ! grep -q "^beszel:" /etc/group >/dev/null 2>&1; then
|
||||
echo "beszel:x:999:" >> /etc/group
|
||||
fi
|
||||
|
||||
# Create beszel user if it doesn't exist (double-check to prevent duplicates)
|
||||
if ! id -u beszel >/dev/null 2>&1 && ! grep -q "^beszel:" /etc/passwd >/dev/null 2>&1; then
|
||||
echo "beszel:x:999:999::/nonexistent:/bin/false" >> /etc/passwd
|
||||
fi
|
||||
|
||||
# Add the user to the docker group if docker group exists and user is not already in it
|
||||
if grep -q "^docker:" /etc/group >/dev/null 2>&1; then
|
||||
echo "Adding beszel to docker group"
|
||||
# Check if beszel is already in docker group
|
||||
if ! grep "^docker:" /etc/group | grep -q "beszel"; then
|
||||
# Add beszel to docker group by modifying /etc/group
|
||||
# Handle both cases: group with existing members and group without members
|
||||
if grep "^docker:" /etc/group | grep -q ":.*:.*$"; then
|
||||
# Group has existing members, append with comma
|
||||
sed -i 's/^docker:\([^:]*:[^:]*:\)\(.*\)$/docker:\1\2,beszel/' /etc/group
|
||||
else
|
||||
# Group has no members, just append
|
||||
sed -i 's/^docker:\([^:]*:[^:]*:\)$/docker:\1beszel/' /etc/group
|
||||
fi
|
||||
fi
|
||||
fi
|
||||
|
||||
else
|
||||
if ! id -u beszel >/dev/null 2>&1; then
|
||||
echo "Creating a dedicated user for the Beszel Agent service..."
|
||||
useradd --system --home-dir /nonexistent --shell /bin/false beszel
|
||||
fi
|
||||
# Add the user to the docker group to allow access to the Docker socket if group docker exists
|
||||
@@ -427,6 +453,11 @@ set_selinux_context
|
||||
# Cleanup
|
||||
rm -rf "$TEMP_DIR"
|
||||
|
||||
# Make sure /etc/machine-id exists for persistent fingerprint
|
||||
if [ ! -f /etc/machine-id ]; then
|
||||
cat /proc/sys/kernel/random/uuid | tr -d '-' > /etc/machine-id
|
||||
fi
|
||||
|
||||
# Check for NVIDIA GPUs and grant device permissions for systemd service
|
||||
detect_nvidia_devices() {
|
||||
local devices=""
|
||||
@@ -546,10 +577,7 @@ start_service() {
|
||||
procd_set_param command /opt/beszel-agent/beszel-agent
|
||||
procd_set_param user beszel
|
||||
procd_set_param pidfile /var/run/beszel-agent.pid
|
||||
procd_set_param env PORT="$PORT"
|
||||
procd_set_param env KEY="$KEY"
|
||||
procd_set_param env TOKEN="$TOKEN"
|
||||
procd_set_param env HUB_URL="$HUB_URL"
|
||||
procd_set_param env PORT="$PORT" KEY="$KEY" TOKEN="$TOKEN" HUB_URL="$HUB_URL"
|
||||
procd_set_param stdout 1
|
||||
procd_set_param stderr 1
|
||||
procd_close_instance
|
||||
@@ -573,10 +601,10 @@ EOF
|
||||
|
||||
# Enable the service
|
||||
chmod +x /etc/init.d/beszel-agent
|
||||
service beszel-agent enable
|
||||
/etc/init.d/beszel-agent enable
|
||||
|
||||
# Start the service
|
||||
service beszel-agent restart
|
||||
/etc/init.d/beszel-agent restart
|
||||
|
||||
# Auto-update service for OpenWRT using a crontab job
|
||||
if [ "$AUTO_UPDATE_FLAG" = "true" ]; then
|
||||
@@ -604,9 +632,9 @@ EOF
|
||||
esac
|
||||
|
||||
# Check service status
|
||||
if ! service beszel-agent running >/dev/null 2>&1; then
|
||||
if ! /etc/init.d/beszel-agent running >/dev/null 2>&1; then
|
||||
echo "Error: The Beszel Agent service is not running."
|
||||
service beszel-agent status
|
||||
/etc/init.d/beszel-agent status
|
||||
exit 1
|
||||
fi
|
||||
|
||||
|
||||
@@ -217,13 +217,6 @@ function Update-ServicePath {
|
||||
throw "NSSM is not available in PATH and no valid NSSMPath was provided"
|
||||
}
|
||||
|
||||
# Stop the service
|
||||
Write-Host "Stopping beszel-agent service..."
|
||||
& $nssmCommand stop beszel-agent
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
Write-Host "Warning: Failed to stop service, continuing anyway..." -ForegroundColor Yellow
|
||||
}
|
||||
|
||||
# Update the application path
|
||||
& $nssmCommand set beszel-agent Application $NewAgentPath
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
@@ -233,7 +226,25 @@ function Update-ServicePath {
|
||||
Write-Host "Service path updated to: $NewAgentPath"
|
||||
|
||||
# Start the service
|
||||
Start-BeszelAgentService -NSSMPath $nssmCommand
|
||||
}
|
||||
|
||||
# Function to start and monitor the service
|
||||
function Start-BeszelAgentService {
|
||||
param (
|
||||
[string]$NSSMPath = ""
|
||||
)
|
||||
|
||||
Write-Host "Starting beszel-agent service..."
|
||||
|
||||
# Determine the NSSM executable to use
|
||||
$nssmCommand = "nssm"
|
||||
if ($NSSMPath -and (Test-Path $NSSMPath)) {
|
||||
$nssmCommand = $NSSMPath
|
||||
} elseif (-not (Test-CommandExists "nssm")) {
|
||||
throw "NSSM is not available in PATH and no valid NSSMPath was provided"
|
||||
}
|
||||
|
||||
& $nssmCommand start beszel-agent
|
||||
$startResult = $LASTEXITCODE
|
||||
|
||||
@@ -255,7 +266,7 @@ function Update-ServicePath {
|
||||
|
||||
if ($serviceStatus -eq "SERVICE_RUNNING") {
|
||||
$serviceStarted = $true
|
||||
Write-Host "Success! The beszel-agent service is now running with the updated path." -ForegroundColor Green
|
||||
Write-Host "Success! The beszel-agent service is now running." -ForegroundColor Green
|
||||
}
|
||||
elseif ($serviceStatus -like "*PENDING*") {
|
||||
Write-Host "Service is still starting (status: $serviceStatus)... waiting" -ForegroundColor Yellow
|
||||
@@ -273,7 +284,7 @@ function Update-ServicePath {
|
||||
}
|
||||
} else {
|
||||
# NSSM start command was successful
|
||||
Write-Host "Success! The beszel-agent service is running with the updated path." -ForegroundColor Green
|
||||
Write-Host "Success! The beszel-agent service is running properly." -ForegroundColor Green
|
||||
}
|
||||
}
|
||||
|
||||
@@ -287,7 +298,6 @@ $isAdmin = Test-Admin
|
||||
try {
|
||||
Write-Host "Beszel Agent Upgrade Script" -ForegroundColor Cyan
|
||||
Write-Host "===========================" -ForegroundColor Cyan
|
||||
Write-Host ""
|
||||
|
||||
# First: Check if service exists (doesn't require admin)
|
||||
$existingService = Get-Service -Name "beszel-agent" -ErrorAction SilentlyContinue
|
||||
@@ -312,6 +322,13 @@ try {
|
||||
Write-Host "Retrieving current service configuration..."
|
||||
$currentConfig = Get-ServiceConfiguration -NSSMPath $nssmPath
|
||||
|
||||
# Stop the service before upgrade
|
||||
Write-Host "Stopping beszel-agent service..."
|
||||
& $nssmPath stop beszel-agent
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
Write-Host "Warning: Failed to stop service, continuing anyway..." -ForegroundColor Yellow
|
||||
}
|
||||
|
||||
# Upgrade the agent (doesn't require admin)
|
||||
Write-Host "Upgrading beszel-agent..."
|
||||
$newAgentPath = $null
|
||||
@@ -340,7 +357,8 @@ try {
|
||||
|
||||
# Check if the path has changed
|
||||
if ($currentConfig.CurrentPath -eq $newAgentPath) {
|
||||
Write-Host "Agent path has not changed. Service update not needed." -ForegroundColor Green
|
||||
Write-Host "Agent path has not changed. Restarting service..." -ForegroundColor Green
|
||||
Start-BeszelAgentService -NSSMPath $nssmPath
|
||||
Write-Host "Upgrade completed successfully!" -ForegroundColor Green
|
||||
exit 0
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user