完善远程执行、主题安装与部署流程

This commit is contained in:
imengying committed 2026-09-04 03:47:06 +08:00
1 parent dae8f665db
commit 2f7cccd94d
53 files changed
+2348 -624

No files matched your search

+1 -1
View File
@@ -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
View File
@@ -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 已卸载"
}
+32 -9
View File
@@ -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
View File
@@ -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
View File
@@ -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
}
+1 -1
View File
@@ -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
View File
@@ -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]