self-diagnostics: Self diagnostics report

This commit is contained in:
Vivek Kumar Dutta 2023-11-02 12:15:17 +05:30
parent 002dceac35
commit 1623fb6559
No known key found for this signature in database
GPG key ID: 65C818099F37097D
13 changed files with 836 additions and 0 deletions

35
self-diagnostics/Makefile Normal file
View file

@ -0,0 +1,35 @@
include $(TOPDIR)/rules.mk
PKG_NAME:=self-diagnostics
PKG_VERSION:=1.0.0
PKG_RELEASE:=1
PKG_LICENSE:=GPL-2.0-only
include $(INCLUDE_DIR)/package.mk
define Package/self-diagnostics
CATEGORY:=Utilities
TITLE:=System Report
DEPENDS:=+@CONFIG_BUSYBOX_CONFIG_TIMEOUT +@CONFIG_BUSYBOX_CONFIG_FEATURE_FIND_PATH +@CONFIG_BUSYBOX_CONFIG_TEE \
+@CONFIG_BUSYBOX_CONFIG_GZIP
endef
define Package/self-diagnostics/description
Generate Self test diagnostics report
endef
#define Build/Prepare
# mkdir -p $(PKG_BUILD_DIR)
# $(CP) ./files/* $(PKG_BUILD_DIR)/
#endef
define Build/Compile
endef
define Package/self-diagnostics/install
$(INSTALL_DIR) $(1)/etc/self-diagnostics/spec/
$(CP) ./files/* $(1)/
endef
$(eval $(call BuildPackage,self-diagnostics))

View file

@ -0,0 +1,6 @@
config globals 'globals'
option extended_spec_dir '/etc/self-diagnostics/spec'
option exec_timeout '5'
option report_name 'self-diagnostics-report-$MODEL-$SERIAL'
option verbose '0'
option compression_level '9'

View file

@ -0,0 +1,28 @@
#!/bin/sh
BIN="/usr/sbin/self-diagnostics"
. /usr/share/libubox/jshn.sh
case "$1" in
list)
echo '{"list": {}, "generate" : {"modules":"String"}}'
;;
call)
case "$2" in
generate)
read -t 1 -r input
json_load "${input}"
json_get_var modules modules
if [ -z "${modules}" ]; then
${BIN} -j
else
${BIN} -j -m "${modules}"
fi
;;
list)
${BIN} -j -l
;;
esac
;;
esac

View file

@ -0,0 +1,373 @@
#!/bin/sh
. /usr/share/libubox/jshn.sh
JSON_OUT=0
SPEC_DIR="/usr/share/self-diagnostics/spec"
SPEC_EXT_DIR="/etc/self-diagnostics/spec"
REPORT_DIR="$(mktemp -d)"
REPORT_NAME="self-test-diagnostics"
VERBOSE=0
COMPOPTS=""
TIMEOUT=5
cleanup()
{
[ -d "${REPORT_DIR}" ] && \
rm -rf ${REPORT_DIR}
}
trap cleanup EXIT
help()
{
echo "Generate self diagnostics report"
echo
echo "Syntax: $0 [-m|h|l|j]"
echo
echo "Options:"
echo " l List available module(s)"
echo " m Generate system report of specific module(s)"
echo " j Enable JSON output"
echo " h Print this help"
echo
}
log()
{
log_file="${REPORT_DIR}/execution.log"
if [ "$VERBOSE" -eq 1 ]; then
logger -t $0 "$*"
fi
echo "[$(date +%Y:%m:%d-%H:%M:%S)] $*" >> ${log_file}
}
# Alias ubus to have a smaller 5-second timeout on all subsequent calls
ubus()
{
if [ "${1}" == "call" ]; then
if command ubus list $2 >/dev/null 2>&1; then
command ubus "$@";
fi
else
command ubus "$@";
fi
}
config_load()
{
local temp
local MODEL SERIAL
log "# Starting Self diagnostics tests #"
MODEL="$(db get device.deviceinfo.ModelName)"
SERIAL="$(db get device.deviceinfo.SerialNumber)"
temp="$(uci -q get self-diagnostics.globals.extended_spec_dir)"
[ -d "${temp}" ] && \
SPEC_EXT_DIR="${temp}"
temp="$(uci -q get self-diagnostics.globals.exec_timeout)"
[ -n "${temp}" ] && \
TIMEOUT="${temp}"
temp="$(uci -q get self-diagnostics.globals.report_name)"
[ -n "${temp}" ] && \
REPORT_NAME="$(eval echo ${temp})"
REPORT_NAME="${REPORT_NAME// /_}"
temp="$(uci -q get self-diagnostics.globals.compression_level)"
[ -n "${temp}" ] && \
COMPOPTS="${temp}"
temp="$(uci -q get self-diagnostics.globals.verbose)"
[ -n "${temp}" ] && \
VERBOSE="${temp}"
}
exec_spec()
{
local json_file exec_skip name timeout exec_timeout rc
json_file="$1"
[ -z "$json_file" ] && {
log "No/invalid spec json_file"
return 1
}
log "Loading $json_file ..."
json_init
json_load_file "${json_file}" || {
log "Failed to load ${json_file} spec file"
return 1
}
name="$(basename ${json_file})"
export_path="${REPORT_DIR}/${name//.json/.log}"
exec_skip=0
if json_is_a dependency array; then
json_select "dependency"
json_get_keys ekeys
for key in $ekeys; do
if json_is_a $key object; then
json_select $key
json_get_var type type
if [ "$type" == "file" ]; then
json_get_var file file
if [ ! -e "$file" ]; then
log "${json_file} has unmet file dependency $file"
exec_skip=1
json_select ..
continue
fi
fi
json_select ..
fi
done
json_select ..
fi
[ "${exec_skip}" -eq 1 ] && {
log "Dependency not satisfied for ${json_file}"
return 0
}
json_get_var description description
log "Description: $description"
if json_is_a exec array; then
json_select "exec"
json_get_keys keys
for key in $keys; do
if json_is_a $key object; then
json_select $key
cmd_skip=0
if json_is_a dependency array; then
json_select "dependency"
json_get_keys d_keys
for d_key in $d_keys; do
if json_is_a $d_key object; then
json_select $d_key
json_get_var type type
if [ "$type" == "file" ]; then
json_get_var file file
if [ ! -e $file ]; then
json_select ..
cmd_skip=1
continue
fi
fi
json_select ..
fi
done
json_select ..
fi
[ $cmd_skip -eq 1 ] && {
json_select ..
log "Dependency not satisfied for ${file}"
continue
}
json_get_var description description
json_get_var cmd cmd
json_get_var timeout timeout
if [ -n "$timeout" ]; then
exec_timeout=$timeout
else
exec_timeout=$TIMEOUT
fi
log "Executing $cmd with timeout $exec_timeout"
echo "##################" >> $export_path
echo $description >> $export_path
echo "##################" >> $export_path
if [ "$VERBOSE" -eq 1 ]; then
eval timeout ${exec_timeout} $cmd 2>&1 | tee -a $export_path | logger -t self-diagnostics
rc=$?
else
eval timeout ${exec_timeout} $cmd >> $export_path 2>&1
rc=$?
fi
if [ "$rc" -eq 0 ]; then
log "Execution [$cmd] completed"
else
log "Execution [$cmd] Failed/Timeout with $rc exit code"
fi
echo >> $export_path
json_select ..
fi
done
json_select ..
fi
}
generate_module()
{
local modules="${@}"
local file module
config_load
log "Modules [$@]"
for module in $modules; do
module="${module/.json/}"
file="$(find $SPEC_DIR -type f -name ${module}.json)"
[ -z "$file" ] && {
[ -d "${SPEC_EXT_DIR}" ] && \
file="$(find $SPEC_EXT_DIR -type f -name ${file}.json)"
}
[ -f "$file" ] && \
exec_spec "$file"
done
}
generate_all()
{
local files
config_load
files="$(find ${SPEC_DIR} -type f -name *.json)"
[ -d "${SPEC_EXT_DIR}" ] && \
files="${files} $(find $SPEC_EXT_DIR -type f -name *.json)"
[ -z "$files" ] && {
return 0
}
for file in $files; do
exec_spec "$file"
done
}
list_modules()
{
local files
if [ "${JSON_OUT}" -eq 1 ]; then
json_init
json_add_array "CoreModules"
else
echo
echo "Core Module(s):"
fi
cd ${SPEC_DIR} && {
for file in $(ls); do
if [ "${JSON_OUT}" -eq 1 ]; then
json_add_string "" "${file/.json/}"
else
echo " - ${file/.json/}"
fi
done
}
if [ "${JSON_OUT}" -eq 1 ]; then
json_close_array
json_add_array "ExtensionModules"
else
echo
echo "Extension Module(s):"
fi
cd ${SPEC_EXT_DIR} && {
for file in $(ls); do
if [ "${JSON_OUT}" -eq 1 ]; then
json_add_string "" "${file/.json/}"
else
echo " - ${file/.json/}"
fi
done
}
if [ "${JSON_OUT}" -eq 1 ]; then
json_close_array
json_dump
else
echo
fi
}
generate_report()
{
local filename report_path
report_path="$(dirname "${REPORT_DIR}")"
filename="${report_path}/${REPORT_NAME}"
[ -f "${filename}.tar" ] && rm "${filename}.tar"
[ -f "${filename}.tar.gz" ] && rm "${filename}.tar.gz"
log "# Report generation completed #"
cd ${REPORT_DIR} && {
filename="${filename}.tar"
tar -cf "${filename}" *
}
rm -r "$REPORT_DIR"
if [ -n "$COMPOPTS" ]; then
gzip -${COMPOPTS} -f "${filename}"
filename="${filename}.gz"
fi
if [ "${JSON_OUT}" -eq 1 ]; then
json_init
json_add_string result "${filename}"
json_dump
else
echo "${filename}"
fi
}
[ ! -d "${SPEC_DIR}" ] && {
log "# ${SPEC_DIR} does not exits"
exit 1
}
list=0
modules=""
while getopts "m:hlj" opts; do
case $opts in
h)
help
exit;;
j)
JSON_OUT=1
;;
l)
list=1
;;
m)
modules="$modules ${OPTARG}"
;;
esac
done
if [ "${list}" -eq 1 ]; then
list_modules
exit 0
fi
if [ -z "${modules}" ]; then
generate_all
else
generate_module ${modules}
fi
generate_report

View file

@ -0,0 +1,11 @@
interfaces=$(uci show wireless | grep "ifname=" | awk -F'[.,=]' '{print$2}')
for int in $interfaces; do
mode=$(uci get "wireless.${int}.mode")
if [ "$mode" = "ap" ] ; then
ap_int=$(uci get "wireless.${int}.ifname")
echo "Get assoc list for ${ap_int}"
ubus call "wifi.ap.${ap_int}" assoclist
echo "Get station info for ${ap_int}"
ubus call "wifi.ap.${ap_int}" stations
fi
done

View file

@ -0,0 +1,5 @@
for radio_if in $(ubus list 'wifi.radio.*'); do
ubus call "${radio_if}" scan
sleep 2
ubus call "${radio_if}" scanresults
done

View file

@ -0,0 +1,29 @@
{
"description": "Gathering configuration data",
"exec" : [
{
"description": "OS Release",
"cmd": "cat /etc/os-release"
},
{
"description": "Installed Packages",
"cmd": "opkg list-installed"
},
{
"description": "Database",
"cmd": "db export"
},
{
"description": "Configuration",
"cmd": "uci export"
},
{
"description": "Runtime Configuration",
"cmd": "cat /var/state/*"
},
{
"description": "Firmware Environment",
"cmd": "fw_printenv"
}
]
}

View file

@ -0,0 +1,63 @@
{
"description": "Gathering EasyMesh state",
"dependency" : [
{
"type": "file",
"file": "/etc/config/mapagent"
},
{
"type": "file",
"file": "/etc/config/ieee1905"
}
],
"exec" : [
{
"description": "IEEE1905 Info",
"cmd": "ubus call ieee1905 info"
},
{
"description": "IEEE1905 Links",
"cmd": "ubus call ieee1905 links"
},
{
"description": "IEEE1905 Neighbors",
"cmd": "ubus call ieee1905 neighbors"
},
{
"description": "IEEE1905 Others",
"cmd": "ubus call ieee1905 others"
},
{
"description": "IEEE1905 Topology",
"cmd": "ubus call ieee1905.topology dump"
},
{
"description": "MAP Agent Info",
"cmd": "ubus call map.agent info"
},
{
"description": "MAP Agent Status",
"cmd": "ubus call map.agent status"
},
{
"description": "MAP Agent Backhaul Info",
"cmd": "ubus call map.agent backhaul_info"
},
{
"description": "MAP Controller Status",
"cmd": "ubus call map.controller status"
},
{
"description": "MAP Controller List MACs",
"cmd": "ubus call map.controller.dbg list_macs"
},
{
"description": "MAP Controller BH Topology Dump",
"cmd": "ubus call map.controller.dbg bh_topology_dump"
},
{
"description": "Data Elements Dump",
"cmd": "ubus call wifi.dataelements.collector refresh; sleep 2; ubus call wifi.dataelements.collector dump2"
}
]
}

View file

@ -0,0 +1,89 @@
{
"description": "Gathering network state",
"exec" : [
{
"description": "Network Device Status",
"cmd": "ubus call network.device status"
},
{
"description": "Network Interface Dump",
"cmd": "ubus call network.interface dump"
},
{
"description": "Linux Network Interface Config",
"cmd": "ifconfig -a"
},
{
"description": "IPv4 Routes",
"cmd": "ip -d r"
},
{
"description": "IPv6 Routes",
"cmd": "ip -d -6 r"
},
{
"description": "Neighbor Table",
"cmd": "ip n"
},
{
"description": "ARP Table",
"cmd": "cat /proc/net/arp"
},
{
"description": "Conntrack Table",
"cmd": "cat /proc/net/nf_conntrack"
},
{
"description": "Network Interface Status",
"cmd": "ip -d a"
},
{
"description": "IPv4 Firewall Status",
"cmd": "iptables -xvnL"
},
{
"description": "IPv6 Firewall Status",
"cmd": "ip6tables -xvnL"
},
{
"description": "Bridge Info",
"cmd": "brctl show"
},
{
"description": "Bridge Link",
"cmd": "bridge link"
},
{
"description": "Bridge VLAN",
"cmd": "bridge vlan"
},
{
"description": "Bridge FDB",
"cmd": "bridge fdb"
},
{
"description": "TCP listened ports",
"cmd": "netstat -tlnp"
},
{
"description": "UDP listened ports",
"cmd": "netstat -ulnp"
},
{
"description": "MAC layer firewall status list",
"cmd": "ebtables -L"
},
{
"description": "MAC layer firewall status",
"cmd": "ebtables -t broute -L"
},
{
"description": "QoS queue stats",
"cmd": "ubus call qos queue_stats"
},
{
"description": "IGMP Snooping Table",
"cmd": "ubus call mcast stats"
}
]
}

View file

@ -0,0 +1,67 @@
{
"description": "Gathering system information",
"exec" : [
{
"description": "Firmware banks",
"cmd": "ubus call fwbank dump"
},
{
"description": "System Info",
"cmd": "ubus call system info"
},
{
"description": "Board Info",
"cmd": "ubus call system board"
},
{
"description": "Running Processes",
"cmd": "top -b -n 1"
},
{
"description": "Kernel Parameters",
"cmd": "sysctl -A 2>/dev/null"
},
{
"description": "System Log",
"cmd": "timeout 5 logread -l 1000"
},
{
"description": "Driver Message",
"cmd": "timeout 5 dmesg"
},
{
"description": "PCI Devices",
"cmd": "lspci -k"
},
{
"description": "Installed Modules",
"cmd": "lsmod"
},
{
"description": "CPU Info",
"cmd": "cat /proc/cpuinfo"
},
{
"description": "Memory Info",
"cmd": "cat /proc/meminfo"
},
{
"description": "Slab Info",
"cmd": "cat /proc/slabinfo"
},
{
"description": "eMMC Partition/Volume Info",
"cmd": "fdisk -l",
"dependency" : {
"file": "/sbin/fdisk"
}
},
{
"description": "NAND Partition/Volume Info",
"cmd": "ubinfo --all",
"dependency" : {
"file": "/usr/sbin/ubinfo"
}
}
]
}

View file

@ -0,0 +1,56 @@
{
"description": "Gathering TR-x69 state",
"dependency" : [
{
"type": "file",
"file": "/etc/config/cwmp"
}
],
"exec" : [
{
"description": "TR-181 DM MAP",
"cmd": "uci -c /etc/bbfdm/dmmap export"
},
{
"description": "TR-181 Parameters via BBFDM",
"cmd": "bbfdmd -c get Device."
},
{
"description": "TR-181 Parameters via CWMP",
"cmd": "icwmpd -c get Device."
},
{
"description": "TR-069 status",
"cmd": "ubus call tr069 status"
},
{
"description": "TR-069 Logs",
"cmd": "cat /var/log/icwmpd.log",
"dependency" : [
{
"type": "file",
"file": "/var/log/icwmpd.log"
}
]
},
{
"description": "TR-181 Parameters via USP",
"cmd": "obuspa -c get Device.",
"timeout": 10
},
{
"description": "USP Agent Database",
"cmd": "obuspa -f $(uci -q get obuspa.global.db_file) -c show database"
},
{
"description": "USP Logs",
"cmd": "cat /var/log/obuspa.log",
"dependency" : [
{
"type": "file",
"file": "/var/log/obuspa.log"
}
]
}
]
}

View file

@ -0,0 +1,43 @@
{
"description": "Gathering Voice state",
"dependency" : [
{
"type": "file",
"file": "/etc/config/asterisk"
}
],
"exec" : [
{
"description": "Endpoint Status",
"cmd": "ubus call endpt status"
},
{
"description": "Endpoint Count",
"cmd": "ubus call endpt count"
},
{
"description": "Voice Status",
"cmd": "ubus call voice.asterisk status"
},
{
"description": "DECT Status",
"cmd": "ubus call dect status",
"dependency" : [
{
"type": "file",
"file": "/etc/config/dect"
}
]
},
{
"description": "DECT Handsets",
"cmd": "ubus call dect handsets",
"dependency" : [
{
"type": "file",
"file": "/etc/config/dect"
}
]
}
]
}

View file

@ -0,0 +1,31 @@
{
"description": "Gathering WiFi state",
"dependency" : [
{
"type": "file",
"file": "/sys/class/ieee80211"
}
],
"exec" : [
{
"description": "Wireless Status",
"cmd": "ubus call network.wireless status"
},
{
"description": "Wireless Radio Status",
"cmd": "ubus call wifi status"
},
{
"description": "Get radio scan",
"cmd": "sh /usr/share/self-diagnostics/helper/wifi_radio_scan.sh"
},
{
"description": "Get Assoc List",
"cmd": "sh /usr/share/self-diagnostics/helper/wifi_assoclist.sh"
},
{
"description": "iwinfo interface details",
"cmd": "/usr/bin/iwinfo"
}
]
}