fix collectors, modular apply/unapply patches, correct config loading in pve-mod-configure (#208)
* first * also check for output file * add full debug to intel device * implement ups debug and intel debug * fix system information call * add graphic info call and return if call not configured * add intel to safe init * write out intel to config * fix patch * Move collection of system information to cache * implement system info * fix config load * more intel fixes * fix tainted paths and intel graphics * resolved rrd crash by disabling rrd when not enabled * fix(configure): toggle install state, scope patching to selected mod * small fix for get_graphics_info naming * fix(configure): don't update config if patch apply/revert fails * revert version in config --------- Co-authored-by: Meliox <na>
This commit is contained in:
parent
8547e337b7
commit
5df83ec369
@ -102,8 +102,14 @@ if ! command -v patch >/dev/null 2>&1; then
|
|||||||
exit 1
|
exit 1
|
||||||
fi
|
fi
|
||||||
|
|
||||||
for mod in $(list_modules); do
|
mapfile -t _all_modules < <(list_modules)
|
||||||
[[ "$(read_conf "$MAIN_CONF" modules "$mod" 0)" == "1" ]] || continue
|
_target_modules=("${@:-${_all_modules[@]}}")
|
||||||
|
for mod in "${_target_modules[@]}"; do
|
||||||
|
# When modules are explicitly named as args, the caller decides what to apply.
|
||||||
|
# When running for all modules (no args from dpkg trigger), respect the config.
|
||||||
|
if [[ $# -eq 0 ]]; then
|
||||||
|
[[ "$(read_conf "$MAIN_CONF" modules "$mod" 0)" == "1" ]] || continue
|
||||||
|
fi
|
||||||
|
|
||||||
mod_dir="$PATCHES_DIR/$mod"
|
mod_dir="$PATCHES_DIR/$mod"
|
||||||
manifest="$mod_dir/patches.list"
|
manifest="$mod_dir/patches.list"
|
||||||
|
|||||||
@ -11,6 +11,7 @@ CONFD_DIR="/etc/pve-mod/conf.d"
|
|||||||
NODE_INFO_CONF="${CONFD_DIR}/node_info.conf"
|
NODE_INFO_CONF="${CONFD_DIR}/node_info.conf"
|
||||||
NAG_SCREEN_CONF="${CONFD_DIR}/nag_screen.conf"
|
NAG_SCREEN_CONF="${CONFD_DIR}/nag_screen.conf"
|
||||||
APPLY_PATCHES="/usr/lib/pve-mod/apply-patches.sh"
|
APPLY_PATCHES="/usr/lib/pve-mod/apply-patches.sh"
|
||||||
|
REVERT_PATCHES="/usr/lib/pve-mod/revert-patches.sh"
|
||||||
NODES_PM="/usr/share/perl5/PVE/API2/Nodes.pm"
|
NODES_PM="/usr/share/perl5/PVE/API2/Nodes.pm"
|
||||||
|
|
||||||
KNOWN_CPU_SENSORS=("coretemp-isa-" "k10temp-pci-")
|
KNOWN_CPU_SENSORS=("coretemp-isa-" "k10temp-pci-")
|
||||||
@ -26,10 +27,33 @@ ask() {
|
|||||||
echo "$response"
|
echo "$response"
|
||||||
}
|
}
|
||||||
bool() { [[ "$1" == true ]] && echo 1 || echo 0; }
|
bool() { [[ "$1" == true ]] && echo 1 || echo 0; }
|
||||||
|
mod_status() {
|
||||||
|
local val="$1" on_label="${2:-[enabled]}" off_label="${3:-[disabled]}"
|
||||||
|
[[ "$val" == "1" ]] && echo -e "\e[0;32m${on_label}\e[0m" || echo -e "\e[0;33m${off_label}\e[0m"
|
||||||
|
}
|
||||||
|
|
||||||
_load_conf() {
|
_load_conf() {
|
||||||
|
# Load main config (module toggles + pve_trigger)
|
||||||
|
if [[ -f "$CONF_FILE" ]]; then
|
||||||
|
local section="" line key val
|
||||||
|
while IFS= read -r line; do
|
||||||
|
case "$line" in
|
||||||
|
'#'*|'') continue ;;
|
||||||
|
'['*']') section="${line#[}"; section="${section%]}"; continue ;;
|
||||||
|
esac
|
||||||
|
[[ "$line" == *=* ]] || continue
|
||||||
|
key="${line%%=*}"; val="${line#*=}"
|
||||||
|
case "${section}.${key}" in
|
||||||
|
modules.node_info) MOD_NODE_INFO="$val" ;;
|
||||||
|
modules.nag_screen) MOD_NAG_SCREEN="$val" ;;
|
||||||
|
pve_trigger.enabled) PVE_TRIGGER_ENABLED="$val" ;;
|
||||||
|
esac
|
||||||
|
done < "$CONF_FILE"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Load node_info mod config
|
||||||
[[ -f "$NODE_INFO_CONF" ]] || return 0
|
[[ -f "$NODE_INFO_CONF" ]] || return 0
|
||||||
local in_debug=0 line key val
|
local in_debug=0 line key val section=""
|
||||||
while IFS= read -r line; do
|
while IFS= read -r line; do
|
||||||
case "$line" in
|
case "$line" in
|
||||||
'#'*|'') continue ;;
|
'#'*|'') continue ;;
|
||||||
@ -69,6 +93,7 @@ _load_conf() {
|
|||||||
debug.lm_sensors_output_file) DEBUG_LM_SENSORS_FILE="$val" ;;
|
debug.lm_sensors_output_file) DEBUG_LM_SENSORS_FILE="$val" ;;
|
||||||
debug.intel_mode) DEBUG_INTEL="$val" ;;
|
debug.intel_mode) DEBUG_INTEL="$val" ;;
|
||||||
debug.intel_devices_file) DEBUG_INTEL_FILE="$val" ;;
|
debug.intel_devices_file) DEBUG_INTEL_FILE="$val" ;;
|
||||||
|
debug.intel_output_file) DEBUG_INTEL_OUTPUT_FILE="$val" ;;
|
||||||
debug.nvidia_mode) DEBUG_NVIDIA="$val" ;;
|
debug.nvidia_mode) DEBUG_NVIDIA="$val" ;;
|
||||||
debug.nvidia_devices_file) DEBUG_NVIDIA_DEVICES_FILE="$val" ;;
|
debug.nvidia_devices_file) DEBUG_NVIDIA_DEVICES_FILE="$val" ;;
|
||||||
debug.nvidia_output_file) DEBUG_NVIDIA_OUTPUT_FILE="$val" ;;
|
debug.nvidia_output_file) DEBUG_NVIDIA_OUTPUT_FILE="$val" ;;
|
||||||
@ -281,7 +306,12 @@ configure_node_info() {
|
|||||||
if [[ -n "$intelCards" ]]; then
|
if [[ -n "$intelCards" ]]; then
|
||||||
info "Intel GPU(s) detected (debug):"
|
info "Intel GPU(s) detected (debug):"
|
||||||
echo "$intelCards" | while IFS= read -r line; do echo " $line"; done
|
echo "$intelCards" | while IFS= read -r line; do echo " $line"; done
|
||||||
ENABLE_INTEL_GPU_INFO=1
|
if [[ -f "$DEBUG_INTEL_OUTPUT_FILE" ]]; then
|
||||||
|
info "[debug] Intel GPU stats output file found at $DEBUG_INTEL_OUTPUT_FILE"
|
||||||
|
ENABLE_INTEL_GPU_INFO=1
|
||||||
|
else
|
||||||
|
warn "[debug] Intel GPU stats output file not found at $DEBUG_INTEL_OUTPUT_FILE. GPU stats graphs will be empty."
|
||||||
|
fi
|
||||||
else
|
else
|
||||||
warn "No Intel GPUs in debug file."
|
warn "No Intel GPUs in debug file."
|
||||||
fi
|
fi
|
||||||
@ -291,6 +321,25 @@ configure_node_info() {
|
|||||||
info "Intel GPU(s) detected:"
|
info "Intel GPU(s) detected:"
|
||||||
echo "$intelCards" | while IFS= read -r line; do echo " $line"; done
|
echo "$intelCards" | while IFS= read -r line; do echo " $line"; done
|
||||||
ENABLE_INTEL_GPU_INFO=1
|
ENABLE_INTEL_GPU_INFO=1
|
||||||
|
|
||||||
|
# Write JSON devices file for debug/cache use by the Perl collector
|
||||||
|
local json="["
|
||||||
|
local first=1
|
||||||
|
while IFS= read -r line; do
|
||||||
|
# Parse: "card0 Intel Alderlake_n (Gen12) pci:vendor=8086,device=46D0,card=0"
|
||||||
|
if [[ "$line" =~ ^(card[0-9]+)[[:space:]]+(.+[^[:space:]])[[:space:]]+(pci:[^[:space:]]+) ]]; then
|
||||||
|
local card="${BASH_REMATCH[1]}"
|
||||||
|
local name="${BASH_REMATCH[2]}"
|
||||||
|
local path="${BASH_REMATCH[3]}"
|
||||||
|
name="${name%"${name##*[![:space:]]}"}" # rtrim
|
||||||
|
[[ "$first" -eq 0 ]] && json+=","
|
||||||
|
json+="{\"card\":\"$card\",\"name\":\"$name\",\"path\":\"$path\",\"drm_path\":\"/dev/dri/$card\"}"
|
||||||
|
first=0
|
||||||
|
fi
|
||||||
|
done <<< "$intelCards"
|
||||||
|
json+="]"
|
||||||
|
echo "$json" > "$DEBUG_INTEL_FILE"
|
||||||
|
info "Intel GPU device list saved to $DEBUG_INTEL_FILE"
|
||||||
else
|
else
|
||||||
warn "No Intel GPUs detected by intel_gpu_top."
|
warn "No Intel GPUs detected by intel_gpu_top."
|
||||||
fi
|
fi
|
||||||
@ -306,7 +355,12 @@ configure_node_info() {
|
|||||||
if [[ -n "$nvidiaCards" ]]; then
|
if [[ -n "$nvidiaCards" ]]; then
|
||||||
info "NVIDIA GPU(s) detected (debug):"
|
info "NVIDIA GPU(s) detected (debug):"
|
||||||
echo "$nvidiaCards" | while IFS= read -r line; do echo " $line"; done
|
echo "$nvidiaCards" | while IFS= read -r line; do echo " $line"; done
|
||||||
ENABLE_NVIDIA_GPU_INFO=1
|
if [[ -f "$DEBUG_NVIDIA_OUTPUT_FILE" ]]; then
|
||||||
|
info "[debug] NVIDIA GPU stats output file found at $DEBUG_NVIDIA_OUTPUT_FILE"
|
||||||
|
ENABLE_NVIDIA_GPU_INFO=1
|
||||||
|
else
|
||||||
|
warn "[debug] NVIDIA GPU stats output file not found at $DEBUG_NVIDIA_OUTPUT_FILE. GPU stats graphs will be empty."
|
||||||
|
fi
|
||||||
else
|
else
|
||||||
warn "No NVIDIA GPUs in debug file."
|
warn "No NVIDIA GPUs in debug file."
|
||||||
fi
|
fi
|
||||||
@ -347,16 +401,20 @@ configure_node_info() {
|
|||||||
[yY])
|
[yY])
|
||||||
local upsConn modelName upsOutput
|
local upsConn modelName upsOutput
|
||||||
upsConn=$(ask "Enter UPS connection string (e.g. upsname@hostname[:port])")
|
upsConn=$(ask "Enter UPS connection string (e.g. upsname@hostname[:port])")
|
||||||
if [[ "$DEBUG_UPS" -eq 1 && -f "$DEBUG_UPS_FILE" ]]; then
|
if [[ "$DEBUG_UPS" -eq 1 ]]; then
|
||||||
info "[debug] Using UPS data from $DEBUG_UPS_FILE"
|
if [[ -f "$DEBUG_UPS_FILE" ]]; then
|
||||||
upsOutput=$(cat "$DEBUG_UPS_FILE")
|
info "[debug] Using UPS data from $DEBUG_UPS_FILE"
|
||||||
else
|
else
|
||||||
if ! command -v upsc &>/dev/null; then
|
warn "[debug] Debug mode for UPS is enabled but file not found at $DEBUG_UPS_FILE."
|
||||||
err "'upsc' is not available. Install 'nut-client' first."
|
|
||||||
fi
|
fi
|
||||||
upsOutput=$(upsc "$upsConn" 2>&1)
|
upsOutput=$(cat "$DEBUG_UPS_FILE" || true)
|
||||||
|
ENABLE_UPS=1
|
||||||
|
elif _check_or_install_tool upsc nut-client "Network UPS Tools (upsc)" && [[ -n "$upsConn" ]]; then
|
||||||
|
upsOutput=$(upsc "$upsConn" 2>/dev/null || true)
|
||||||
|
else
|
||||||
|
warn "Could not connect to UPS at '$upsConn'. UPS info will be disabled."
|
||||||
fi
|
fi
|
||||||
if echo "$upsOutput" | grep -q "device.model:"; then
|
if [[ -n "$upsOutput" ]]; then
|
||||||
modelName=$(echo "$upsOutput" | grep "device.model:" | cut -d: -f2- | xargs)
|
modelName=$(echo "$upsOutput" | grep "device.model:" | cut -d: -f2- | xargs)
|
||||||
ENABLE_UPS=1
|
ENABLE_UPS=1
|
||||||
UPS_DEVICE_NAME="$upsConn"
|
UPS_DEVICE_NAME="$upsConn"
|
||||||
@ -365,7 +423,7 @@ configure_node_info() {
|
|||||||
warn "Could not connect to UPS at '$upsConn'. UPS info will be disabled."
|
warn "Could not connect to UPS at '$upsConn'. UPS info will be disabled."
|
||||||
ENABLE_UPS=0
|
ENABLE_UPS=0
|
||||||
fi
|
fi
|
||||||
;;
|
;;
|
||||||
*) info "UPS information disabled." ;;
|
*) info "UPS information disabled." ;;
|
||||||
esac
|
esac
|
||||||
#endregion UPS
|
#endregion UPS
|
||||||
@ -385,6 +443,15 @@ configure_node_info() {
|
|||||||
[nN]) info "System information disabled." ;;
|
[nN]) info "System information disabled." ;;
|
||||||
*) warn "Invalid selection. Defaulting to type 1."; ENABLE_SYSTEM_INFO=1; SYSTEM_INFO_TYPE=1 ;;
|
*) warn "Invalid selection. Defaulting to type 1."; ENABLE_SYSTEM_INFO=1; SYSTEM_INFO_TYPE=1 ;;
|
||||||
esac
|
esac
|
||||||
|
|
||||||
|
if [[ "$ENABLE_SYSTEM_INFO" -eq 1 ]]; then
|
||||||
|
local cache_dir="/var/lib/pve-mod"
|
||||||
|
mkdir -p "$cache_dir"
|
||||||
|
local cache_file="${cache_dir}/dmidecode-type${SYSTEM_INFO_TYPE}.txt"
|
||||||
|
dmidecode -t "$SYSTEM_INFO_TYPE" > "$cache_file" 2>/dev/null || true
|
||||||
|
chmod 644 "$cache_file"
|
||||||
|
info "DMI data cached to $cache_file"
|
||||||
|
fi
|
||||||
#endregion System info
|
#endregion System info
|
||||||
}
|
}
|
||||||
#endregion node-info wizard
|
#endregion node-info wizard
|
||||||
@ -407,9 +474,6 @@ nag_screen=${MOD_NAG_SCREEN}
|
|||||||
|
|
||||||
[pve_trigger]
|
[pve_trigger]
|
||||||
enabled=${PVE_TRIGGER_ENABLED}
|
enabled=${PVE_TRIGGER_ENABLED}
|
||||||
|
|
||||||
[service]
|
|
||||||
mode=embedded
|
|
||||||
EOF
|
EOF
|
||||||
info "Main configuration saved to $CONF_FILE"
|
info "Main configuration saved to $CONF_FILE"
|
||||||
|
|
||||||
@ -450,6 +514,7 @@ lm_sensors_mode=${DEBUG_LM_SENSORS}
|
|||||||
lm_sensors_output_file=${DEBUG_LM_SENSORS_FILE}
|
lm_sensors_output_file=${DEBUG_LM_SENSORS_FILE}
|
||||||
intel_mode=${DEBUG_INTEL}
|
intel_mode=${DEBUG_INTEL}
|
||||||
intel_devices_file=${DEBUG_INTEL_FILE}
|
intel_devices_file=${DEBUG_INTEL_FILE}
|
||||||
|
intel_output_file=${DEBUG_INTEL_OUTPUT_FILE}
|
||||||
nvidia_mode=${DEBUG_NVIDIA}
|
nvidia_mode=${DEBUG_NVIDIA}
|
||||||
nvidia_devices_file=${DEBUG_NVIDIA_DEVICES_FILE}
|
nvidia_devices_file=${DEBUG_NVIDIA_DEVICES_FILE}
|
||||||
nvidia_output_file=${DEBUG_NVIDIA_OUTPUT_FILE}
|
nvidia_output_file=${DEBUG_NVIDIA_OUTPUT_FILE}
|
||||||
@ -473,69 +538,6 @@ EOF
|
|||||||
}
|
}
|
||||||
#endregion write config
|
#endregion write config
|
||||||
|
|
||||||
#region debug wizard
|
|
||||||
configure_debug() {
|
|
||||||
msgb "\n=== Debug / Development Mode ==="
|
|
||||||
echo "Debug mode substitutes real tools with pre-captured data files."
|
|
||||||
echo "When a collector's mode is enabled the tool (sensors/intel_gpu_top/etc.) is not required."
|
|
||||||
local choice
|
|
||||||
choice=$(ask "Configure debug file overrides? (y/N)")
|
|
||||||
[[ "$choice" != [yY] ]] && return
|
|
||||||
|
|
||||||
local newpath
|
|
||||||
|
|
||||||
choice=$(ask "Enable LM-Sensors debug? (y/N)")
|
|
||||||
if [[ "$choice" == [yY] ]]; then
|
|
||||||
DEBUG_LM_SENSORS=1
|
|
||||||
newpath=$(ask "Path to sensors JSON file [${DEBUG_LM_SENSORS_FILE}]")
|
|
||||||
DEBUG_LM_SENSORS_FILE="${newpath:-$DEBUG_LM_SENSORS_FILE}"
|
|
||||||
info "LM-Sensors debug: ${DEBUG_LM_SENSORS_FILE}"
|
|
||||||
fi
|
|
||||||
|
|
||||||
choice=$(ask "Enable Intel GPU debug? (y/N)")
|
|
||||||
if [[ "$choice" == [yY] ]]; then
|
|
||||||
DEBUG_INTEL=1
|
|
||||||
newpath=$(ask "Path to Intel GPU devices JSON [${DEBUG_INTEL_FILE}]")
|
|
||||||
DEBUG_INTEL_FILE="${newpath:-$DEBUG_INTEL_FILE}"
|
|
||||||
info "Intel GPU debug: ${DEBUG_INTEL_FILE}"
|
|
||||||
fi
|
|
||||||
|
|
||||||
choice=$(ask "Enable NVIDIA GPU debug? (y/N)")
|
|
||||||
if [[ "$choice" == [yY] ]]; then
|
|
||||||
DEBUG_NVIDIA=1
|
|
||||||
newpath=$(ask "Path to nvidia-smi output CSV [${DEBUG_NVIDIA_OUTPUT_FILE}]")
|
|
||||||
DEBUG_NVIDIA_OUTPUT_FILE="${newpath:-$DEBUG_NVIDIA_OUTPUT_FILE}"
|
|
||||||
newpath=$(ask "Path to nvidia-smi devices CSV [${DEBUG_NVIDIA_DEVICES_FILE}]")
|
|
||||||
DEBUG_NVIDIA_DEVICES_FILE="${newpath:-$DEBUG_NVIDIA_DEVICES_FILE}"
|
|
||||||
info "NVIDIA GPU debug: output=${DEBUG_NVIDIA_OUTPUT_FILE} devices=${DEBUG_NVIDIA_DEVICES_FILE}"
|
|
||||||
fi
|
|
||||||
|
|
||||||
choice=$(ask "Enable AMD GPU debug? (y/N)")
|
|
||||||
if [[ "$choice" == [yY] ]]; then
|
|
||||||
DEBUG_AMD=1
|
|
||||||
newpath=$(ask "Path to AMD GPU devices JSON [${DEBUG_AMD_FILE}]")
|
|
||||||
DEBUG_AMD_FILE="${newpath:-$DEBUG_AMD_FILE}"
|
|
||||||
info "AMD GPU debug: ${DEBUG_AMD_FILE}"
|
|
||||||
fi
|
|
||||||
|
|
||||||
choice=$(ask "Enable UPS debug? (y/N)")
|
|
||||||
if [[ "$choice" == [yY] ]]; then
|
|
||||||
DEBUG_UPS=1
|
|
||||||
newpath=$(ask "Path to UPS output JSON [${DEBUG_UPS_FILE}]")
|
|
||||||
DEBUG_UPS_FILE="${newpath:-$DEBUG_UPS_FILE}"
|
|
||||||
info "UPS debug: ${DEBUG_UPS_FILE}"
|
|
||||||
fi
|
|
||||||
|
|
||||||
choice=$(ask "Enable debug logging? (y/N)")
|
|
||||||
if [[ "$choice" == [yY] ]]; then
|
|
||||||
DEBUG_LOG=1
|
|
||||||
newpath=$(ask "Log file path [${DEBUG_LOG_FILE}]")
|
|
||||||
DEBUG_LOG_FILE="${newpath:-$DEBUG_LOG_FILE}"
|
|
||||||
info "Debug log: ${DEBUG_LOG_FILE}"
|
|
||||||
fi
|
|
||||||
}
|
|
||||||
#endregion debug wizard
|
|
||||||
|
|
||||||
main() {
|
main() {
|
||||||
# ── Welcome banner ────────────────────────────────────────────────────────
|
# ── Welcome banner ────────────────────────────────────────────────────────
|
||||||
local _version
|
local _version
|
||||||
@ -578,6 +580,7 @@ main() {
|
|||||||
PVE_TRIGGER_ENABLED=0
|
PVE_TRIGGER_ENABLED=0
|
||||||
DEBUG_LM_SENSORS=0; DEBUG_LM_SENSORS_FILE="/tmp/sensors-output.json"
|
DEBUG_LM_SENSORS=0; DEBUG_LM_SENSORS_FILE="/tmp/sensors-output.json"
|
||||||
DEBUG_INTEL=0; DEBUG_INTEL_FILE="/tmp/intel-gpu-devices.json"
|
DEBUG_INTEL=0; DEBUG_INTEL_FILE="/tmp/intel-gpu-devices.json"
|
||||||
|
DEBUG_INTEL_OUTPUT_FILE="/tmp/intel-gpu-top-output.txt"
|
||||||
DEBUG_NVIDIA=0; DEBUG_NVIDIA_OUTPUT_FILE="/tmp/nvidia-smi-output.csv"
|
DEBUG_NVIDIA=0; DEBUG_NVIDIA_OUTPUT_FILE="/tmp/nvidia-smi-output.csv"
|
||||||
DEBUG_NVIDIA_DEVICES_FILE="/tmp/nvidia-smi-devices.csv"
|
DEBUG_NVIDIA_DEVICES_FILE="/tmp/nvidia-smi-devices.csv"
|
||||||
DEBUG_AMD=0; DEBUG_AMD_FILE="/tmp/amd-gpu-devices.json"
|
DEBUG_AMD=0; DEBUG_AMD_FILE="/tmp/amd-gpu-devices.json"
|
||||||
@ -590,41 +593,60 @@ main() {
|
|||||||
# this run, and all other options retain their previously saved values.
|
# this run, and all other options retain their previously saved values.
|
||||||
msgb "\n=== pve-mod Module Selection ==="
|
msgb "\n=== pve-mod Module Selection ==="
|
||||||
echo "Available options (select one):"
|
echo "Available options (select one):"
|
||||||
echo " [1] Node Info — sensor readings, GPU stats, UPS, system information"
|
echo -e " [1] Node Info $(mod_status "$MOD_NODE_INFO") — sensor readings, GPU stats, UPS, system information"
|
||||||
echo " [2] Nag Screen — remove Proxmox subscription nag screen"
|
echo -e " [2] Nag Screen $(mod_status "$MOD_NAG_SCREEN") — remove Proxmox subscription nag screen"
|
||||||
echo " [3] Auto re-patch on PVE upgrade — automatically re-apply patches when"
|
echo -e " [3] Auto re-patch on PVE upgrade $(mod_status "$PVE_TRIGGER_ENABLED") — automatically re-apply patches when"
|
||||||
echo " pve-manager is upgraded"
|
echo " pve-manager is upgraded"
|
||||||
echo " [n] None / cancel"
|
echo " [n] None / cancel"
|
||||||
local modChoice
|
local modChoice selected_mod="" patching_needed=0
|
||||||
modChoice=$(ask "Select an option to enable (1/2/3/n)")
|
modChoice=$(ask "Select an option (1/2/3/n)")
|
||||||
case "$modChoice" in
|
case "$modChoice" in
|
||||||
1)
|
1)
|
||||||
MOD_NODE_INFO=1
|
selected_mod="node_info"
|
||||||
msgb "\n=== Node Info Configuration ==="
|
if [[ "$MOD_NODE_INFO" == "1" ]]; then
|
||||||
configure_node_info
|
MOD_NODE_INFO=0; info "Node Info will be removed."
|
||||||
|
else
|
||||||
|
MOD_NODE_INFO=1; patching_needed=1
|
||||||
|
msgb "\n=== Node Info Configuration ==="
|
||||||
|
configure_node_info
|
||||||
|
fi
|
||||||
;;
|
;;
|
||||||
2)
|
2)
|
||||||
MOD_NAG_SCREEN=1
|
selected_mod="nag_screen"
|
||||||
msgb "\n=== Nag Screen ==="
|
if [[ "$MOD_NAG_SCREEN" == "1" ]]; then
|
||||||
info "Subscription nag screen removal will be applied."
|
MOD_NAG_SCREEN=0; info "Nag Screen will be removed."
|
||||||
|
else
|
||||||
|
MOD_NAG_SCREEN=1; patching_needed=1
|
||||||
|
info "Subscription nag screen removal will be applied."
|
||||||
|
fi
|
||||||
;;
|
;;
|
||||||
3)
|
3)
|
||||||
PVE_TRIGGER_ENABLED=1
|
if [[ "$PVE_TRIGGER_ENABLED" == "1" ]]; then
|
||||||
info "Auto re-patching on PVE upgrade enabled."
|
PVE_TRIGGER_ENABLED=0; info "Auto re-patch disabled."
|
||||||
|
else
|
||||||
|
PVE_TRIGGER_ENABLED=1; info "Auto re-patching on PVE upgrade enabled."
|
||||||
|
fi
|
||||||
;;
|
;;
|
||||||
[nN]) info "No option selected. Exiting."; exit 0 ;;
|
[nN]) info "No option selected. Exiting."; exit 0 ;;
|
||||||
*) warn "Invalid selection. Exiting."; exit 0 ;;
|
*) warn "Invalid selection. Exiting."; exit 0 ;;
|
||||||
esac
|
esac
|
||||||
|
|
||||||
# ── Debug mode ────────────────────────────────────────────────────────────
|
# ── Write config and apply/revert ─────────────────────────────────────────
|
||||||
configure_debug
|
# For mods with patches: apply if being enabled, revert if being disabled.
|
||||||
|
# Option 3 (pve_trigger) has no patches — write_config is sufficient.
|
||||||
# ── Write config and apply ────────────────────────────────────────────────
|
if [[ "$patching_needed" == "1" ]]; then
|
||||||
|
msgb "\n=== Applying patches ==="
|
||||||
|
if ! "$APPLY_PATCHES" "$selected_mod"; then
|
||||||
|
err "Could not apply all patches for $selected_mod. Configuration was not updated."
|
||||||
|
fi
|
||||||
|
elif [[ -n "$selected_mod" ]]; then
|
||||||
|
msgb "\n=== Removing patches ==="
|
||||||
|
if ! "$REVERT_PATCHES" "$selected_mod"; then
|
||||||
|
err "Could not revert all patches for $selected_mod. Configuration was not updated."
|
||||||
|
fi
|
||||||
|
fi
|
||||||
write_config
|
write_config
|
||||||
|
|
||||||
msgb "\n=== Applying patches ==="
|
|
||||||
"$APPLY_PATCHES"
|
|
||||||
|
|
||||||
msgb "\n=== Done ==="
|
msgb "\n=== Done ==="
|
||||||
info "pve-mod is configured and active."
|
info "pve-mod is configured and active."
|
||||||
info "Clear your browser cache to see the changes."
|
info "Clear your browser cache to see the changes."
|
||||||
|
|||||||
@ -39,7 +39,7 @@ revert_one_patch() {
|
|||||||
fi
|
fi
|
||||||
warn " $(basename "$patch") could not be reverted cleanly; manual cleanup may be needed"
|
warn " $(basename "$patch") could not be reverted cleanly; manual cleanup may be needed"
|
||||||
patch -R -p1 -F0 -f --dry-run --verbose -d "$PVE_MOD_ROOT" < "$patch" >&2 || true
|
patch -R -p1 -F0 -f --dry-run --verbose -d "$PVE_MOD_ROOT" < "$patch" >&2 || true
|
||||||
return 1
|
return 2
|
||||||
}
|
}
|
||||||
|
|
||||||
# ── main ──────────────────────────────────────────────────────────────────────
|
# ── main ──────────────────────────────────────────────────────────────────────
|
||||||
@ -51,10 +51,13 @@ fi
|
|||||||
[[ -d "$PATCHES_DIR" ]] || exit 0
|
[[ -d "$PATCHES_DIR" ]] || exit 0
|
||||||
|
|
||||||
CHANGED=false
|
CHANGED=false
|
||||||
|
FAILED=false
|
||||||
|
|
||||||
for mod_dir in "$PATCHES_DIR"/*/; do
|
mapfile -t _all_modules < <(for d in "$PATCHES_DIR"/*/; do [[ -d "$d" ]] && basename "$d"; done)
|
||||||
|
_target_modules=("${@:-${_all_modules[@]}}")
|
||||||
|
for mod in "${_target_modules[@]}"; do
|
||||||
|
mod_dir="$PATCHES_DIR/$mod/"
|
||||||
[[ -d "$mod_dir" ]] || continue
|
[[ -d "$mod_dir" ]] || continue
|
||||||
mod="$(basename "$mod_dir")"
|
|
||||||
manifest="$mod_dir/patches.list"
|
manifest="$mod_dir/patches.list"
|
||||||
mod_conf="$CONFD_DIR/$mod.conf"
|
mod_conf="$CONFD_DIR/$mod.conf"
|
||||||
|
|
||||||
@ -88,9 +91,13 @@ for mod_dir in "$PATCHES_DIR"/*/; do
|
|||||||
patch_name="${patches[$i]}"
|
patch_name="${patches[$i]}"
|
||||||
patch_file="$mod_dir/$patch_name"
|
patch_file="$mod_dir/$patch_name"
|
||||||
[[ -f "$patch_file" ]] || continue
|
[[ -f "$patch_file" ]] || continue
|
||||||
if revert_one_patch "$patch_file"; then
|
revert_one_patch "$patch_file"
|
||||||
|
rc=$?
|
||||||
|
if [[ "$rc" -eq 0 ]]; then
|
||||||
info " reverted $patch_name"
|
info " reverted $patch_name"
|
||||||
CHANGED=true
|
CHANGED=true
|
||||||
|
elif [[ "$rc" -eq 2 ]]; then
|
||||||
|
FAILED=true
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
done
|
done
|
||||||
@ -99,4 +106,6 @@ if [[ "$CHANGED" == "true" ]]; then
|
|||||||
info "Restarting pveproxy..."
|
info "Restarting pveproxy..."
|
||||||
systemctl restart pveproxy 2>/dev/null || true
|
systemctl restart pveproxy 2>/dev/null || true
|
||||||
fi
|
fi
|
||||||
|
|
||||||
|
[[ "$FAILED" == "false" ]] || exit 1
|
||||||
exit 0
|
exit 0
|
||||||
|
|||||||
@ -5,7 +5,7 @@ use warnings;
|
|||||||
use Exporter 'import';
|
use Exporter 'import';
|
||||||
|
|
||||||
use PVE::PVEMod::Config qw(%config $process_type $pve_mod_working_dir);
|
use PVE::PVEMod::Config qw(%config $process_type $pve_mod_working_dir);
|
||||||
use PVE::PVEMod::Utils qw(debug check_executable setup_collector_signals safe_write_json);
|
use PVE::PVEMod::Utils qw(debug check_executable setup_collector_signals safe_read_json safe_write_json);
|
||||||
use PVE::PVEMod::Store qw(update_intel_gpu_rrd);
|
use PVE::PVEMod::Store qw(update_intel_gpu_rrd);
|
||||||
|
|
||||||
our @EXPORT_OK = qw(
|
our @EXPORT_OK = qw(
|
||||||
@ -20,26 +20,44 @@ our @EXPORT_OK = qw(
|
|||||||
sub get_intel_gpu_devices {
|
sub get_intel_gpu_devices {
|
||||||
my @devices = ();
|
my @devices = ();
|
||||||
|
|
||||||
debug(__LINE__, "Getting Intel GPU devices");
|
if ($config{debug}{intel_mode} && -f $config{debug}{intel_devices_file}) {
|
||||||
if (open my $fh, '-|', 'intel_gpu_top -L') {
|
debug(__LINE__, "Debug mode: reading Intel GPU devices from $config{debug}{intel_devices_file}");
|
||||||
while (<$fh>) {
|
my $data = safe_read_json($config{debug}{intel_devices_file});
|
||||||
chomp;
|
if ($data && ref $data eq 'ARRAY') {
|
||||||
# Parse: "card0 Intel Alderlake_n (Gen12) pci:vendor=8086,device=46D0,card=0"
|
for my $dev (@$data) {
|
||||||
# or: "card0 Intel Alderlake_n (Gen12) pci:0000:00:02.0"
|
|
||||||
if (/^(card\d+)\s+(.+?)\s+(pci:[^\s]+)/) {
|
|
||||||
my ($card, $name, $path) = ($1, $2, $3);
|
|
||||||
push @devices, {
|
push @devices, {
|
||||||
card => $card,
|
card => $dev->{card},
|
||||||
name => $name,
|
name => $dev->{name},
|
||||||
path => $path,
|
path => $dev->{path},
|
||||||
drm_path => "/dev/dri/$card",
|
drm_path => $dev->{drm_path},
|
||||||
};
|
};
|
||||||
debug(__LINE__, "Found Intel device: $card -> $name ($path)");
|
debug(__LINE__, "Found Intel device (debug): $dev->{card} -> $dev->{name} ($dev->{path})");
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
debug(__LINE__, "Failed to parse debug file $config{debug}{intel_devices_file}");
|
||||||
}
|
}
|
||||||
close $fh;
|
|
||||||
} else {
|
} else {
|
||||||
debug(__LINE__, "Failed to run intel_gpu_top -L: $!");
|
debug(__LINE__, "Getting Intel GPU devices");
|
||||||
|
if (open my $fh, '-|', 'intel_gpu_top -L') {
|
||||||
|
while (<$fh>) {
|
||||||
|
chomp;
|
||||||
|
# Parse: "card0 Intel Alderlake_n (Gen12) pci:vendor=8086,device=46D0,card=0"
|
||||||
|
# or: "card0 Intel Alderlake_n (Gen12) pci:0000:00:02.0"
|
||||||
|
if (/^(card\d+)\s+(.+?)\s+(pci:[^\s]+)/) {
|
||||||
|
my ($card, $name, $path) = ($1, $2, $3);
|
||||||
|
push @devices, {
|
||||||
|
card => $card,
|
||||||
|
name => $name,
|
||||||
|
path => $path,
|
||||||
|
drm_path => "/dev/dri/$card",
|
||||||
|
};
|
||||||
|
debug(__LINE__, "Found Intel device: $card -> $name ($path)");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
close $fh;
|
||||||
|
} else {
|
||||||
|
debug(__LINE__, "Failed to run intel_gpu_top -L: $!");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return @devices;
|
return @devices;
|
||||||
@ -132,46 +150,81 @@ sub collector_for_intel_device {
|
|||||||
if defined $intel_gpu_top_pid && $intel_gpu_top_pid > 0;
|
if defined $intel_gpu_top_pid && $intel_gpu_top_pid > 0;
|
||||||
});
|
});
|
||||||
|
|
||||||
debug(__LINE__, "About to open pipe to intel_gpu_top");
|
|
||||||
my $intel_pull_interval = $config{intervals}{data_pull} * 1000; # milliseconds
|
|
||||||
$intel_gpu_top_pid = open(my $fh, '-|',
|
|
||||||
"intel_gpu_top -d $drm_dev -s $intel_pull_interval -l 2>&1");
|
|
||||||
|
|
||||||
unless (defined $intel_gpu_top_pid && $intel_gpu_top_pid > 0) {
|
|
||||||
debug(__LINE__, "Failed to run intel_gpu_top for $drm_dev: $!");
|
|
||||||
exit 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
debug(__LINE__, "Pipe opened successfully, PID=$intel_gpu_top_pid");
|
|
||||||
|
|
||||||
my $node_name = "node0";
|
my $node_name = "node0";
|
||||||
|
|
||||||
while (my $line = <$fh>) {
|
if ($config{debug}{intel_mode} && -f $config{debug}{intel_output_file}) {
|
||||||
last if $shutdown;
|
debug(__LINE__, "Debug mode: reading Intel GPU stats from $config{debug}{intel_output_file}");
|
||||||
chomp $line;
|
while (!$shutdown) {
|
||||||
|
if (open my $fh, '<', $config{debug}{intel_output_file}) {
|
||||||
|
while (my $line = <$fh>) {
|
||||||
|
chomp $line;
|
||||||
|
next if $line =~ /MHz|IRQ|RC6|Power|RCS|BCS|VCS|VECS|req\s+act|^\s*$/;
|
||||||
|
|
||||||
next if $line =~ /MHz|IRQ|RC6|Power|RCS|BCS|VCS|VECS|req\s+act|^\s*$/;
|
if ($line =~ /^\s*[\d\s\.]+$/) {
|
||||||
|
my $stats = _parse_intel_gpu_line($line);
|
||||||
|
|
||||||
if ($line =~ /^\s*[\d\s\.]+$/) {
|
if ($stats) {
|
||||||
my $stats = _parse_intel_gpu_line($line);
|
my $device_data = {
|
||||||
|
$node_name => {
|
||||||
|
name => $device->{name},
|
||||||
|
device_path => $device->{path},
|
||||||
|
drm_path => $device->{drm_path},
|
||||||
|
stats => $stats,
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
if ($stats) {
|
safe_write_json($device_state_file, $device_data);
|
||||||
my $device_data = {
|
update_intel_gpu_rrd($device->{card}, $stats);
|
||||||
$node_name => {
|
}
|
||||||
name => $device->{name},
|
|
||||||
device_path => $device->{path},
|
|
||||||
drm_path => $device->{drm_path},
|
|
||||||
stats => $stats,
|
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
|
close $fh;
|
||||||
|
} else {
|
||||||
|
debug(__LINE__, "Failed to open debug file $config{debug}{intel_output_file}: $!");
|
||||||
|
}
|
||||||
|
sleep $config{intervals}{data_pull} unless $shutdown;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
debug(__LINE__, "About to open pipe to intel_gpu_top");
|
||||||
|
my $intel_pull_interval = $config{intervals}{data_pull} * 1000; # milliseconds
|
||||||
|
$intel_gpu_top_pid = open(my $fh, '-|',
|
||||||
|
"intel_gpu_top -d $drm_dev -s $intel_pull_interval -l 2>&1");
|
||||||
|
|
||||||
safe_write_json($device_state_file, $device_data);
|
unless (defined $intel_gpu_top_pid && $intel_gpu_top_pid > 0) {
|
||||||
update_intel_gpu_rrd($device->{card}, $stats);
|
debug(__LINE__, "Failed to run intel_gpu_top for $drm_dev: $!");
|
||||||
|
exit 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
debug(__LINE__, "Pipe opened successfully, PID=$intel_gpu_top_pid");
|
||||||
|
|
||||||
|
while (my $line = <$fh>) {
|
||||||
|
last if $shutdown;
|
||||||
|
chomp $line;
|
||||||
|
|
||||||
|
next if $line =~ /MHz|IRQ|RC6|Power|RCS|BCS|VCS|VECS|req\s+act|^\s*$/;
|
||||||
|
|
||||||
|
if ($line =~ /^\s*[\d\s\.]+$/) {
|
||||||
|
my $stats = _parse_intel_gpu_line($line);
|
||||||
|
|
||||||
|
if ($stats) {
|
||||||
|
my $device_data = {
|
||||||
|
$node_name => {
|
||||||
|
name => $device->{name},
|
||||||
|
device_path => $device->{path},
|
||||||
|
drm_path => $device->{drm_path},
|
||||||
|
stats => $stats,
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
safe_write_json($device_state_file, $device_data);
|
||||||
|
update_intel_gpu_rrd($device->{card}, $stats);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
close $fh;
|
||||||
}
|
}
|
||||||
|
|
||||||
close $fh;
|
|
||||||
debug(__LINE__, "Collector for $device->{card} shutting down");
|
debug(__LINE__, "Collector for $device->{card} shutting down");
|
||||||
exit 0;
|
exit 0;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -6,7 +6,7 @@ use Exporter 'import';
|
|||||||
|
|
||||||
use JSON;
|
use JSON;
|
||||||
|
|
||||||
use PVE::PVEMod::Config qw($process_type $ups_state_file);
|
use PVE::PVEMod::Config qw(%config $process_type $ups_state_file);
|
||||||
use PVE::PVEMod::Utils qw(debug setup_collector_signals);
|
use PVE::PVEMod::Utils qw(debug setup_collector_signals);
|
||||||
|
|
||||||
our @EXPORT_OK = qw(
|
our @EXPORT_OK = qw(
|
||||||
@ -40,7 +40,7 @@ sub collector_for_ups {
|
|||||||
debug(__LINE__, "Error writing UPS data: $@");
|
debug(__LINE__, "Error writing UPS data: $@");
|
||||||
}
|
}
|
||||||
|
|
||||||
sleep 1 unless $shutdown; # $config{intervals}{data_pull}
|
sleep $config{intervals}{data_pull} unless $shutdown;
|
||||||
}
|
}
|
||||||
|
|
||||||
debug(__LINE__, "UPS collector shutting down");
|
debug(__LINE__, "UPS collector shutting down");
|
||||||
@ -56,7 +56,17 @@ sub _get_ups_status {
|
|||||||
|
|
||||||
debug(__LINE__, "Collecting UPS status for $ups_name");
|
debug(__LINE__, "Collecting UPS status for $ups_name");
|
||||||
|
|
||||||
my $output = `/usr/bin/upsc $ups_name 2>/dev/null`;
|
my $output;
|
||||||
|
if ($config{debug}{ups_mode} && -f $config{debug}{ups_output_file}) {
|
||||||
|
debug(__LINE__, "Debug mode: reading UPS data from $config{debug}{ups_output_file}");
|
||||||
|
open my $fh, '<', $config{debug}{ups_output_file}
|
||||||
|
or do { debug(__LINE__, "Failed to open debug file $config{debug}{ups_output_file}: $!"); return encode_json({ error => "Failed to open debug file" }); };
|
||||||
|
local $/;
|
||||||
|
$output = <$fh>;
|
||||||
|
close $fh;
|
||||||
|
} else {
|
||||||
|
$output = `/usr/bin/upsc $ups_name 2>/dev/null`;
|
||||||
|
}
|
||||||
|
|
||||||
unless (defined $output && length($output) > 0) {
|
unless (defined $output && length($output) > 0) {
|
||||||
debug(__LINE__, "No output from upsc for $ups_name");
|
debug(__LINE__, "No output from upsc for $ups_name");
|
||||||
|
|||||||
@ -44,10 +44,16 @@ sub get_system_information_data {
|
|||||||
sub _get_system_info {
|
sub _get_system_info {
|
||||||
my ($type) = @_;
|
my ($type) = @_;
|
||||||
|
|
||||||
my $output = `/usr/sbin/dmidecode -t $type 2>/dev/null`;
|
my $cache_file = "/var/lib/pve-mod/dmidecode-type${type}.txt";
|
||||||
|
my $output;
|
||||||
|
if (open(my $fh, '<', $cache_file)) {
|
||||||
|
local $/;
|
||||||
|
$output = <$fh>;
|
||||||
|
close($fh);
|
||||||
|
}
|
||||||
|
|
||||||
unless (defined $output && length($output) > 0) {
|
unless (defined $output && length($output) > 0) {
|
||||||
debug(__LINE__, "No output from dmidecode -t $type");
|
debug(__LINE__, "No cached DMI data at $cache_file - re-run pve-mod-configure as root to refresh");
|
||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -20,6 +20,13 @@ our @EXPORT_OK = qw(
|
|||||||
our $DEBUG_ENABLED = 1;
|
our $DEBUG_ENABLED = 1;
|
||||||
our $VERSION = 'version-placeholder';
|
our $VERSION = 'version-placeholder';
|
||||||
|
|
||||||
|
# ============================================================================
|
||||||
|
# Config paths
|
||||||
|
# ============================================================================
|
||||||
|
|
||||||
|
my $CONF_FILE = '/etc/pve-mod/pve-mod.conf';
|
||||||
|
my $CONFD_DIR = '/etc/pve-mod/conf.d';
|
||||||
|
|
||||||
# Runtime process-type tag — set to 'worker' or 'collector' after fork.
|
# Runtime process-type tag — set to 'worker' or 'collector' after fork.
|
||||||
# Each forked child gets its own copy of this variable.
|
# Each forked child gets its own copy of this variable.
|
||||||
our $process_type = 'main'; # 'main', 'worker', or 'collector'
|
our $process_type = 'main'; # 'main', 'worker', or 'collector'
|
||||||
@ -42,6 +49,7 @@ our %config = (
|
|||||||
lm_sensors_output_file => '/tmp/sensors-output.json',
|
lm_sensors_output_file => '/tmp/sensors-output.json',
|
||||||
intel_mode => 0,
|
intel_mode => 0,
|
||||||
intel_devices_file => '/tmp/intel-gpu-devices.json',
|
intel_devices_file => '/tmp/intel-gpu-devices.json',
|
||||||
|
intel_output_file => '/tmp/intel-gpu-output.json',
|
||||||
nvidia_mode => 0,
|
nvidia_mode => 0,
|
||||||
nvidia_devices_file => '/tmp/nvidia-smi-devices.csv',
|
nvidia_devices_file => '/tmp/nvidia-smi-devices.csv',
|
||||||
nvidia_output_file => '/tmp/nvidia-smi-output.csv',
|
nvidia_output_file => '/tmp/nvidia-smi-output.csv',
|
||||||
@ -104,8 +112,8 @@ our $RRD_BASE = '/var/lib/rrdcached/db/pve-mod-gpu';
|
|||||||
# ============================================================================
|
# ============================================================================
|
||||||
|
|
||||||
sub _load_ini_file {
|
sub _load_ini_file {
|
||||||
my $path = '/etc/pve-mod/pve-mod.conf';
|
my ($path) = @_;
|
||||||
return unless -f $path;
|
return unless defined $path && -f $path;
|
||||||
|
|
||||||
open my $fh, '<', $path or return;
|
open my $fh, '<', $path or return;
|
||||||
my $section = '';
|
my $section = '';
|
||||||
@ -146,6 +154,7 @@ sub _load_ini_file {
|
|||||||
close $fh;
|
close $fh;
|
||||||
}
|
}
|
||||||
|
|
||||||
_load_ini_file();
|
_load_ini_file($CONF_FILE);
|
||||||
|
_load_ini_file($_) for glob("$CONFD_DIR/*.conf");
|
||||||
|
|
||||||
1;
|
1;
|
||||||
|
|||||||
@ -149,8 +149,12 @@ sub _load_graphics_data {
|
|||||||
# API calls
|
# API calls
|
||||||
# ============================================================================
|
# ============================================================================
|
||||||
|
|
||||||
sub get_graphic_info {
|
sub get_graphics_info {
|
||||||
debug(__LINE__, "get_graphic_info called");
|
debug(__LINE__, "get_graphics_info called");
|
||||||
|
if (!($config{gpu}{intel_enabled} || !$config{gpu}{nvidia_enabled} || !$config{gpu}{amd_enabled})) {
|
||||||
|
debug(__LINE__, "GPU information collection is disabled");
|
||||||
|
return { };
|
||||||
|
}
|
||||||
|
|
||||||
# Start PVE Mod
|
# Start PVE Mod
|
||||||
pve_mod_starter();
|
pve_mod_starter();
|
||||||
@ -165,6 +169,10 @@ sub get_graphic_info {
|
|||||||
|
|
||||||
sub get_sensors_info {
|
sub get_sensors_info {
|
||||||
debug(__LINE__, "get_sensors_info called");
|
debug(__LINE__, "get_sensors_info called");
|
||||||
|
if (!$config{lm_sensors}{enabled}) {
|
||||||
|
debug(__LINE__, "LM Sensors collection is disabled");
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
# Start PVE Mod
|
# Start PVE Mod
|
||||||
pve_mod_starter();
|
pve_mod_starter();
|
||||||
@ -179,6 +187,10 @@ sub get_sensors_info {
|
|||||||
|
|
||||||
sub get_ups_info {
|
sub get_ups_info {
|
||||||
debug(__LINE__, "get_ups_info called");
|
debug(__LINE__, "get_ups_info called");
|
||||||
|
if (!$config{ups}{enabled}) {
|
||||||
|
debug(__LINE__, "UPS collection is disabled");
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
# Start PVE Mod
|
# Start PVE Mod
|
||||||
pve_mod_starter();
|
pve_mod_starter();
|
||||||
|
|||||||
@ -1000,7 +1000,21 @@ Ext.define('PVE.node.StatusView', {
|
|||||||
if (value === null || value === undefined) {
|
if (value === null || value === undefined) {
|
||||||
return '';
|
return '';
|
||||||
}
|
}
|
||||||
return value;
|
|
||||||
|
const titleMap = {
|
||||||
|
manufacturer: 'Manufacturer',
|
||||||
|
product_name: 'Product Name',
|
||||||
|
serial_number: 'Serial Number',
|
||||||
|
};
|
||||||
|
|
||||||
|
let parts = [];
|
||||||
|
['manufacturer', 'product_name', 'serial_number'].forEach(function(key) {
|
||||||
|
if (value[key] !== undefined && value[key] !== null) {
|
||||||
|
parts.push(titleMap[key] + ': ' + value[key]);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
return parts.length > 0 ? parts.join(' | ') : '';
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
],
|
],
|
||||||
|
|||||||
@ -8,7 +8,7 @@ use File::Path qw(make_path);
|
|||||||
use PVE::INotify;
|
use PVE::INotify;
|
||||||
use RRDs;
|
use RRDs;
|
||||||
|
|
||||||
use PVE::PVEMod::Config qw($RRD_SOCKET $RRD_BASE);
|
use PVE::PVEMod::Config qw(%config $RRD_SOCKET $RRD_BASE);
|
||||||
use PVE::PVEMod::Utils qw(debug);
|
use PVE::PVEMod::Utils qw(debug);
|
||||||
|
|
||||||
our @EXPORT_OK = qw(
|
our @EXPORT_OK = qw(
|
||||||
@ -40,6 +40,8 @@ sub gpu_rrd_path {
|
|||||||
# ============================================================================
|
# ============================================================================
|
||||||
|
|
||||||
sub _ensure_intel_gpu_rrd {
|
sub _ensure_intel_gpu_rrd {
|
||||||
|
return unless $config{gpu}{gpu_history};
|
||||||
|
|
||||||
my ($card) = @_;
|
my ($card) = @_;
|
||||||
my $path = gpu_rrd_path($card);
|
my $path = gpu_rrd_path($card);
|
||||||
return if -f $path;
|
return if -f $path;
|
||||||
@ -104,6 +106,8 @@ sub update_intel_gpu_rrd {
|
|||||||
# ============================================================================
|
# ============================================================================
|
||||||
|
|
||||||
sub _ensure_nvidia_gpu_rrd {
|
sub _ensure_nvidia_gpu_rrd {
|
||||||
|
return unless $config{gpu}{gpu_history};
|
||||||
|
|
||||||
my ($index) = @_;
|
my ($index) = @_;
|
||||||
my $card = "nvidia$index";
|
my $card = "nvidia$index";
|
||||||
my $path = gpu_rrd_path($card);
|
my $path = gpu_rrd_path($card);
|
||||||
|
|||||||
@ -215,6 +215,10 @@ sub safe_write_json {
|
|||||||
my ($filepath, $data, $pretty) = @_;
|
my ($filepath, $data, $pretty) = @_;
|
||||||
$pretty //= 1;
|
$pretty //= 1;
|
||||||
|
|
||||||
|
# Untaint filepath for taint-mode environments (pveproxy runs with -T)
|
||||||
|
($filepath) = ($filepath =~ /^([a-zA-Z0-9_\/\-\.]+)$/)
|
||||||
|
or do { debug(__LINE__, "Unsafe filepath rejected: $filepath"); return 0; };
|
||||||
|
|
||||||
eval {
|
eval {
|
||||||
open my $fh, '>', $filepath or die "Failed to open $filepath: $!";
|
open my $fh, '>', $filepath or die "Failed to open $filepath: $!";
|
||||||
my $json = $pretty ? JSON->new->pretty->encode($data) : encode_json($data);
|
my $json = $pretty ? JSON->new->pretty->encode($data) : encode_json($data);
|
||||||
@ -232,6 +236,10 @@ sub safe_write_json {
|
|||||||
sub safe_read_json {
|
sub safe_read_json {
|
||||||
my ($filepath, $as_string) = @_;
|
my ($filepath, $as_string) = @_;
|
||||||
|
|
||||||
|
# Untaint filepath
|
||||||
|
($filepath) = ($filepath =~ /^([a-zA-Z0-9_\/\-\.]+)$/)
|
||||||
|
or return;
|
||||||
|
|
||||||
return unless -f $filepath;
|
return unless -f $filepath;
|
||||||
|
|
||||||
my $result;
|
my $result;
|
||||||
|
|||||||
@ -34,6 +34,7 @@ lm_sensors_mode=0
|
|||||||
lm_sensors_output_file=/tmp/sensors-output.json
|
lm_sensors_output_file=/tmp/sensors-output.json
|
||||||
intel_mode=0
|
intel_mode=0
|
||||||
intel_devices_file=/tmp/intel-gpu-devices.json
|
intel_devices_file=/tmp/intel-gpu-devices.json
|
||||||
|
intel_output_file=/tmp/intel-gpu-output.txt
|
||||||
nvidia_mode=0
|
nvidia_mode=0
|
||||||
nvidia_devices_file=/tmp/nvidia-smi-devices.csv
|
nvidia_devices_file=/tmp/nvidia-smi-devices.csv
|
||||||
nvidia_output_file=/tmp/nvidia-smi-output.csv
|
nvidia_output_file=/tmp/nvidia-smi-output.csv
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
--- a/usr/share/perl5/PVE/API2/Nodes.pm
|
--- a/usr/share/perl5/PVE/API2/Nodes.pm
|
||||||
+++ b/usr/share/perl5/PVE/API2/Nodes.pm
|
+++ b/usr/share/perl5/PVE/API2/Nodes.pm
|
||||||
@@ -536,6 +536,12 @@
|
@@ -536,6 +536,13 @@
|
||||||
|
|
||||||
$res->{pveversion} = PVE::pvecfg::package() . "/" . PVE::pvecfg::version_text();
|
$res->{pveversion} = PVE::pvecfg::package() . "/" . PVE::pvecfg::version_text();
|
||||||
|
|
||||||
@ -9,7 +9,8 @@
|
|||||||
+ $res->{PveMod_JsonSensorInfo} = PVE::API2::PVEMod_SensorInfo::get_sensors_info();
|
+ $res->{PveMod_JsonSensorInfo} = PVE::API2::PVEMod_SensorInfo::get_sensors_info();
|
||||||
+ $res->{PveMod_Version} = PVE::API2::PVEMod_SensorInfo::get_pve_mod_version();
|
+ $res->{PveMod_Version} = PVE::API2::PVEMod_SensorInfo::get_pve_mod_version();
|
||||||
+ $res->{PveMod_upsInfo} = PVE::API2::PVEMod_SensorInfo::get_ups_info();
|
+ $res->{PveMod_upsInfo} = PVE::API2::PVEMod_SensorInfo::get_ups_info();
|
||||||
+ $res->{PveMod_systemInfo} = PVE::API2::PVEMod_SensorInfo::get_system_info();
|
+ $res->{PveMod_graphicsInfo} = PVE::API2::PVEMod_SensorInfo::get_graphics_info();
|
||||||
|
+ $res->{PveMod_systemInfo} = PVE::API2::PVEMod_SensorInfo::get_system_information();
|
||||||
my $dinfo = df('/', 1); # output is bytes
|
my $dinfo = df('/', 1); # output is bytes
|
||||||
|
|
||||||
$res->{rootfs} = {
|
$res->{rootfs} = {
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user