完善远程执行、主题安装与部署流程
This commit is contained in:
1 parent
dae8f665db
commit
2f7cccd94d
53 files changed
+2348
-624
No files matched your search
+1
-1
@@ -1,7 +1,7 @@
|
||||
[package]
|
||||
name = "nodeflare-agent"
|
||||
version = "0.0.1"
|
||||
edition = "2021"
|
||||
edition = "2024"
|
||||
license = "MIT"
|
||||
description = "Independent Rust telemetry agent for NodeFlare"
|
||||
repository = "https://github.com/imengying/NodeFlare"
|
||||
|
||||
+36
-5
@@ -1,11 +1,16 @@
|
||||
#!/bin/sh
|
||||
set -eu
|
||||
|
||||
SERVICE_NAME="nodeflare"
|
||||
SERVICE_NAME="nodeflare-agent"
|
||||
LEGACY_SERVICE_NAME="nodeflare"
|
||||
INSTALL_DIR="/opt/nodeflare"
|
||||
AGENT_FILE="$INSTALL_DIR/agent"
|
||||
STATE_DIR="/var/lib/nodeflare-agent"
|
||||
PENDING_FILE="$STATE_DIR/pending.jsonl"
|
||||
SERVICE_FILE="/etc/systemd/system/$SERVICE_NAME.service"
|
||||
OPENRC_FILE="/etc/init.d/$SERVICE_NAME"
|
||||
LEGACY_SERVICE_FILE="/etc/systemd/system/$LEGACY_SERVICE_NAME.service"
|
||||
LEGACY_OPENRC_FILE="/etc/init.d/$LEGACY_SERVICE_NAME"
|
||||
|
||||
usage() {
|
||||
cat <<'EOF'
|
||||
@@ -50,6 +55,21 @@ detect_init_system() {
|
||||
fi
|
||||
}
|
||||
|
||||
remove_legacy_agent_service() {
|
||||
init_system="$1"
|
||||
if [ "$init_system" = "systemd" ] && [ -f "$LEGACY_SERVICE_FILE" ] \
|
||||
&& grep -Fq "$AGENT_FILE" "$LEGACY_SERVICE_FILE"; then
|
||||
systemctl disable --now "$LEGACY_SERVICE_NAME" 2>/dev/null || true
|
||||
rm -f "$LEGACY_SERVICE_FILE"
|
||||
systemctl daemon-reload
|
||||
elif [ "$init_system" = "openrc" ] && [ -f "$LEGACY_OPENRC_FILE" ] \
|
||||
&& grep -Fq "$AGENT_FILE" "$LEGACY_OPENRC_FILE"; then
|
||||
rc-service "$LEGACY_SERVICE_NAME" stop 2>/dev/null || true
|
||||
rc-update del "$LEGACY_SERVICE_NAME" default 2>/dev/null || true
|
||||
rm -f "$LEGACY_OPENRC_FILE"
|
||||
fi
|
||||
}
|
||||
|
||||
ensure_curl() {
|
||||
command -v curl >/dev/null 2>&1 && return
|
||||
log "未找到 curl,正在通过系统包管理器安装"
|
||||
@@ -134,7 +154,12 @@ install_agent() {
|
||||
init_system=$(detect_init_system)
|
||||
[ "$init_system" != "unknown" ] || fail "未检测到正在运行的 systemd 或 OpenRC"
|
||||
|
||||
mkdir -p "$INSTALL_DIR"
|
||||
mkdir -p "$INSTALL_DIR" "$STATE_DIR"
|
||||
chmod 755 "$INSTALL_DIR"
|
||||
chmod 750 "$STATE_DIR"
|
||||
if [ -f "$INSTALL_DIR/pending.jsonl" ] && [ ! -e "$PENDING_FILE" ]; then
|
||||
mv "$INSTALL_DIR/pending.jsonl" "$PENDING_FILE"
|
||||
fi
|
||||
temporary="$INSTALL_DIR/.agent.$$.download"
|
||||
trap 'rm -f "$temporary"' EXIT HUP INT TERM
|
||||
artifact="agent-linux-$arch"
|
||||
@@ -197,13 +222,14 @@ install_agent() {
|
||||
systemd) systemctl stop "$SERVICE_NAME" 2>/dev/null || true ;;
|
||||
openrc) rc-service "$SERVICE_NAME" stop 2>/dev/null || true ;;
|
||||
esac
|
||||
remove_legacy_agent_service "$init_system"
|
||||
mv "$temporary" "$AGENT_FILE"
|
||||
trap - EXIT HUP INT TERM
|
||||
log "正在配置并启动 $init_system 服务"
|
||||
if [ "$init_system" = "systemd" ]; then
|
||||
printf '%s\n' \
|
||||
'[Unit]' \
|
||||
'Description=nodeflare' \
|
||||
'Description=NodeFlare Agent' \
|
||||
'After=network-online.target' \
|
||||
'Wants=network-online.target' \
|
||||
'' \
|
||||
@@ -216,7 +242,8 @@ install_agent() {
|
||||
'PrivateTmp=true' \
|
||||
'ProtectHome=true' \
|
||||
'ProtectSystem=strict' \
|
||||
"ReadWritePaths=$INSTALL_DIR" \
|
||||
"Environment=NODEFLARE_STATE_DIR=$STATE_DIR" \
|
||||
"ReadWritePaths=$INSTALL_DIR $STATE_DIR" \
|
||||
'' \
|
||||
'[Install]' \
|
||||
'WantedBy=multi-user.target' > "$SERVICE_FILE"
|
||||
@@ -234,6 +261,7 @@ install_agent() {
|
||||
"command=\"$AGENT_FILE\"" \
|
||||
"command_args=\"-e $endpoint -t $token -i $interval\"" \
|
||||
"command_user=\"root\"" \
|
||||
"export NODEFLARE_STATE_DIR=\"$STATE_DIR\"" \
|
||||
"supervisor=\"supervise-daemon\"" \
|
||||
"respawn_delay=10" \
|
||||
'depend() { need net; }' > "$OPENRC_FILE"
|
||||
@@ -272,6 +300,7 @@ uninstall_agent() {
|
||||
[ "$(id -u)" -eq 0 ] || fail "请使用 root 权限执行卸载"
|
||||
log "正在停止并移除 NodeFlare Agent"
|
||||
init_system=$(detect_init_system)
|
||||
remove_legacy_agent_service "$init_system"
|
||||
case "$init_system" in
|
||||
systemd) systemctl disable --now "$SERVICE_NAME" 2>/dev/null || true ;;
|
||||
openrc)
|
||||
@@ -282,7 +311,9 @@ uninstall_agent() {
|
||||
rm -f "$SERVICE_FILE"
|
||||
rm -f "$OPENRC_FILE"
|
||||
[ "$init_system" != "systemd" ] || systemctl daemon-reload 2>/dev/null || true
|
||||
rm -rf "$INSTALL_DIR"
|
||||
rm -f "$AGENT_FILE" "$INSTALL_DIR/pending.jsonl"
|
||||
rm -rf "$STATE_DIR"
|
||||
rmdir "$INSTALL_DIR" 2>/dev/null || true
|
||||
echo "NodeFlare Agent 已卸载"
|
||||
}
|
||||
|
||||
|
||||
@@ -1,10 +1,15 @@
|
||||
#!/bin/sh
|
||||
set -eu
|
||||
|
||||
SERVICE_NAME="nodeflare"
|
||||
SERVICE_NAME="nodeflare-agent"
|
||||
RC_NAME="nodeflare_agent"
|
||||
LEGACY_SERVICE_NAME="nodeflare"
|
||||
INSTALL_DIR="/usr/local/libexec/nodeflare"
|
||||
AGENT_FILE="$INSTALL_DIR/agent"
|
||||
STATE_DIR="/var/db/nodeflare-agent"
|
||||
PENDING_FILE="$STATE_DIR/pending.jsonl"
|
||||
SERVICE_FILE="/usr/local/etc/rc.d/$SERVICE_NAME"
|
||||
LEGACY_SERVICE_FILE="/usr/local/etc/rc.d/$LEGACY_SERVICE_NAME"
|
||||
|
||||
log() {
|
||||
printf '[NodeFlare] %s\n' "$1"
|
||||
@@ -57,13 +62,23 @@ download_file() {
|
||||
fi
|
||||
}
|
||||
|
||||
remove_legacy_agent_service() {
|
||||
if [ -f "$LEGACY_SERVICE_FILE" ] && grep -Fq "$AGENT_FILE" "$LEGACY_SERVICE_FILE"; then
|
||||
service "$LEGACY_SERVICE_NAME" stop 2>/dev/null || true
|
||||
sysrc -x "${LEGACY_SERVICE_NAME}_enable" >/dev/null 2>&1 || true
|
||||
rm -f "$LEGACY_SERVICE_FILE"
|
||||
fi
|
||||
}
|
||||
|
||||
if [ "${1:-}" = "--uninstall" ]; then
|
||||
[ "$#" -eq 1 ] || fail "--uninstall 不接受其它参数"
|
||||
[ "$(id -u)" -eq 0 ] || fail "请使用 root 权限执行卸载"
|
||||
log "正在停止并移除 NodeFlare Agent"
|
||||
remove_legacy_agent_service
|
||||
service "$SERVICE_NAME" stop 2>/dev/null || true
|
||||
sysrc -x "${SERVICE_NAME}_enable" >/dev/null 2>&1 || true
|
||||
rm -f "$SERVICE_FILE" "$AGENT_FILE"
|
||||
sysrc -x "${RC_NAME}_enable" >/dev/null 2>&1 || true
|
||||
rm -f "$SERVICE_FILE" "$AGENT_FILE" "$INSTALL_DIR/pending.jsonl"
|
||||
rm -rf "$STATE_DIR"
|
||||
rmdir "$INSTALL_DIR" 2>/dev/null || true
|
||||
echo "NodeFlare Agent 已卸载"
|
||||
exit 0
|
||||
@@ -136,7 +151,12 @@ if [ -n "$mirror" ]; then
|
||||
case "$mirror" in *@*) fail "下载加速前缀不能包含用户信息" ;; esac
|
||||
fi
|
||||
|
||||
mkdir -p "$INSTALL_DIR"
|
||||
mkdir -p "$INSTALL_DIR" "$STATE_DIR"
|
||||
chmod 755 "$INSTALL_DIR"
|
||||
chmod 750 "$STATE_DIR"
|
||||
if [ -f "$INSTALL_DIR/pending.jsonl" ] && [ ! -e "$PENDING_FILE" ]; then
|
||||
mv "$INSTALL_DIR/pending.jsonl" "$PENDING_FILE"
|
||||
fi
|
||||
temporary="$INSTALL_DIR/.agent.$$.download"
|
||||
trap 'rm -f "$temporary"' EXIT HUP INT TERM
|
||||
artifact="agent-freebsd-x64"
|
||||
@@ -182,29 +202,32 @@ installed_version=${installed_version##* }
|
||||
[ "$installed_version" = "${release_tag#v}" ] || fail "Release $release_tag 与 Agent 版本 $installed_version 不一致"
|
||||
|
||||
log "正在配置并启动 FreeBSD rc.d 服务"
|
||||
remove_legacy_agent_service
|
||||
service "$SERVICE_NAME" stop 2>/dev/null || true
|
||||
mv "$temporary" "$AGENT_FILE"
|
||||
trap - EXIT HUP INT TERM
|
||||
cat > "$SERVICE_FILE" <<EOF
|
||||
#!/bin/sh
|
||||
# PROVIDE: nodeflare
|
||||
# PROVIDE: nodeflare_agent
|
||||
# REQUIRE: NETWORKING
|
||||
# KEYWORD: shutdown
|
||||
|
||||
. /etc/rc.subr
|
||||
|
||||
name="$SERVICE_NAME"
|
||||
rcvar="${SERVICE_NAME}_enable"
|
||||
export NODEFLARE_STATE_DIR="$STATE_DIR"
|
||||
|
||||
name="$RC_NAME"
|
||||
rcvar="${RC_NAME}_enable"
|
||||
pidfile="/var/run/\${name}.pid"
|
||||
command="/usr/sbin/daemon"
|
||||
command_args="-P \${pidfile} -r -R 10 -S -T \${name} $AGENT_FILE -e $endpoint -t $token -i $interval"
|
||||
|
||||
load_rc_config "\${name}"
|
||||
: \${nodeflare_enable:="NO"}
|
||||
: \${nodeflare_agent_enable:="NO"}
|
||||
run_rc_command "\$1"
|
||||
EOF
|
||||
chmod 700 "$SERVICE_FILE"
|
||||
sysrc "${SERVICE_NAME}_enable=YES" >/dev/null
|
||||
sysrc "${RC_NAME}_enable=YES" >/dev/null
|
||||
service "$SERVICE_NAME" start
|
||||
service "$SERVICE_NAME" status >/dev/null || {
|
||||
service "$SERVICE_NAME" status >&2 || true
|
||||
|
||||
+17
-3
@@ -1,10 +1,14 @@
|
||||
#!/bin/sh
|
||||
set -eu
|
||||
|
||||
LABEL="com.nodeflare.agent"
|
||||
LABEL="nodeflare-agent"
|
||||
LEGACY_LABEL="com.nodeflare.agent"
|
||||
INSTALL_DIR="/usr/local/libexec/nodeflare"
|
||||
AGENT_FILE="$INSTALL_DIR/agent"
|
||||
STATE_DIR="/Library/Application Support/NodeFlare"
|
||||
PENDING_FILE="$STATE_DIR/pending.jsonl"
|
||||
PLIST_FILE="/Library/LaunchDaemons/$LABEL.plist"
|
||||
LEGACY_PLIST_FILE="/Library/LaunchDaemons/$LEGACY_LABEL.plist"
|
||||
|
||||
log() {
|
||||
printf '[NodeFlare] %s\n' "$1"
|
||||
@@ -39,7 +43,9 @@ if [ "${1:-}" = "--uninstall" ]; then
|
||||
[ "$(id -u)" -eq 0 ] || fail "请使用 root 权限执行卸载"
|
||||
log "正在停止并移除 NodeFlare Agent"
|
||||
launchctl bootout system "$PLIST_FILE" 2>/dev/null || true
|
||||
rm -f "$PLIST_FILE" "$AGENT_FILE"
|
||||
launchctl bootout system "$LEGACY_PLIST_FILE" 2>/dev/null || true
|
||||
rm -f "$PLIST_FILE" "$LEGACY_PLIST_FILE" "$AGENT_FILE" "$INSTALL_DIR/pending.jsonl"
|
||||
rm -rf "$STATE_DIR"
|
||||
rmdir "$INSTALL_DIR" 2>/dev/null || true
|
||||
echo "NodeFlare Agent 已卸载"
|
||||
exit 0
|
||||
@@ -105,7 +111,12 @@ if [ -n "$mirror" ]; then
|
||||
case "$mirror" in *@*) fail "下载加速前缀不能包含用户信息" ;; esac
|
||||
fi
|
||||
|
||||
mkdir -p "$INSTALL_DIR"
|
||||
mkdir -p "$INSTALL_DIR" "$STATE_DIR"
|
||||
chmod 755 "$INSTALL_DIR"
|
||||
chmod 750 "$STATE_DIR"
|
||||
if [ -f "$INSTALL_DIR/pending.jsonl" ] && [ ! -e "$PENDING_FILE" ]; then
|
||||
mv "$INSTALL_DIR/pending.jsonl" "$PENDING_FILE"
|
||||
fi
|
||||
temporary="$INSTALL_DIR/.agent.$$.download"
|
||||
trap 'rm -f "$temporary"' EXIT HUP INT TERM
|
||||
artifact="agent-macos-aarch64"
|
||||
@@ -156,6 +167,8 @@ installed_version=${installed_version##* }
|
||||
[ "$installed_version" = "${release_tag#v}" ] || fail "Release $release_tag 与 Agent 版本 $installed_version 不一致"
|
||||
log "正在配置并启动 macOS LaunchDaemon 服务"
|
||||
launchctl bootout system "$PLIST_FILE" 2>/dev/null || true
|
||||
launchctl bootout system "$LEGACY_PLIST_FILE" 2>/dev/null || true
|
||||
rm -f "$LEGACY_PLIST_FILE"
|
||||
mv "$temporary" "$AGENT_FILE"
|
||||
trap - EXIT HUP INT TERM
|
||||
cat > "$PLIST_FILE" <<EOF
|
||||
@@ -164,6 +177,7 @@ cat > "$PLIST_FILE" <<EOF
|
||||
<plist version="1.0"><dict>
|
||||
<key>Label</key><string>$LABEL</string>
|
||||
<key>ProgramArguments</key><array><string>$AGENT_FILE</string><string>-e</string><string>$endpoint</string><string>-t</string><string>$token</string><string>-i</string><string>$interval</string></array>
|
||||
<key>EnvironmentVariables</key><dict><key>NODEFLARE_STATE_DIR</key><string>$STATE_DIR</string></dict>
|
||||
<key>KeepAlive</key><true/><key>RunAtLoad</key><true/>
|
||||
<key>StandardOutPath</key><string>/var/log/nodeflare-agent.log</string>
|
||||
<key>StandardErrorPath</key><string>/var/log/nodeflare-agent.log</string>
|
||||
|
||||
+18
-4
@@ -9,9 +9,13 @@ param(
|
||||
)
|
||||
|
||||
$ErrorActionPreference = "Stop"
|
||||
$TaskName = "NodeFlare Agent"
|
||||
$InstallDir = Join-Path $env:ProgramData "NodeFlare"
|
||||
$AgentFile = Join-Path $InstallDir "nodeflare-agent.exe"
|
||||
$TaskName = "nodeflare-agent"
|
||||
$LegacyTaskName = "NodeFlare Agent"
|
||||
$InstallDir = Join-Path $env:ProgramFiles "NodeFlare"
|
||||
$StateDir = Join-Path $env:ProgramData "NodeFlare"
|
||||
$AgentFile = Join-Path $InstallDir "agent.exe"
|
||||
$LegacyAgentFile = Join-Path $StateDir "nodeflare-agent.exe"
|
||||
$LegacyCurrentAgentFile = Join-Path $StateDir "agent.exe"
|
||||
|
||||
function Write-Step([string]$Message) {
|
||||
Write-Host "[NodeFlare] $Message"
|
||||
@@ -69,7 +73,11 @@ if ($Uninstall) {
|
||||
Write-Step "正在停止并移除 NodeFlare Agent"
|
||||
Stop-ScheduledTask -TaskName $TaskName -ErrorAction SilentlyContinue
|
||||
Unregister-ScheduledTask -TaskName $TaskName -Confirm:$false -ErrorAction SilentlyContinue
|
||||
Remove-Item -LiteralPath $InstallDir -Recurse -Force -ErrorAction SilentlyContinue
|
||||
Stop-ScheduledTask -TaskName $LegacyTaskName -ErrorAction SilentlyContinue
|
||||
Unregister-ScheduledTask -TaskName $LegacyTaskName -Confirm:$false -ErrorAction SilentlyContinue
|
||||
Remove-Item -LiteralPath $AgentFile -Force -ErrorAction SilentlyContinue
|
||||
Remove-Item -LiteralPath $InstallDir -Force -ErrorAction SilentlyContinue
|
||||
Remove-Item -LiteralPath $StateDir -Recurse -Force -ErrorAction SilentlyContinue
|
||||
Write-Host "NodeFlare Agent 已卸载"
|
||||
exit 0
|
||||
}
|
||||
@@ -103,7 +111,9 @@ if ($TokenLength -gt 512) {
|
||||
$Endpoint = $Endpoint.TrimEnd('/')
|
||||
|
||||
New-Item -ItemType Directory -Path $InstallDir -Force | Out-Null
|
||||
New-Item -ItemType Directory -Path $StateDir -Force | Out-Null
|
||||
& icacls.exe $InstallDir /inheritance:r /grant:r 'SYSTEM:(OI)(CI)F' 'Administrators:(OI)(CI)F' | Out-Null
|
||||
& icacls.exe $StateDir /inheritance:r /grant:r 'SYSTEM:(OI)(CI)F' 'Administrators:(OI)(CI)F' | Out-Null
|
||||
$Temporary = "$AgentFile.$PID.download.exe"
|
||||
$ReleaseApi = "https://api.github.com/repos/imengying/NodeFlare/releases/latest"
|
||||
$Artifact = "agent-windows-x64.exe"
|
||||
@@ -142,7 +152,11 @@ try {
|
||||
Write-InstallError "Release $($Release.tag_name) 与 Agent 版本 $InstalledVersion 不一致"
|
||||
}
|
||||
Stop-ScheduledTask -TaskName $TaskName -ErrorAction SilentlyContinue
|
||||
Stop-ScheduledTask -TaskName $LegacyTaskName -ErrorAction SilentlyContinue
|
||||
Unregister-ScheduledTask -TaskName $LegacyTaskName -Confirm:$false -ErrorAction SilentlyContinue
|
||||
Move-Item -LiteralPath $Temporary -Destination $AgentFile -Force
|
||||
Remove-Item -LiteralPath $LegacyAgentFile -Force -ErrorAction SilentlyContinue
|
||||
Remove-Item -LiteralPath $LegacyCurrentAgentFile -Force -ErrorAction SilentlyContinue
|
||||
} finally {
|
||||
Remove-Item -LiteralPath $Temporary -Force -ErrorAction SilentlyContinue
|
||||
}
|
||||
|
||||
@@ -31,7 +31,7 @@ pub(crate) fn batch_len(queue: &VecDeque<Report>) -> usize {
|
||||
mod tests {
|
||||
use std::collections::VecDeque;
|
||||
|
||||
use super::{batch_len, MAX_LIVE_BATCH_BYTES};
|
||||
use super::{MAX_LIVE_BATCH_BYTES, batch_len};
|
||||
use crate::Report;
|
||||
|
||||
#[test]
|
||||
|
||||
+65
-48
@@ -15,7 +15,7 @@ use std::process::Command;
|
||||
#[cfg(target_os = "windows")]
|
||||
use std::process::Stdio;
|
||||
use std::sync::atomic::{AtomicBool, AtomicI64, Ordering};
|
||||
use std::sync::{mpsc, Arc, Condvar, Mutex};
|
||||
use std::sync::{Arc, Condvar, Mutex, mpsc};
|
||||
use std::thread;
|
||||
use std::time::{Duration, Instant, SystemTime, UNIX_EPOCH};
|
||||
|
||||
@@ -25,7 +25,7 @@ use sha2::{Digest, Sha256};
|
||||
#[cfg(any(target_os = "windows", target_os = "macos", target_os = "freebsd"))]
|
||||
use sysinfo::{Disks, Networks, ProcessRefreshKind, ProcessesToUpdate, System};
|
||||
use tungstenite::client::IntoClientRequest;
|
||||
use tungstenite::{connect, Error as WebSocketError, Message};
|
||||
use tungstenite::{Error as WebSocketError, Message, connect};
|
||||
|
||||
#[cfg(not(any(
|
||||
target_os = "linux",
|
||||
@@ -88,7 +88,7 @@ struct RuntimeConfig {
|
||||
}
|
||||
|
||||
#[derive(Debug, Parser)]
|
||||
#[command(name = "nodeflare", version = VERSION, about = "NodeFlare monitoring agent")]
|
||||
#[command(name = "agent", version = VERSION, about = "NodeFlare monitoring agent")]
|
||||
struct CliOptions {
|
||||
/// NodeFlare endpoint
|
||||
#[arg(short = 'e', value_name = "URL")]
|
||||
@@ -144,19 +144,21 @@ impl LatencyExecutor {
|
||||
let result_tx = result_tx.clone();
|
||||
thread::Builder::new()
|
||||
.name(format!("nodeflare-latency-{index}"))
|
||||
.spawn(move || loop {
|
||||
let task = match task_rx.lock() {
|
||||
Ok(receiver) => receiver.recv(),
|
||||
Err(_) => return,
|
||||
};
|
||||
match task {
|
||||
Ok(task) => {
|
||||
if result_tx.send(execute_latency_task(task)).is_err() {
|
||||
return;
|
||||
.spawn(move || {
|
||||
loop {
|
||||
let task = match task_rx.lock() {
|
||||
Ok(receiver) => receiver.recv(),
|
||||
Err(_) => return,
|
||||
};
|
||||
match task {
|
||||
Ok(task) => {
|
||||
if result_tx.send(execute_latency_task(task)).is_err() {
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(mpsc::RecvError) => return,
|
||||
};
|
||||
Err(mpsc::RecvError) => return,
|
||||
};
|
||||
}
|
||||
})?;
|
||||
}
|
||||
|
||||
@@ -2329,6 +2331,20 @@ fn prune_report_samples(samples: &mut Vec<Report>, now: i64) {
|
||||
}
|
||||
|
||||
fn pending_spool_path() -> Result<PathBuf> {
|
||||
if let Some(value) = env::var_os("NODEFLARE_STATE_DIR") {
|
||||
let directory = PathBuf::from(value);
|
||||
if !directory.is_absolute() {
|
||||
return Err("NODEFLARE_STATE_DIR must be an absolute path".into());
|
||||
}
|
||||
fs::create_dir_all(&directory)?;
|
||||
return Ok(directory.join("pending.jsonl"));
|
||||
}
|
||||
#[cfg(target_os = "windows")]
|
||||
if let Some(program_data) = env::var_os("ProgramData") {
|
||||
let directory = PathBuf::from(program_data).join("NodeFlare");
|
||||
fs::create_dir_all(&directory)?;
|
||||
return Ok(directory.join("pending.jsonl"));
|
||||
}
|
||||
let executable = env::current_exe()?;
|
||||
let directory = executable
|
||||
.parent()
|
||||
@@ -2591,7 +2607,7 @@ fn update(agent: &ureq::Agent, mirror: &str) -> Result<bool> {
|
||||
"Wait-Process -Id $targetPid; ",
|
||||
"Move-Item -LiteralPath $env:NODEFLARE_UPDATE_NEW ",
|
||||
"-Destination $env:NODEFLARE_UPDATE_CURRENT -Force; ",
|
||||
"try { Start-ScheduledTask -TaskName 'NodeFlare Agent' -ErrorAction Stop } ",
|
||||
"try { Start-ScheduledTask -TaskName 'nodeflare-agent' -ErrorAction Stop } ",
|
||||
"catch { $restartArgs=@($env:NODEFLARE_UPDATE_ARGS | ConvertFrom-Json); ",
|
||||
"Start-Process -FilePath $env:NODEFLARE_UPDATE_CURRENT -ArgumentList $restartArgs }"
|
||||
);
|
||||
@@ -2645,16 +2661,15 @@ fn run(options: &CliOptions, once: bool, print_only: bool) -> Result<()> {
|
||||
.map(|report| report.latency_results.len())
|
||||
.sum::<usize>();
|
||||
prune_report_samples(&mut pending_samples, unix_timestamp());
|
||||
if loaded_len != pending_samples.len()
|
||||
if (loaded_len != pending_samples.len()
|
||||
|| loaded_latency
|
||||
!= pending_samples
|
||||
.iter()
|
||||
.map(|report| report.latency_results.len())
|
||||
.sum::<usize>()
|
||||
.sum::<usize>())
|
||||
&& let Err(error) = rewrite_pending_spool(&spool_path, &pending_samples)
|
||||
{
|
||||
if let Err(error) = rewrite_pending_spool(&spool_path, &pending_samples) {
|
||||
eprintln!("pending report spool cleanup failed: {error}");
|
||||
}
|
||||
eprintln!("pending report spool cleanup failed: {error}");
|
||||
}
|
||||
let mut last_emitted_timestamp = pending_samples
|
||||
.iter()
|
||||
@@ -2680,10 +2695,10 @@ fn run(options: &CliOptions, once: bool, print_only: bool) -> Result<()> {
|
||||
let before = pending_samples.len();
|
||||
pending_samples.retain(|report| report.timestamp > persisted_through);
|
||||
stats.persisted_samples_pruned(before.saturating_sub(pending_samples.len()));
|
||||
if before != pending_samples.len() {
|
||||
if let Err(error) = rewrite_pending_spool(&spool_path, &pending_samples) {
|
||||
eprintln!("pending report spool compaction failed: {error}");
|
||||
}
|
||||
if before != pending_samples.len()
|
||||
&& let Err(error) = rewrite_pending_spool(&spool_path, &pending_samples)
|
||||
{
|
||||
eprintln!("pending report spool compaction failed: {error}");
|
||||
}
|
||||
if once_target_timestamp.is_some_and(|target| persisted_through >= target) {
|
||||
return Ok(());
|
||||
@@ -2776,16 +2791,15 @@ fn run(options: &CliOptions, once: bool, print_only: bool) -> Result<()> {
|
||||
pending_samples.drain(..overflow);
|
||||
stats.live_queue_dropped(overflow);
|
||||
}
|
||||
if before_prune != pending_samples.len()
|
||||
if (before_prune != pending_samples.len()
|
||||
|| latency_before_prune
|
||||
!= pending_samples
|
||||
.iter()
|
||||
.map(|report| report.latency_results.len())
|
||||
.sum::<usize>()
|
||||
.sum::<usize>())
|
||||
&& let Err(error) = rewrite_pending_spool(&spool_path, &pending_samples)
|
||||
{
|
||||
if let Err(error) = rewrite_pending_spool(&spool_path, &pending_samples) {
|
||||
eprintln!("pending report spool compaction failed: {error}");
|
||||
}
|
||||
eprintln!("pending report spool compaction failed: {error}");
|
||||
}
|
||||
next_collect = advance_deadline(
|
||||
next_collect,
|
||||
@@ -2842,7 +2856,7 @@ fn main() {
|
||||
let options = CliOptions::parse();
|
||||
let result = run(&options, options.once || options.collect, options.collect);
|
||||
if let Err(error) = result {
|
||||
eprintln!("nodeflare-agent: {error}");
|
||||
eprintln!("agent: {error}");
|
||||
std::process::exit(1);
|
||||
}
|
||||
}
|
||||
@@ -2853,15 +2867,16 @@ mod tests {
|
||||
use std::time::{Duration, Instant};
|
||||
|
||||
use super::{
|
||||
CLOCK_CALIBRATION_MAX_AGE, CliOptions, ClockCalibration, GithubReleaseAsset, LatencyResult,
|
||||
LatencyTask, LiveAck, MAX_LATENCY_TASKS, MAX_PENDING_LATENCY_RESULTS,
|
||||
PUBLIC_IP_STALE_AFTER, PublicIpValue, Report, UPDATE_CHECK_JITTER_MAX_SECONDS,
|
||||
ack_d1_interval, ack_wss_interval, advance_deadline, clock_offset_from_http_date,
|
||||
corrected_timestamp, gpu_name_from_uevent, is_public_probe_ip, live_endpoint,
|
||||
live_update_payload, monotonic_report_timestamp, normalized_version, parse_lspci_gpu_names,
|
||||
parse_pciconf_gpu_names, parse_probe_target, parse_public_ip,
|
||||
parse_system_profiler_gpu_names, ping_latencies, ping_latency, prune_report_samples,
|
||||
release_asset_sha256, sanitize_latency_tasks, update_check_jitter, valid_endpoint,
|
||||
version_triplet, CliOptions, ClockCalibration, GithubReleaseAsset, LatencyResult,
|
||||
LatencyTask, LiveAck, PublicIpValue, Report, CLOCK_CALIBRATION_MAX_AGE, MAX_LATENCY_TASKS,
|
||||
MAX_PENDING_LATENCY_RESULTS, PUBLIC_IP_STALE_AFTER, UPDATE_CHECK_JITTER_MAX_SECONDS,
|
||||
version_triplet,
|
||||
};
|
||||
|
||||
#[cfg(any(target_os = "windows", target_os = "macos", target_os = "freebsd"))]
|
||||
@@ -3080,7 +3095,7 @@ mod tests {
|
||||
#[test]
|
||||
fn parses_cli_options() {
|
||||
let parsed = CliOptions::try_parse_from([
|
||||
"nodeflare",
|
||||
"agent",
|
||||
"-e",
|
||||
"https://monitor.example.com",
|
||||
"-t",
|
||||
@@ -3094,19 +3109,21 @@ mod tests {
|
||||
assert_eq!(parsed.token, "agent-token");
|
||||
assert_eq!(parsed.interval, 60);
|
||||
assert!(parsed.once);
|
||||
assert!(CliOptions::try_parse_from(["nodeflare", "-t"]).is_err());
|
||||
assert!(CliOptions::try_parse_from(["nodeflare", "-t", "first", "-t", "second"]).is_err());
|
||||
assert!(CliOptions::try_parse_from([
|
||||
"nodeflare",
|
||||
"-e",
|
||||
"https://monitor.example.com",
|
||||
"-t",
|
||||
"agent-token",
|
||||
"--token-file",
|
||||
"/run/nodeflare/token",
|
||||
])
|
||||
.is_err());
|
||||
assert!(CliOptions::try_parse_from(["nodeflare", "--once", "--collect"]).is_err());
|
||||
assert!(CliOptions::try_parse_from(["agent", "-t"]).is_err());
|
||||
assert!(CliOptions::try_parse_from(["agent", "-t", "first", "-t", "second"]).is_err());
|
||||
assert!(
|
||||
CliOptions::try_parse_from([
|
||||
"agent",
|
||||
"-e",
|
||||
"https://monitor.example.com",
|
||||
"-t",
|
||||
"agent-token",
|
||||
"--token-file",
|
||||
"/run/nodeflare/token",
|
||||
])
|
||||
.is_err()
|
||||
);
|
||||
assert!(CliOptions::try_parse_from(["agent", "--once", "--collect"]).is_err());
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
||||
Reference in new issue
Block a user