secubox-openwrt/luci-app-system-hub/root/usr/libexec/rpcd/system-hub

754 lines
23 KiB
Bash
Executable File

#!/bin/sh
# SPDX-License-Identifier: Apache-2.0
# System Hub - Central Control & Remote Assistance RPCD Backend
# Copyright (C) 2024 CyberMind.fr - Gandalf
. /lib/functions.sh
. /usr/share/libubox/jshn.sh
CONFIG_FILE="/etc/config/system-hub"
LOG_FILE="/var/log/system-hub.log"
REPORTS_DIR="/etc/system-hub/reports"
DIAG_DIR="/etc/system-hub/diagnostics"
# Logging function
log_event() {
local level="$1"
local message="$2"
local timestamp=$(date '+%Y-%m-%d %H:%M:%S')
echo "[$timestamp] [$level] $message" >> "$LOG_FILE"
}
# Get system overview status
get_status() {
json_init
local enabled=$(uci -q get system-hub.config.enabled || echo "1")
json_add_boolean "enabled" "$enabled"
# System info
json_add_object "system"
json_add_string "hostname" "$(uci -q get system.@system[0].hostname || hostname)"
json_add_string "model" "$(cat /tmp/sysinfo/model 2>/dev/null || echo 'Unknown')"
json_add_string "architecture" "$(uname -m)"
json_add_string "kernel" "$(uname -r)"
json_add_string "openwrt_version" "$(cat /etc/openwrt_release 2>/dev/null | grep DISTRIB_RELEASE | cut -d= -f2 | tr -d \"\')"
json_add_int "uptime" "$(cat /proc/uptime | cut -d. -f1)"
json_add_string "local_time" "$(date '+%Y-%m-%d %H:%M:%S')"
json_close_object
# CPU info
json_add_object "cpu"
local load1=$(cat /proc/loadavg | awk '{print $1}')
local load5=$(cat /proc/loadavg | awk '{print $2}')
local load15=$(cat /proc/loadavg | awk '{print $3}')
local cores=$(grep -c processor /proc/cpuinfo)
local usage=$(top -bn1 | grep "CPU:" | awk '{print 100-$8}' | head -1)
[ -z "$usage" ] && usage=$(awk '/^cpu / {print 100-($5*100/($2+$3+$4+$5+$6+$7+$8))}' /proc/stat)
json_add_string "load_1m" "$load1"
json_add_string "load_5m" "$load5"
json_add_string "load_15m" "$load15"
json_add_int "cores" "$cores"
json_add_int "usage_percent" "${usage%.*}"
json_close_object
# Memory info
json_add_object "memory"
local mem_total=$(grep MemTotal /proc/meminfo | awk '{print $2}')
local mem_free=$(grep MemFree /proc/meminfo | awk '{print $2}')
local mem_available=$(grep MemAvailable /proc/meminfo | awk '{print $2}')
local mem_buffers=$(grep Buffers /proc/meminfo | awk '{print $2}')
local mem_cached=$(grep "^Cached:" /proc/meminfo | awk '{print $2}')
local mem_used=$((mem_total - mem_free - mem_buffers - mem_cached))
local mem_percent=$((mem_used * 100 / mem_total))
json_add_int "total_kb" "$mem_total"
json_add_int "used_kb" "$mem_used"
json_add_int "free_kb" "$mem_free"
json_add_int "available_kb" "$mem_available"
json_add_int "usage_percent" "$mem_percent"
json_close_object
# Storage info
json_add_object "storage"
local disk_info=$(df / | tail -1)
local disk_total=$(echo "$disk_info" | awk '{print $2}')
local disk_used=$(echo "$disk_info" | awk '{print $3}')
local disk_free=$(echo "$disk_info" | awk '{print $4}')
local disk_percent=$(echo "$disk_info" | awk '{print $5}' | tr -d '%')
json_add_int "total_kb" "$disk_total"
json_add_int "used_kb" "$disk_used"
json_add_int "free_kb" "$disk_free"
json_add_int "usage_percent" "$disk_percent"
json_close_object
# Temperature (if available)
local temp=""
if [ -f /sys/class/thermal/thermal_zone0/temp ]; then
temp=$(($(cat /sys/class/thermal/thermal_zone0/temp) / 1000))
fi
json_add_int "temperature" "${temp:-0}"
# Network summary
json_add_object "network"
local wan_status=$(ubus call network.interface.wan status 2>/dev/null | jsonfilter -e '@.up' 2>/dev/null)
local wan_ip=$(ubus call network.interface.wan status 2>/dev/null | jsonfilter -e '@["ipv4-address"][0].address' 2>/dev/null)
local lan_ip=$(ubus call network.interface.lan status 2>/dev/null | jsonfilter -e '@["ipv4-address"][0].address' 2>/dev/null)
json_add_boolean "wan_up" "${wan_status:-0}"
json_add_string "wan_ip" "${wan_ip:-N/A}"
json_add_string "lan_ip" "${lan_ip:-N/A}"
local clients=$(cat /proc/net/arp | grep -v "IP address" | wc -l)
json_add_int "connected_clients" "$clients"
json_close_object
# Component summary
local installed=0
local running=0
local issues=0
config_load system-hub
config_foreach count_components component
json_add_object "components"
json_add_int "installed" "$installed"
json_add_int "running" "$running"
json_add_int "issues" "$issues"
json_close_object
# Remote status
json_add_object "remote"
local remote_enabled=$(uci -q get system-hub.remote.enabled || echo "0")
local rustdesk_enabled=$(uci -q get system-hub.remote.rustdesk_enabled || echo "0")
local rustdesk_id=$(uci -q get system-hub.remote.rustdesk_id || echo "")
json_add_boolean "enabled" "$remote_enabled"
json_add_boolean "rustdesk_enabled" "$rustdesk_enabled"
json_add_string "rustdesk_id" "$rustdesk_id"
json_add_boolean "session_active" "0"
json_close_object
# Last health check
json_add_string "last_health_check" "$(stat -c %Y $REPORTS_DIR/health_latest.json 2>/dev/null | xargs -I{} date -d @{} '+%Y-%m-%d %H:%M:%S' 2>/dev/null || echo 'Never')"
json_dump
}
count_components() {
local status=$(uci -q get system-hub.$1.status)
local service=$(uci -q get system-hub.$1.service)
[ "$status" = "installed" ] && installed=$((installed + 1))
if [ -n "$service" ] && /etc/init.d/$service enabled 2>/dev/null; then
if /etc/init.d/$service running 2>/dev/null; then
running=$((running + 1))
else
issues=$((issues + 1))
fi
fi
}
# Get all components with status
get_components() {
json_init
json_add_array "components"
config_load system-hub
config_foreach output_component component
json_close_array
json_dump
}
output_component() {
local section="$1"
local service=$(uci -q get system-hub.$section.service)
local status=$(uci -q get system-hub.$section.status)
# Check if service is running
local is_running=0
local is_enabled=0
if [ -n "$service" ] && [ "$status" = "installed" ]; then
/etc/init.d/$service enabled 2>/dev/null && is_enabled=1
/etc/init.d/$service running 2>/dev/null && is_running=1
fi
json_add_object
json_add_string "id" "$section"
json_add_string "name" "$(uci -q get system-hub.$section.name)"
json_add_string "description" "$(uci -q get system-hub.$section.description)"
json_add_string "package" "$(uci -q get system-hub.$section.package)"
json_add_string "service" "$service"
json_add_string "icon" "$(uci -q get system-hub.$section.icon)"
json_add_string "color" "$(uci -q get system-hub.$section.color)"
json_add_string "category" "$(uci -q get system-hub.$section.category)"
json_add_string "status" "$status"
json_add_string "version" "$(uci -q get system-hub.$section.version)"
json_add_boolean "enabled" "$is_enabled"
json_add_boolean "running" "$is_running"
json_add_string "web_port" "$(uci -q get system-hub.$section.web_port)"
json_add_string "roadmap_date" "$(uci -q get system-hub.$section.roadmap_date)"
json_close_object
}
# Get health report
get_health() {
json_init
# Overall score
local score=100
local issues=""
# CPU health
local cpu_usage=$(awk '/^cpu / {print int(100-($5*100/($2+$3+$4+$5+$6+$7+$8)))}' /proc/stat)
local cpu_warning=$(uci -q get system-hub.health.cpu_warning || echo 80)
local cpu_critical=$(uci -q get system-hub.health.cpu_critical || echo 95)
local cpu_status="ok"
if [ "$cpu_usage" -ge "$cpu_critical" ]; then
cpu_status="critical"
score=$((score - 30))
issues="$issues CPU critical ($cpu_usage%);"
elif [ "$cpu_usage" -ge "$cpu_warning" ]; then
cpu_status="warning"
score=$((score - 15))
issues="$issues CPU warning ($cpu_usage%);"
fi
# Memory health
local mem_total=$(grep MemTotal /proc/meminfo | awk '{print $2}')
local mem_free=$(grep MemFree /proc/meminfo | awk '{print $2}')
local mem_buffers=$(grep Buffers /proc/meminfo | awk '{print $2}')
local mem_cached=$(grep "^Cached:" /proc/meminfo | awk '{print $2}')
local mem_used=$((mem_total - mem_free - mem_buffers - mem_cached))
local mem_percent=$((mem_used * 100 / mem_total))
local mem_warning=$(uci -q get system-hub.health.memory_warning || echo 80)
local mem_critical=$(uci -q get system-hub.health.memory_critical || echo 95)
local mem_status="ok"
if [ "$mem_percent" -ge "$mem_critical" ]; then
mem_status="critical"
score=$((score - 25))
issues="$issues Memory critical ($mem_percent%);"
elif [ "$mem_percent" -ge "$mem_warning" ]; then
mem_status="warning"
score=$((score - 10))
issues="$issues Memory warning ($mem_percent%);"
fi
# Disk health
local disk_percent=$(df / | tail -1 | awk '{print $5}' | tr -d '%')
local disk_warning=$(uci -q get system-hub.health.disk_warning || echo 80)
local disk_critical=$(uci -q get system-hub.health.disk_critical || echo 95)
local disk_status="ok"
if [ "$disk_percent" -ge "$disk_critical" ]; then
disk_status="critical"
score=$((score - 25))
issues="$issues Disk critical ($disk_percent%);"
elif [ "$disk_percent" -ge "$disk_warning" ]; then
disk_status="warning"
score=$((score - 10))
issues="$issues Disk warning ($disk_percent%);"
fi
# Temperature health
local temp=0
local temp_status="ok"
if [ -f /sys/class/thermal/thermal_zone0/temp ]; then
temp=$(($(cat /sys/class/thermal/thermal_zone0/temp) / 1000))
local temp_warning=$(uci -q get system-hub.health.temperature_warning || echo 70)
local temp_critical=$(uci -q get system-hub.health.temperature_critical || echo 85)
if [ "$temp" -ge "$temp_critical" ]; then
temp_status="critical"
score=$((score - 20))
issues="$issues Temperature critical (${temp}°C);"
elif [ "$temp" -ge "$temp_warning" ]; then
temp_status="warning"
score=$((score - 10))
issues="$issues Temperature warning (${temp}°C);"
fi
fi
# Services health
local services_ok=0
local services_failed=0
for svc in network dnsmasq firewall uhttpd; do
if /etc/init.d/$svc enabled 2>/dev/null; then
if /etc/init.d/$svc running 2>/dev/null; then
services_ok=$((services_ok + 1))
else
services_failed=$((services_failed + 1))
score=$((score - 5))
issues="$issues Service $svc not running;"
fi
fi
done
# Network health
local wan_up=0
local wan_status=$(ubus call network.interface.wan status 2>/dev/null | jsonfilter -e '@.up' 2>/dev/null)
[ "$wan_status" = "true" ] && wan_up=1
local net_status="ok"
if [ "$wan_up" = "0" ]; then
net_status="critical"
score=$((score - 20))
issues="$issues WAN down;"
fi
# Ensure score is not negative
[ "$score" -lt 0 ] && score=0
# Determine overall status
local overall="healthy"
[ "$score" -lt 80 ] && overall="warning"
[ "$score" -lt 50 ] && overall="critical"
json_add_int "score" "$score"
json_add_string "status" "$overall"
json_add_string "issues" "$issues"
json_add_string "timestamp" "$(date '+%Y-%m-%d %H:%M:%S')"
json_add_object "cpu"
json_add_int "usage" "$cpu_usage"
json_add_string "status" "$cpu_status"
json_close_object
json_add_object "memory"
json_add_int "usage" "$mem_percent"
json_add_string "status" "$mem_status"
json_close_object
json_add_object "disk"
json_add_int "usage" "$disk_percent"
json_add_string "status" "$disk_status"
json_close_object
json_add_object "temperature"
json_add_int "value" "$temp"
json_add_string "status" "$temp_status"
json_close_object
json_add_object "services"
json_add_int "running" "$services_ok"
json_add_int "failed" "$services_failed"
json_close_object
json_add_object "network"
json_add_boolean "wan_up" "$wan_up"
json_add_string "status" "$net_status"
json_close_object
# Recommendations
json_add_array "recommendations"
[ "$cpu_status" != "ok" ] && json_add_string "" "Réduire la charge CPU en désactivant des services non essentiels"
[ "$mem_status" != "ok" ] && json_add_string "" "Libérer de la mémoire ou augmenter le swap"
[ "$disk_status" != "ok" ] && json_add_string "" "Nettoyer les fichiers temporaires et logs anciens"
[ "$temp_status" != "ok" ] && json_add_string "" "Améliorer la ventilation ou réduire la charge"
[ "$net_status" != "ok" ] && json_add_string "" "Vérifier la connexion WAN et les paramètres réseau"
json_close_array
json_dump
}
# Get remote assistance config
get_remote() {
json_init
json_add_boolean "enabled" "$(uci -q get system-hub.remote.enabled || echo 0)"
json_add_boolean "rustdesk_enabled" "$(uci -q get system-hub.remote.rustdesk_enabled || echo 0)"
json_add_string "rustdesk_server" "$(uci -q get system-hub.remote.rustdesk_server)"
json_add_string "rustdesk_id" "$(uci -q get system-hub.remote.rustdesk_id)"
json_add_boolean "allow_unattended" "$(uci -q get system-hub.remote.allow_unattended || echo 0)"
json_add_boolean "require_approval" "$(uci -q get system-hub.remote.require_approval || echo 1)"
json_add_boolean "notify_on_connect" "$(uci -q get system-hub.remote.notify_on_connect || echo 1)"
json_add_int "session_timeout" "$(uci -q get system-hub.remote.session_timeout || echo 3600)"
# Check if RustDesk is installed and running
local rustdesk_installed=0
local rustdesk_running=0
which rustdesk >/dev/null 2>&1 && rustdesk_installed=1
pgrep -x rustdesk >/dev/null 2>&1 && rustdesk_running=1
json_add_boolean "rustdesk_installed" "$rustdesk_installed"
json_add_boolean "rustdesk_running" "$rustdesk_running"
# Support info
json_add_object "support"
json_add_string "provider" "$(uci -q get system-hub.support.provider)"
json_add_string "email" "$(uci -q get system-hub.support.email)"
json_add_string "phone" "$(uci -q get system-hub.support.phone)"
json_add_string "website" "$(uci -q get system-hub.support.website)"
json_add_string "ticket_url" "$(uci -q get system-hub.support.ticket_url)"
json_close_object
json_dump
}
# Collect diagnostic data
collect_diagnostics() {
read input
json_load "$input"
json_get_var include_logs include_logs
json_get_var include_config include_config
json_get_var include_network include_network
json_get_var anonymize anonymize
json_init
local diag_file="$DIAG_DIR/diagnostic_$(date +%Y%m%d_%H%M%S).tar.gz"
local temp_dir="/tmp/system-hub-diag-$$"
mkdir -p "$temp_dir"
# System info
{
echo "=== System Info ==="
echo "Date: $(date)"
echo "Hostname: $(hostname)"
echo "Model: $(cat /tmp/sysinfo/model 2>/dev/null)"
echo "Kernel: $(uname -a)"
echo "OpenWrt: $(cat /etc/openwrt_release)"
echo ""
echo "=== Uptime ==="
uptime
echo ""
echo "=== Memory ==="
free
cat /proc/meminfo
echo ""
echo "=== Disk ==="
df -h
echo ""
echo "=== CPU ==="
cat /proc/cpuinfo
echo ""
echo "=== Processes ==="
ps w
} > "$temp_dir/system_info.txt"
# Logs
if [ "$include_logs" = "1" ]; then
{
echo "=== System Log ==="
logread | tail -500
echo ""
echo "=== Kernel Log ==="
dmesg | tail -200
} > "$temp_dir/logs.txt"
# Component logs
[ -f /var/log/crowdsec.log ] && tail -200 /var/log/crowdsec.log > "$temp_dir/crowdsec.log"
[ -f /var/log/netifyd.log ] && tail -200 /var/log/netifyd.log > "$temp_dir/netifyd.log"
[ -f /var/log/system-hub.log ] && tail -200 /var/log/system-hub.log > "$temp_dir/system-hub.log"
fi
# Network info
if [ "$include_network" = "1" ]; then
{
echo "=== Interfaces ==="
ip addr
echo ""
echo "=== Routes ==="
ip route
echo ""
echo "=== ARP ==="
cat /proc/net/arp
echo ""
echo "=== Connections ==="
netstat -tuln 2>/dev/null || ss -tuln
echo ""
echo "=== Firewall ==="
iptables -L -n -v 2>/dev/null
echo ""
echo "=== WiFi ==="
iwinfo 2>/dev/null || iw dev 2>/dev/null
} > "$temp_dir/network.txt"
fi
# Config (anonymized if requested)
if [ "$include_config" = "1" ]; then
mkdir -p "$temp_dir/config"
for conf in network wireless firewall dhcp system; do
if [ -f "/etc/config/$conf" ]; then
if [ "$anonymize" = "1" ]; then
# Remove passwords and sensitive data
sed -e 's/option key .*/option key *****/g' \
-e 's/option password .*/option password *****/g' \
-e 's/option private_key .*/option private_key *****/g' \
-e 's/option preshared_key .*/option preshared_key *****/g' \
"/etc/config/$conf" > "$temp_dir/config/$conf"
else
cp "/etc/config/$conf" "$temp_dir/config/"
fi
fi
done
fi
# Packages list
opkg list-installed > "$temp_dir/packages.txt"
# Create archive
tar -czf "$diag_file" -C "$temp_dir" .
rm -rf "$temp_dir"
local file_size=$(stat -c%s "$diag_file")
json_add_boolean "success" 1
json_add_string "file" "$diag_file"
json_add_int "size" "$file_size"
json_add_string "timestamp" "$(date '+%Y-%m-%d %H:%M:%S')"
log_event "info" "Diagnostic collected: $diag_file"
json_dump
}
# Generate health report
generate_report() {
json_init
local report_file="$REPORTS_DIR/health_$(date +%Y%m%d_%H%M%S).json"
# Get health data and save
get_health > "$report_file"
# Also save as latest
cp "$report_file" "$REPORTS_DIR/health_latest.json"
json_add_boolean "success" 1
json_add_string "file" "$report_file"
json_add_string "timestamp" "$(date '+%Y-%m-%d %H:%M:%S')"
log_event "info" "Health report generated: $report_file"
json_dump
}
# Get unified logs from all components
get_logs() {
read input
json_load "$input"
json_get_var limit limit
json_get_var source source
json_get_var level level
[ -z "$limit" ] && limit=100
json_init
json_add_array "logs"
# System log
if [ -z "$source" ] || [ "$source" = "system" ]; then
logread | tail -n $limit | while read line; do
local ts=$(echo "$line" | awk '{print $1" "$2" "$3}')
local msg=$(echo "$line" | cut -d' ' -f4-)
local lvl="info"
echo "$line" | grep -qi "error\|fail\|critical" && lvl="error"
echo "$line" | grep -qi "warn" && lvl="warning"
json_add_object
json_add_string "timestamp" "$ts"
json_add_string "source" "system"
json_add_string "level" "$lvl"
json_add_string "message" "$msg"
json_close_object
done
fi
# Component logs
for logfile in /var/log/system-hub.log /var/log/crowdsec.log /var/log/client-guardian.log; do
if [ -f "$logfile" ]; then
local src=$(basename "$logfile" .log)
[ -z "$source" ] || [ "$source" = "$src" ] && tail -n $((limit / 3)) "$logfile" | while read line; do
json_add_object
json_add_string "timestamp" "$(echo "$line" | sed -n 's/\[\([^]]*\)\].*/\1/p')"
json_add_string "source" "$src"
json_add_string "level" "$(echo "$line" | sed -n 's/.*\] \[\([^]]*\)\].*/\1/p')"
json_add_string "message" "$(echo "$line" | sed 's/.*\] \[.*\] //')"
json_close_object
done
fi
done
json_close_array
json_dump
}
# Start remote session
start_remote_session() {
read input
json_load "$input"
json_get_var type type
json_init
case "$type" in
rustdesk)
if which rustdesk >/dev/null 2>&1; then
rustdesk --service &
sleep 2
local id=$(rustdesk --get-id 2>/dev/null)
json_add_boolean "success" 1
json_add_string "type" "rustdesk"
json_add_string "id" "$id"
json_add_string "message" "RustDesk session started"
log_event "info" "Remote session started: RustDesk ID $id"
else
json_add_boolean "success" 0
json_add_string "error" "RustDesk not installed"
fi
;;
ssh)
json_add_boolean "success" 1
json_add_string "type" "ssh"
json_add_string "host" "$(ubus call network.interface.wan status 2>/dev/null | jsonfilter -e '@["ipv4-address"][0].address')"
json_add_int "port" "22"
;;
*)
json_add_boolean "success" 0
json_add_string "error" "Unknown session type"
;;
esac
json_dump
}
# Update component
manage_component() {
read input
json_load "$input"
json_get_var component component
json_get_var action action
json_init
local service=$(uci -q get system-hub.$component.service)
if [ -z "$service" ]; then
json_add_boolean "success" 0
json_add_string "error" "Component not found"
json_dump
return
fi
case "$action" in
start)
/etc/init.d/$service start 2>&1
json_add_boolean "success" 1
json_add_string "message" "Service $service started"
log_event "info" "Component $component started"
;;
stop)
/etc/init.d/$service stop 2>&1
json_add_boolean "success" 1
json_add_string "message" "Service $service stopped"
log_event "info" "Component $component stopped"
;;
restart)
/etc/init.d/$service restart 2>&1
json_add_boolean "success" 1
json_add_string "message" "Service $service restarted"
log_event "info" "Component $component restarted"
;;
enable)
/etc/init.d/$service enable 2>&1
json_add_boolean "success" 1
json_add_string "message" "Service $service enabled"
;;
disable)
/etc/init.d/$service disable 2>&1
json_add_boolean "success" 1
json_add_string "message" "Service $service disabled"
;;
*)
json_add_boolean "success" 0
json_add_string "error" "Unknown action"
;;
esac
json_dump
}
# Upload diagnostic file
upload_diagnostic() {
read input
json_load "$input"
json_get_var file file
json_init
local upload_url=$(uci -q get system-hub.diagnostics.upload_url)
local upload_token=$(uci -q get system-hub.diagnostics.upload_token)
if [ -z "$upload_url" ]; then
json_add_boolean "success" 0
json_add_string "error" "Upload URL not configured"
json_dump
return
fi
if [ ! -f "$file" ]; then
json_add_boolean "success" 0
json_add_string "error" "File not found"
json_dump
return
fi
# Upload via curl
local response=$(curl -s -X POST \
-H "Authorization: Bearer $upload_token" \
-F "file=@$file" \
-F "hostname=$(hostname)" \
"$upload_url" 2>&1)
if [ $? -eq 0 ]; then
json_add_boolean "success" 1
json_add_string "message" "File uploaded successfully"
json_add_string "response" "$response"
log_event "info" "Diagnostic uploaded: $file"
else
json_add_boolean "success" 0
json_add_string "error" "Upload failed: $response"
fi
json_dump
}
# Get schedules
get_schedules() {
json_init
json_add_array "schedules"
config_load system-hub
config_foreach output_schedule schedule
json_close_array
json_dump
}
output_schedule() {
json_add_object
json_add_string "id" "$1"
json_add_string "name" "$(uci -q get system-hub.$1.name)"
json_add_boolean "enabled" "$(uci -q get system-hub.$1.enabled || echo 0)"
json_add_string "type" "$(uci -q get system-hub.$1.type)"
json_add_string "cron" "$(uci -q get system-hub.$1.cron)"
json_close_object
}
# Main dispatcher
case "$1" in
list)
echo '{"status":{},"components":{},"health":{},"remote":{},"logs":{"limit":"int","source":"str","level":"str"},"schedules":{},"collect_diagnostics":{"include_logs":"bool","include_config":"bool","include_network":"bool","anonymize":"bool"},"generate_report":{},"start_remote_session":{"type":"str"},"manage_component":{"component":"str","action":"str"},"upload_diagnostic":{"file":"str"}}'
;;
call)
case "$2" in
status) get_status ;;
components) get_components ;;
health) get_health ;;
remote) get_remote ;;
logs) get_logs ;;
schedules) get_schedules ;;
collect_diagnostics) collect_diagnostics ;;
generate_report) generate_report ;;
start_remote_session) start_remote_session ;;
manage_component) manage_component ;;
upload_diagnostic) upload_diagnostic ;;
*) echo '{"error": "Unknown method"}' ;;
esac
;;
esac