mirror of
https://github.com/kiddin9/op-packages.git
synced 2026-10-29 05:55:13 +08:00
💋 Sync 2026-10-04 04:16:09
This commit is contained in:
1 parent
f6b2df73ec
commit
f62992fd80
745 files changed
+212416
-1173
No files matched your search
+77
@@ -0,0 +1,77 @@
|
||||
#!/bin/sh
|
||||
# Aggressive rebuild — matches source netwizard behaviour. Called only if user opts in.
|
||||
|
||||
MODE="$1"; LAN_IP="$2"; PPPOE_USER="$3"; PPPOE_PASS="$4"; WAN_IFACE="$5"
|
||||
[ -z "$MODE" ] && MODE="dhcp"
|
||||
[ -z "$LAN_IP" ] && LAN_IP="192.168.10.1"
|
||||
|
||||
BACKUP_DIR="/etc/config.bak.$(date +%s)"
|
||||
mkdir -p "$BACKUP_DIR"
|
||||
for f in network firewall dhcp wireless system wizard netwizard; do
|
||||
[ -f /etc/config/$f ] && cp /etc/config/$f "$BACKUP_DIR/"
|
||||
done
|
||||
echo "Backup saved to $BACKUP_DIR"
|
||||
|
||||
if [ -z "$WAN_IFACE" ]; then
|
||||
WAN_IFACE=$(uci -q get network.wan.device)
|
||||
[ -z "$WAN_IFACE" ] && WAN_IFACE=$(ls /sys/class/net/ 2>/dev/null | grep -E '^(eth[01]|wan)' | head -n1)
|
||||
[ -z "$WAN_IFACE" ] && WAN_IFACE="eth1"
|
||||
fi
|
||||
|
||||
uci -q delete network.wan 2>/dev/null
|
||||
uci -q delete network.wan6 2>/dev/null
|
||||
uci -q delete network.lan6 2>/dev/null
|
||||
|
||||
WAN_IDX=$(uci show firewall | sed -n "s/^firewall\.@zone\[\([0-9]*\)\]\.name='wan'$/\1/p")
|
||||
[ -n "$WAN_IDX" ] && uci -q delete firewall.@zone[$WAN_IDX] 2>/dev/null
|
||||
|
||||
if [ "$MODE" = "siderouter" ]; then
|
||||
LAN_IDX=$(uci show firewall | sed -n "s/^firewall\.@zone\[\([0-9]*\)\]\.name='lan'$/\1/p")
|
||||
[ -n "$LAN_IDX" ] && uci -q delete firewall.@zone[$LAN_IDX].masq 2>/dev/null
|
||||
uci set network.lan=interface
|
||||
uci set network.lan.proto='static'
|
||||
uci set network.lan.ipaddr="$LAN_IP"
|
||||
uci set network.lan.netmask='255.255.255.0'
|
||||
else
|
||||
uci set network.wan=interface
|
||||
uci set network.wan.device="$WAN_IFACE"
|
||||
if [ "$MODE" = "pppoe" ]; then
|
||||
uci set network.wan.proto='pppoe'
|
||||
[ -n "$PPPOE_USER" ] && uci set network.wan.username="$PPPOE_USER"
|
||||
[ -n "$PPPOE_PASS" ] && uci set network.wan.password="$PPPOE_PASS"
|
||||
else
|
||||
uci set network.wan.proto='dhcp'
|
||||
fi
|
||||
uci set network.wan6=interface
|
||||
uci set network.wan6.device="@wan"
|
||||
uci set network.wan6.proto='dhcpv6'
|
||||
|
||||
uci add firewall zone >/dev/null
|
||||
uci set firewall.@zone[-1].name='wan'
|
||||
uci set firewall.@zone[-1].input='REJECT'
|
||||
uci set firewall.@zone[-1].output='ACCEPT'
|
||||
uci set firewall.@zone[-1].forward='REJECT'
|
||||
uci set firewall.@zone[-1].masq='1'
|
||||
uci set firewall.@zone[-1].mtu_fix='1'
|
||||
uci add_list firewall.@zone[-1].network='wan'
|
||||
uci add_list firewall.@zone[-1].network='wan6'
|
||||
|
||||
uci add firewall forwarding >/dev/null
|
||||
uci set firewall.@forwarding[-1].src='lan'
|
||||
uci set firewall.@forwarding[-1].dest='wan'
|
||||
|
||||
uci set network.lan.ipaddr="$LAN_IP"
|
||||
uci set network.lan.netmask='255.255.255.0'
|
||||
fi
|
||||
|
||||
uci -q commit network
|
||||
uci -q commit firewall
|
||||
uci -q commit dhcp
|
||||
|
||||
/etc/init.d/network restart >/dev/null 2>&1 &
|
||||
sleep 2
|
||||
/etc/init.d/firewall reload >/dev/null 2>&1 &
|
||||
/etc/init.d/dnsmasq reload >/dev/null 2>&1 &
|
||||
|
||||
echo "Aggressive apply complete. Mode: $MODE, WAN: $WAN_IFACE, LAN: $LAN_IP"
|
||||
echo "Backup: $BACKUP_DIR"
|
||||
+45
@@ -0,0 +1,45 @@
|
||||
#!/bin/sh
|
||||
# Regenerate nginx shortcut server blocks + dnsmasq domain entries from /etc/config/wizard shortcuts.
|
||||
# Called after the user adds/removes a shortcut in the UI.
|
||||
|
||||
clean() {
|
||||
local sec
|
||||
for sec in $(uci -q show nginx 2>/dev/null | sed -n "s/^nginx\.\(_sc_[^=.]*\)=server$/\1/p"); do
|
||||
uci -q delete nginx."$sec"
|
||||
done
|
||||
for sec in $(uci -q show dhcp 2>/dev/null | sed -n "s/^dhcp\.\(_sc_[^=.]*\)=domain$/\1/p"); do
|
||||
uci -q delete dhcp."$sec"
|
||||
done
|
||||
}
|
||||
|
||||
process_one() {
|
||||
local shortcut to_url lanaddr cfg="$1"
|
||||
lanaddr="$(uci -q get network.lan.ipaddr | tr ' ' '\n' | head -n1)"
|
||||
lanaddr="${lanaddr%%/*}"
|
||||
[ -z "$lanaddr" ] && lanaddr="10.0.0.1"
|
||||
|
||||
config_get shortcut "$cfg" shortcut
|
||||
config_get to_url "$cfg" to_url
|
||||
[ -z "$shortcut" ] || [ -z "$to_url" ] && return 0
|
||||
|
||||
if [ -f /etc/nginx/uci.conf ]; then
|
||||
uci -q set nginx._sc_$shortcut=server
|
||||
uci -q set nginx._sc_$shortcut.server_name="$shortcut"
|
||||
uci -q add_list nginx._sc_$shortcut.listen="80"
|
||||
uci -q set nginx._sc_$shortcut.return="302 $to_url"
|
||||
uci -q set dhcp._sc_$shortcut=domain
|
||||
uci -q set dhcp._sc_$shortcut.name="$shortcut"
|
||||
uci -q set dhcp._sc_$shortcut.ip="$lanaddr"
|
||||
fi
|
||||
}
|
||||
|
||||
clean
|
||||
config_load wizard
|
||||
config_foreach process_one shortcuts
|
||||
|
||||
uci -q commit nginx 2>/dev/null
|
||||
uci -q commit dhcp 2>/dev/null
|
||||
[ -x /etc/init.d/nginx ] && /etc/init.d/nginx reload >/dev/null 2>&1
|
||||
[ -x /etc/init.d/dnsmasq ] && /etc/init.d/dnsmasq reload >/dev/null 2>&1
|
||||
|
||||
echo "Shortcuts applied."
|
||||
@@ -0,0 +1,12 @@
|
||||
#!/bin/sh
|
||||
BACKUP_DIR="/etc/config.bak.$(date +%s)"
|
||||
mkdir -p "$BACKUP_DIR"
|
||||
COUNT=0
|
||||
for f in network firewall dhcp wireless system wizard netwizard taskplan; do
|
||||
if [ -f /etc/config/$f ]; then
|
||||
cp /etc/config/$f "$BACKUP_DIR/"
|
||||
COUNT=$((COUNT + 1))
|
||||
fi
|
||||
done
|
||||
echo "Backed up $COUNT files to $BACKUP_DIR"
|
||||
ls -1 "$BACKUP_DIR"
|
||||
+2
@@ -0,0 +1,2 @@
|
||||
#!/bin/sh
|
||||
ls -1d /etc/config.bak.* 2>/dev/null | sort -r
|
||||
@@ -0,0 +1,23 @@
|
||||
#!/bin/sh
|
||||
DIR="$1"
|
||||
[ -z "$DIR" ] && { echo "Usage: restore.sh <backup-dir>"; exit 1; }
|
||||
[ ! -d "$DIR" ] && { echo "Directory not found: $DIR"; exit 1; }
|
||||
|
||||
SAFETY="/etc/config.bak.pre-restore.$(date +%s)"
|
||||
mkdir -p "$SAFETY"
|
||||
for f in "$DIR"/*; do
|
||||
[ -f "$f" ] || continue
|
||||
base=$(basename "$f")
|
||||
[ -f "/etc/config/$base" ] && cp "/etc/config/$base" "$SAFETY/"
|
||||
cp "$f" "/etc/config/$base"
|
||||
done
|
||||
|
||||
for c in network firewall dhcp wireless wizard netwizard taskplan; do
|
||||
uci -q commit $c 2>/dev/null
|
||||
done
|
||||
|
||||
/etc/init.d/network reload >/dev/null 2>&1 &
|
||||
/etc/init.d/firewall reload >/dev/null 2>&1 &
|
||||
|
||||
echo "Restored from $DIR"
|
||||
echo "Previous state saved to $SAFETY"
|
||||
@@ -0,0 +1,82 @@
|
||||
#!/bin/sh
|
||||
# ubus RPC module for Quick Actions Failover
|
||||
. /usr/share/libubox/jshn.sh
|
||||
|
||||
list_methods() {
|
||||
cat <<'EOF'
|
||||
{
|
||||
"status": {},
|
||||
"interfaces": {},
|
||||
"action": { "action": "string" }
|
||||
}
|
||||
EOF
|
||||
}
|
||||
|
||||
method_status() {
|
||||
cat >/dev/null
|
||||
local en lock
|
||||
en=$(uci -q get quickactions.failover.enabled); [ -z "$en" ] && en=1
|
||||
[ -f /tmp/quickactions_wan_down.lock ] && lock=1 || lock=0
|
||||
json_init
|
||||
json_add_int "enabled" "$en"
|
||||
json_add_int "on_backup" "$lock"
|
||||
json_add_string "primary" "$(uci -q get quickactions.failover.primary)"
|
||||
json_add_string "backups" "$(uci -q get quickactions.failover.backups)"
|
||||
json_add_string "check_ips" "$(uci -q get quickactions.failover.check_ips)"
|
||||
json_add_string "interval" "$(uci -q get quickactions.failover.check_interval)"
|
||||
json_add_string "last_log" "$(logread 2>/dev/null | grep -E 'quickactions-(failover|hotplug)' | tail -1)"
|
||||
json_dump
|
||||
}
|
||||
|
||||
method_interfaces() {
|
||||
cat >/dev/null
|
||||
local list
|
||||
list=$(
|
||||
{
|
||||
uci show network 2>/dev/null | grep '=interface$' | cut -d. -f2 | cut -d= -f1
|
||||
ls -1 /sys/class/net/ 2>/dev/null | grep -E '^(pppoe-|eth|usb)'
|
||||
} | sort -u | tr '\n' ' '
|
||||
)
|
||||
json_init
|
||||
json_add_string "interfaces" "$list"
|
||||
json_dump
|
||||
}
|
||||
|
||||
method_action() {
|
||||
local payload action out
|
||||
payload=$(cat)
|
||||
json_load "$payload"
|
||||
json_get_var action "action"
|
||||
|
||||
case "$action" in
|
||||
on|off|status|test)
|
||||
out=$(/usr/bin/quickactions-failover "$action" 2>&1)
|
||||
;;
|
||||
*)
|
||||
out="unknown action: [$action]"
|
||||
;;
|
||||
esac
|
||||
|
||||
json_init
|
||||
json_add_string "output" "$out"
|
||||
json_dump
|
||||
}
|
||||
|
||||
call_method() {
|
||||
local method="$1"
|
||||
case "$method" in
|
||||
action) method_action ;;
|
||||
status) method_status ;;
|
||||
interfaces) method_interfaces ;;
|
||||
*) cat >/dev/null
|
||||
json_init
|
||||
json_add_string "error" "unknown_method"
|
||||
json_dump ;;
|
||||
esac
|
||||
}
|
||||
|
||||
case "$1" in
|
||||
list) list_methods ;;
|
||||
call) call_method "$2" ;;
|
||||
*) echo '{"error":"usage: '$0' {list|call <method>}"}' ;;
|
||||
esac
|
||||
@@ -0,0 +1,338 @@
|
||||
#!/bin/sh
|
||||
# ubus RPC module for Quick Actions Scripts
|
||||
. /usr/share/libubox/jshn.sh
|
||||
|
||||
SCRIPTS_DIR=/etc/quickactions/scripts
|
||||
mkdir -p "$SCRIPTS_DIR"
|
||||
|
||||
list_methods() {
|
||||
cat <<'EOF'
|
||||
{
|
||||
"list": {},
|
||||
"read": { "sid": "string" },
|
||||
"write": { "sid": "string", "name": "string", "category": "string", "content": "string", "args": "string", "timeout": "string", "enabled": "string" },
|
||||
"delete": { "sid": "string" },
|
||||
"run": { "sid": "string" },
|
||||
"chmod": { "sid": "string", "mode": "string" },
|
||||
"install_preset": { "preset": "string" },
|
||||
"detail": { "sid": "string" }
|
||||
}
|
||||
EOF
|
||||
}
|
||||
|
||||
method_list() {
|
||||
cat >/dev/null
|
||||
json_init
|
||||
json_add_array "scripts"
|
||||
# No pipe into while → no subshell → json_add works
|
||||
for sid in $(uci show quickactions 2>/dev/null | grep '=script$' | cut -d. -f2 | cut -d= -f1); do
|
||||
name=$(uci -q get "quickactions.$sid.name")
|
||||
category=$(uci -q get "quickactions.$sid.category")
|
||||
path=$(uci -q get "quickactions.$sid.path")
|
||||
[ -z "$path" ] && path="$SCRIPTS_DIR/$sid.sh"
|
||||
enabled=$(uci -q get "quickactions.$sid.enabled")
|
||||
[ -z "$enabled" ] && enabled="1"
|
||||
sz=0
|
||||
[ -f "$path" ] && sz=$(wc -c < "$path" 2>/dev/null)
|
||||
[ -z "$sz" ] && sz=0
|
||||
json_add_object
|
||||
json_add_string "sid" "$sid"
|
||||
json_add_string "name" "$name"
|
||||
json_add_string "category" "$category"
|
||||
json_add_string "path" "$path"
|
||||
json_add_string "enabled" "$enabled"
|
||||
json_add_int "size" "$sz"
|
||||
json_close_object
|
||||
done
|
||||
json_close_array
|
||||
json_dump
|
||||
}
|
||||
|
||||
method_read() {
|
||||
local sid=""
|
||||
json_load "$(cat)"
|
||||
json_get_var sid "sid"
|
||||
[ -z "$sid" ] && { json_init; json_add_string "error" "no sid"; json_dump; return; }
|
||||
|
||||
local path
|
||||
path=$(uci -q get "quickactions.$sid.path")
|
||||
[ -z "$path" ] && path="$SCRIPTS_DIR/$sid.sh"
|
||||
|
||||
json_init
|
||||
if [ -f "$path" ]; then
|
||||
json_add_string "content" "$(cat "$path")"
|
||||
else
|
||||
json_add_string "content" ""
|
||||
fi
|
||||
json_dump
|
||||
}
|
||||
|
||||
method_write() {
|
||||
local payload sid name category content args timeout enabled path
|
||||
payload=$(cat)
|
||||
json_load "$payload"
|
||||
json_get_var sid "sid"
|
||||
json_get_var name "name"
|
||||
json_get_var category "category"
|
||||
json_get_var content "content"
|
||||
json_get_var args "args"
|
||||
json_get_var timeout "timeout"
|
||||
json_get_var enabled "enabled"
|
||||
|
||||
[ -z "$sid" ] && sid="script_$(date +%s)"
|
||||
[ -z "$name" ] && name="$sid"
|
||||
[ -z "$category" ] && category="custom"
|
||||
[ -z "$timeout" ] && timeout="60"
|
||||
[ -z "$enabled" ] && enabled="1"
|
||||
|
||||
path=$(uci -q get "quickactions.$sid.path")
|
||||
[ -z "$path" ] && path="$SCRIPTS_DIR/$sid.sh"
|
||||
|
||||
mkdir -p "$(dirname "$path")"
|
||||
printf '%s' "$content" > "$path"
|
||||
chmod 755 "$path" 2>/dev/null
|
||||
|
||||
uci -q set "quickactions.$sid=script"
|
||||
uci -q set "quickactions.$sid.name=$name"
|
||||
uci -q set "quickactions.$sid.category=$category"
|
||||
uci -q set "quickactions.$sid.path=$path"
|
||||
uci -q set "quickactions.$sid.enabled=$enabled"
|
||||
uci -q set "quickactions.$sid.timeout=$timeout"
|
||||
[ -n "$args" ] && uci -q set "quickactions.$sid.args=$args"
|
||||
uci -q commit quickactions
|
||||
|
||||
json_init
|
||||
json_add_string "sid" "$sid"
|
||||
json_add_boolean "ok" 1
|
||||
json_dump
|
||||
}
|
||||
|
||||
method_delete() {
|
||||
local sid=""
|
||||
json_load "$(cat)"
|
||||
json_get_var sid "sid"
|
||||
[ -z "$sid" ] && { json_init; json_add_boolean "ok" 0; json_dump; return; }
|
||||
|
||||
local path
|
||||
path=$(uci -q get "quickactions.$sid.path")
|
||||
[ -z "$path" ] && path="$SCRIPTS_DIR/$sid.sh"
|
||||
[ -f "$path" ] && rm -f "$path"
|
||||
|
||||
uci -q delete "quickactions.$sid"
|
||||
uci -q commit quickactions
|
||||
|
||||
json_init
|
||||
json_add_boolean "ok" 1
|
||||
json_dump
|
||||
}
|
||||
|
||||
method_run() {
|
||||
local sid=""
|
||||
json_load "$(cat)"
|
||||
json_get_var sid "sid"
|
||||
[ -z "$sid" ] && { json_init; json_add_string "error" "no sid"; json_dump; return; }
|
||||
|
||||
local path timeout args
|
||||
path=$(uci -q get "quickactions.$sid.path")
|
||||
[ -z "$path" ] && path="$SCRIPTS_DIR/$sid.sh"
|
||||
timeout=$(uci -q get "quickactions.$sid.timeout")
|
||||
[ -z "$timeout" ] && timeout=60
|
||||
args=$(uci -q get "quickactions.$sid.args")
|
||||
|
||||
if [ ! -f "$path" ]; then
|
||||
json_init
|
||||
json_add_string "output" "Script not found: $path"
|
||||
json_add_int "exit_code" 127
|
||||
json_dump
|
||||
return
|
||||
fi
|
||||
[ -x "$path" ] || chmod 755 "$path" 2>/dev/null
|
||||
|
||||
local start_sec end_sec out rc
|
||||
start_sec=$(date +%s 2>/dev/null)
|
||||
out=$(cd / && timeout "$timeout" "$path" $args 2>&1)
|
||||
rc=$?
|
||||
end_sec=$(date +%s 2>/dev/null)
|
||||
|
||||
json_init
|
||||
json_add_string "output" "$out"
|
||||
json_add_int "exit_code" "$rc"
|
||||
json_add_int "duration" "$((end_sec - start_sec))"
|
||||
json_dump
|
||||
}
|
||||
|
||||
method_chmod() {
|
||||
local payload sid mode
|
||||
payload=$(cat)
|
||||
json_load "$payload"
|
||||
json_get_var sid "sid"
|
||||
json_get_var mode "mode"
|
||||
[ -z "$mode" ] && mode="755"
|
||||
|
||||
local path
|
||||
path=$(uci -q get "quickactions.$sid.path")
|
||||
[ -z "$path" ] && path="$SCRIPTS_DIR/$sid.sh"
|
||||
|
||||
[ -f "$path" ] && chmod "$mode" "$path" 2>/dev/null
|
||||
|
||||
json_init
|
||||
json_add_boolean "ok" 1
|
||||
json_dump
|
||||
}
|
||||
|
||||
method_detail() {
|
||||
local sid=""
|
||||
json_load "$(cat)"
|
||||
json_get_var sid "sid"
|
||||
[ -z "$sid" ] && { json_init; json_add_string "error" "no sid"; json_dump; return; }
|
||||
|
||||
local path
|
||||
path=$(uci -q get "quickactions.$sid.path")
|
||||
[ -z "$path" ] && path="$SCRIPTS_DIR/$sid.sh"
|
||||
|
||||
json_init
|
||||
json_add_string "sid" "$sid"
|
||||
json_add_string "name" "$(uci -q get quickactions.$sid.name)"
|
||||
json_add_string "category" "$(uci -q get quickactions.$sid.category)"
|
||||
json_add_string "path" "$path"
|
||||
json_add_string "enabled" "$(uci -q get quickactions.$sid.enabled)"
|
||||
json_add_string "timeout" "$(uci -q get quickactions.$sid.timeout)"
|
||||
json_add_string "args" "$(uci -q get quickactions.$sid.args)"
|
||||
json_add_string "description" "$(uci -q get quickactions.$sid.description)"
|
||||
if [ -f "$path" ]; then
|
||||
json_add_string "content" "$(cat "$path")"
|
||||
json_add_int "size" "$(wc -c < "$path")"
|
||||
json_add_string "permissions" "$(ls -l "$path" | awk '{print $1}')"
|
||||
else
|
||||
json_add_string "content" ""
|
||||
json_add_int "size" 0
|
||||
json_add_string "permissions" ""
|
||||
fi
|
||||
json_dump
|
||||
}
|
||||
|
||||
method_install_preset() {
|
||||
local preset=""
|
||||
json_load "$(cat)"
|
||||
json_get_var preset "preset"
|
||||
|
||||
local sid="failover-lite"
|
||||
local path="$SCRIPTS_DIR/$sid.sh"
|
||||
mkdir -p "$SCRIPTS_DIR"
|
||||
|
||||
if [ "$preset" = "failover" ] || [ -z "$preset" ]; then
|
||||
cat > "$path" << 'FO_EOF'
|
||||
#!/bin/sh
|
||||
# Failover-lite — MWAN3 substitute for low-RAM routers.
|
||||
. /lib/functions.sh
|
||||
config_load quickactions
|
||||
cfg() { config_get v failover "$1" "$2"; echo "$v"; }
|
||||
|
||||
ENABLED=$(cfg enabled 1); [ "$ENABLED" = "0" ] && exit 0
|
||||
PRIMARY=$(cfg primary ""); [ -z "$PRIMARY" ] && exit 0
|
||||
CHECK_IPS=$(cfg check_ips "1.1.1.1 8.8.8.8")
|
||||
PING_TIMEOUT=$(cfg ping_timeout 5)
|
||||
FAIL_AT=$(cfg fail_threshold 2)
|
||||
REC_AT=$(cfg recover_threshold 1)
|
||||
|
||||
LOCK=/tmp/qa-failover-preset.lock
|
||||
FAIL_FILE=/tmp/qa-failover-preset.fails
|
||||
OK_FILE=/tmp/qa-failover-preset.oks
|
||||
|
||||
phys_iface() {
|
||||
local log="$1" dev
|
||||
[ -e "/sys/class/net/pppoe-$log" ] && { echo "pppoe-$log"; return; }
|
||||
case "$log" in *pppoe*) [ -e "/sys/class/net/$log" ] && { echo "$log"; return; } ;; esac
|
||||
dev=$(uci -q get network.$log.device)
|
||||
[ -n "$dev" ] && [ -e "/sys/class/net/$dev" ] && { echo "$dev"; return; }
|
||||
echo "$log"
|
||||
}
|
||||
ping_ok() {
|
||||
local iface="$1" ip
|
||||
for ip in $CHECK_IPS; do
|
||||
ping -I "$iface" -c 1 -W "$PING_TIMEOUT" "$ip" >/dev/null 2>&1 && return 0
|
||||
done
|
||||
return 1
|
||||
}
|
||||
flush_ct() {
|
||||
[ -e /proc/net/nf_conntrack ] && echo f > /proc/net/nf_conntrack
|
||||
[ -e /proc/net/ip_conntrack ] && echo f > /proc/net/ip_conntrack
|
||||
return 0
|
||||
}
|
||||
|
||||
DEV=$(phys_iface "$PRIMARY")
|
||||
|
||||
if [ -f "$LOCK" ]; then
|
||||
OK_N=0; [ -f "$OK_FILE" ] && OK_N=$(cat "$OK_FILE")
|
||||
if ping_ok "$DEV"; then
|
||||
OK_N=$((OK_N + 1))
|
||||
if [ "$OK_N" -ge "$REC_AT" ]; then
|
||||
rm -f "$LOCK" "$FAIL_FILE" "$OK_FILE"
|
||||
flush_ct
|
||||
logger -t qa-failover-preset "PRIMARY $PRIMARY recovered"
|
||||
else
|
||||
echo "$OK_N" > "$OK_FILE"
|
||||
fi
|
||||
else
|
||||
echo 0 > "$OK_FILE"
|
||||
fi
|
||||
exit 0
|
||||
fi
|
||||
|
||||
if ping_ok "$DEV"; then
|
||||
rm -f "$FAIL_FILE"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
FAIL_N=0; [ -f "$FAIL_FILE" ] && FAIL_N=$(cat "$FAIL_FILE")
|
||||
FAIL_N=$((FAIL_N + 1))
|
||||
echo "$FAIL_N" > "$FAIL_FILE"
|
||||
|
||||
if [ "$FAIL_N" -ge "$FAIL_AT" ]; then
|
||||
touch "$LOCK"; rm -f "$FAIL_FILE"; flush_ct
|
||||
logger -t qa-failover-preset "PRIMARY $PRIMARY DOWN after $FAIL_AT failures"
|
||||
fi
|
||||
exit 0
|
||||
FO_EOF
|
||||
fi
|
||||
|
||||
chmod 755 "$path"
|
||||
uci -q set "quickactions.$sid=script"
|
||||
uci -q set "quickactions.$sid.name=Failover-lite"
|
||||
uci -q set "quickactions.$sid.category=failover"
|
||||
uci -q set "quickactions.$sid.path=$path"
|
||||
uci -q set "quickactions.$sid.enabled=0"
|
||||
uci -q set "quickactions.$sid.timeout=30"
|
||||
uci -q set "quickactions.$sid.description=MWAN3 substitute: ping test + conntrack flush"
|
||||
uci -q commit quickactions
|
||||
|
||||
json_init
|
||||
json_add_string "sid" "$sid"
|
||||
json_add_string "path" "$path"
|
||||
json_add_boolean "ok" 1
|
||||
json_dump
|
||||
}
|
||||
|
||||
call_method() {
|
||||
local method="$1"
|
||||
case "$method" in
|
||||
list) method_list ;;
|
||||
read) method_read ;;
|
||||
write) method_write ;;
|
||||
delete) method_delete ;;
|
||||
run) method_run ;;
|
||||
chmod) method_chmod ;;
|
||||
detail) method_detail ;;
|
||||
install_preset) method_install_preset ;;
|
||||
*) cat >/dev/null
|
||||
json_init
|
||||
json_add_string "error" "unknown_method"
|
||||
json_dump ;;
|
||||
esac
|
||||
}
|
||||
|
||||
case "$1" in
|
||||
list) list_methods ;;
|
||||
call) call_method "$2" ;;
|
||||
*) echo '{"error":"usage"}' ;;
|
||||
esac
|
||||
@@ -0,0 +1,117 @@
|
||||
#!/bin/sh
|
||||
# ubus RPC module for Quick Actions Task Plan
|
||||
. /usr/share/libubox/jshn.sh
|
||||
|
||||
LOG_FILE="/etc/quickactions-taskplan/taskplan.log"
|
||||
CONFIG_FILE="/etc/config/taskplan"
|
||||
CRON_FILE="/etc/crontabs/root"
|
||||
INIT_SCRIPT="/etc/init.d/quickactions-taskplan"
|
||||
|
||||
list_methods() {
|
||||
cat <<'EOF'
|
||||
{
|
||||
"status": {},
|
||||
"list": {},
|
||||
"task_list": {},
|
||||
"start": {},
|
||||
"stop": {},
|
||||
"restart": {},
|
||||
"reload": {}
|
||||
}
|
||||
EOF
|
||||
}
|
||||
|
||||
method_status() {
|
||||
local running=0 cron_tasks=0 scheduled=0 startup=0 log_content=""
|
||||
pgrep -f quickactions-taskplan >/dev/null 2>&1 && running=1
|
||||
[ -f "$CRON_FILE" ] && cron_tasks=$(grep -c "quickactions-taskplanhandler" "$CRON_FILE" 2>/dev/null || echo 0)
|
||||
[ -f "$CONFIG_FILE" ] && scheduled=$(grep -c "stime" "$CONFIG_FILE" 2>/dev/null || echo 0)
|
||||
[ -f "$CONFIG_FILE" ] && startup=$(grep -c "ltime" "$CONFIG_FILE" 2>/dev/null || echo 0)
|
||||
[ -f "$LOG_FILE" ] && log_content=$(tail -n 50 "$LOG_FILE" 2>/dev/null)
|
||||
|
||||
json_init
|
||||
json_add_int "running" $running
|
||||
json_add_int "cron_tasks" $cron_tasks
|
||||
json_add_int "scheduled_tasks" $scheduled
|
||||
json_add_int "startup_tasks" $startup
|
||||
json_add_string "log" "$log_content"
|
||||
json_dump
|
||||
}
|
||||
|
||||
method_list() {
|
||||
local ssum=0 lsum=0
|
||||
[ -f "$CONFIG_FILE" ] && ssum=$(grep -c "stime" "$CONFIG_FILE" 2>/dev/null || echo 0)
|
||||
[ -f "$CONFIG_FILE" ] && lsum=$(grep -c "ltime" "$CONFIG_FILE" 2>/dev/null || echo 0)
|
||||
json_init
|
||||
json_add_int "scheduled" $ssum
|
||||
json_add_int "startup" $lsum
|
||||
json_dump
|
||||
}
|
||||
|
||||
method_task_list() {
|
||||
json_init
|
||||
json_add_array "tasks"
|
||||
if [ -f "$CONFIG_FILE" ]; then
|
||||
local index=0
|
||||
while true; do
|
||||
local section=$(uci -q get taskplan.@stime[$index] 2>/dev/null)
|
||||
[ -z "$section" ] && break
|
||||
json_add_object
|
||||
json_add_string "type" "scheduled"
|
||||
json_add_int "index" $index
|
||||
json_add_int "enable" "$(uci -q get taskplan.@stime[$index].enable || echo 0)"
|
||||
json_add_string "remarks" "$(uci -q get taskplan.@stime[$index].remarks || echo "")"
|
||||
json_add_string "stype" "$(uci -q get taskplan.@stime[$index].stype || echo "")"
|
||||
json_add_string "schedule" "$(uci -q get taskplan.@stime[$index].minute) $(uci -q get taskplan.@stime[$index].hour) $(uci -q get taskplan.@stime[$index].week) $(uci -q get taskplan.@stime[$index].month)"
|
||||
json_close_object
|
||||
index=$((index + 1))
|
||||
done
|
||||
index=0
|
||||
while true; do
|
||||
local section=$(uci -q get taskplan.@ltime[$index] 2>/dev/null)
|
||||
[ -z "$section" ] && break
|
||||
json_add_object
|
||||
json_add_string "type" "startup"
|
||||
json_add_int "index" $index
|
||||
json_add_int "enable" "$(uci -q get taskplan.@ltime[$index].enable || echo 0)"
|
||||
json_add_string "remarks" "$(uci -q get taskplan.@ltime[$index].remarks || echo "")"
|
||||
json_add_string "stype" "$(uci -q get taskplan.@ltime[$index].stype || echo "")"
|
||||
json_add_int "delay" "$(uci -q get taskplan.@ltime[$index].delay || echo 10)"
|
||||
json_close_object
|
||||
index=$((index + 1))
|
||||
done
|
||||
fi
|
||||
json_close_array
|
||||
json_dump
|
||||
}
|
||||
|
||||
service_action() {
|
||||
local action="$1"
|
||||
[ -x "$INIT_SCRIPT" ] && "$INIT_SCRIPT" "$action" >/dev/null 2>&1
|
||||
local ret=$?
|
||||
json_init
|
||||
json_add_int "result" $ret
|
||||
[ $ret -eq 0 ] && json_add_string "message" "Service $action ok"
|
||||
json_dump
|
||||
}
|
||||
|
||||
call_method() {
|
||||
local method="$1"
|
||||
cat >/dev/null
|
||||
case "$method" in
|
||||
status) method_status ;;
|
||||
list) method_list ;;
|
||||
task_list) method_task_list ;;
|
||||
start) service_action start ;;
|
||||
stop) service_action stop ;;
|
||||
restart) service_action restart ;;
|
||||
reload) service_action reload ;;
|
||||
*) json_init; json_add_string "error" "unknown_method"; json_dump ;;
|
||||
esac
|
||||
}
|
||||
|
||||
case "$1" in
|
||||
list) list_methods ;;
|
||||
call) call_method "$2" ;;
|
||||
*) echo '{"error":"usage: '$0' {list|call <method>}"}' ;;
|
||||
esac
|
||||
@@ -0,0 +1,640 @@
|
||||
#!/bin/sh
|
||||
# ubus RPC module for Quick Actions VLAN tab.
|
||||
# Params arrive on stdin as JSON. No positional args.
|
||||
|
||||
. /usr/share/libubox/jshn.sh
|
||||
|
||||
VLAN_DIR=/etc/quickactions/vlan
|
||||
TPL_DIR=$VLAN_DIR/templates
|
||||
GEN_DIR=$VLAN_DIR/generated
|
||||
mkdir -p "$VLAN_DIR" "$TPL_DIR" "$GEN_DIR"
|
||||
|
||||
list_methods() {
|
||||
cat <<'EOF'
|
||||
{
|
||||
"detect": {},
|
||||
"preview": { "plan": "string" },
|
||||
"apply": { "plan": "string", "safe": "string" },
|
||||
"snapshot": { "note": "string" },
|
||||
"list_snapshots": {},
|
||||
"restore": { "path": "string" },
|
||||
"confirm": {},
|
||||
"generate_cli": { "plan": "string", "target": "string" },
|
||||
"save_template": { "name": "string", "target": "string", "plan": "string", "notes": "string" },
|
||||
"list_templates": {},
|
||||
"load_template": { "name": "string" },
|
||||
"delete_template": { "name": "string" },
|
||||
"save_generated": { "name": "string", "target": "string", "content": "string" },
|
||||
"list_generated": {},
|
||||
"delete_generated": { "name": "string" },
|
||||
"lldp_neighbors": {},
|
||||
"snmp_query": { "ip": "string", "community": "string" },
|
||||
"bridge_vlan_show": {},
|
||||
"kernel_ifaces": {},
|
||||
"iface_stats": { "ifaces": "string" },
|
||||
"ping_test": { "iface": "string", "ip": "string" }
|
||||
}
|
||||
EOF
|
||||
}
|
||||
|
||||
# read stdin and populate named vars (var=json_key pairs)
|
||||
_load() {
|
||||
local payload
|
||||
payload=$(cat)
|
||||
json_load "$payload"
|
||||
while [ "$#" -ge 2 ]; do
|
||||
eval "$1=\"\$(json_get_var __v '$2'; echo \$__v)\""
|
||||
shift 2
|
||||
done
|
||||
}
|
||||
|
||||
detect() {
|
||||
json_init
|
||||
local mode="none"
|
||||
uci show network 2>/dev/null | grep -q "\.type='bridge'" && mode="dsa"
|
||||
uci show network 2>/dev/null | grep -q "^network\.@switch\[0\]" && mode="swconfig"
|
||||
|
||||
json_add_string "mode" "$mode"
|
||||
|
||||
json_add_array "bridges"
|
||||
for s in $(uci show network 2>/dev/null | grep "=device$" | cut -d. -f2 | cut -d= -f1); do
|
||||
t=$(uci -q get "network.$s.type")
|
||||
[ "$t" != "bridge" ] && continue
|
||||
name=$(uci -q get "network.$s.name")
|
||||
[ -z "$name" ] && name="$s"
|
||||
json_add_object
|
||||
json_add_string "sid" "$s"
|
||||
json_add_string "name" "$name"
|
||||
vf=$(uci -q get "network.$s.vlan_filtering")
|
||||
json_add_string "vlan_filtering" "${vf:-0}"
|
||||
json_close_object
|
||||
done
|
||||
json_close_array
|
||||
|
||||
json_add_array "bridge_vlans"
|
||||
for s in $(uci show network 2>/dev/null | grep "=bridge-vlan$" | cut -d. -f2 | cut -d= -f1); do
|
||||
json_add_object
|
||||
json_add_string "sid" "$s"
|
||||
json_add_string "device" "$(uci -q get network.$s.device)"
|
||||
json_add_string "vlan" "$(uci -q get network.$s.vlan)"
|
||||
json_add_string "ports" "$(uci -q get network.$s.ports | tr '\n' ' ')"
|
||||
json_close_object
|
||||
done
|
||||
json_close_array
|
||||
|
||||
json_add_array "interfaces"
|
||||
for s in $(uci show network 2>/dev/null | grep "=interface$" | cut -d. -f2 | cut -d= -f1); do
|
||||
json_add_object
|
||||
json_add_string "sid" "$s"
|
||||
json_add_string "device" "$(uci -q get network.$s.device)"
|
||||
json_add_string "proto" "$(uci -q get network.$s.proto)"
|
||||
json_add_string "ipaddr" "$(uci -q get network.$s.ipaddr)"
|
||||
json_add_string "netmask" "$(uci -q get network.$s.netmask)"
|
||||
json_close_object
|
||||
done
|
||||
json_close_array
|
||||
|
||||
json_add_array "dhcp"
|
||||
for s in $(uci show dhcp 2>/dev/null | grep "=dhcp$" | cut -d. -f2 | cut -d= -f1); do
|
||||
json_add_object
|
||||
json_add_string "sid" "$s"
|
||||
json_add_string "interface" "$(uci -q get dhcp.$s.interface)"
|
||||
json_add_string "start" "$(uci -q get dhcp.$s.start)"
|
||||
json_add_string "limit" "$(uci -q get dhcp.$s.limit)"
|
||||
json_close_object
|
||||
done
|
||||
json_close_array
|
||||
|
||||
json_add_array "zones"
|
||||
local i=0
|
||||
while true; do
|
||||
local name
|
||||
name=$(uci -q get "firewall.@zone[$i].name")
|
||||
[ -z "$name" ] && break
|
||||
json_add_object
|
||||
json_add_string "name" "$name"
|
||||
json_add_string "network" "$(uci -q get firewall.@zone[$i].network | tr '\n' ' ')"
|
||||
json_add_string "input" "$(uci -q get firewall.@zone[$i].input)"
|
||||
json_add_string "output" "$(uci -q get firewall.@zone[$i].output)"
|
||||
json_add_string "forward" "$(uci -q get firewall.@zone[$i].forward)"
|
||||
json_close_object
|
||||
i=$((i + 1))
|
||||
done
|
||||
json_close_array
|
||||
|
||||
json_add_array "wifi"
|
||||
for s in $(uci show wireless 2>/dev/null | grep "=wifi-iface$" | cut -d. -f2 | cut -d= -f1); do
|
||||
json_add_object
|
||||
json_add_string "sid" "$s"
|
||||
json_add_string "device" "$(uci -q get wireless.$s.device)"
|
||||
json_add_string "mode" "$(uci -q get wireless.$s.mode)"
|
||||
json_add_string "ssid" "$(uci -q get wireless.$s.ssid)"
|
||||
json_add_string "network" "$(uci -q get wireless.$s.network)"
|
||||
json_close_object
|
||||
done
|
||||
json_close_array
|
||||
|
||||
json_add_array "easymesh"
|
||||
for iface in /sys/class/net/bat0.*; do
|
||||
[ -e "$iface" ] || continue
|
||||
json_add_string "" "$(basename "$iface")"
|
||||
done
|
||||
json_close_array
|
||||
|
||||
json_add_string "kernel" "$(uname -r)"
|
||||
json_add_string "mem_mb" "$(awk '/MemTotal/ {print int($2/1024)}' /proc/meminfo 2>/dev/null)"
|
||||
json_add_string "hostname" "$(cat /proc/sys/kernel/hostname 2>/dev/null)"
|
||||
json_dump
|
||||
}
|
||||
|
||||
kernel_ifaces() {
|
||||
json_init
|
||||
json_add_array "ifaces"
|
||||
for d in /sys/class/net/*; do
|
||||
[ -e "$d" ] || continue
|
||||
local n
|
||||
n=$(basename "$d")
|
||||
case "$n" in
|
||||
lo|sit*|ip6tnl*|gre*|gretap*|erspan*|ifb*|veth*) continue ;;
|
||||
esac
|
||||
local up
|
||||
up="0"; [ "$(cat "$d/operstate" 2>/dev/null)" = "up" ] && up="1"
|
||||
json_add_object
|
||||
json_add_string "name" "$n"
|
||||
json_add_int "up" "$up"
|
||||
json_close_object
|
||||
done
|
||||
json_close_array
|
||||
json_dump
|
||||
}
|
||||
|
||||
preview() {
|
||||
local plan
|
||||
_load plan plan
|
||||
[ -z "$plan" ] && { json_init; json_add_string "error" "no plan"; json_dump; return; }
|
||||
echo "$plan" > "$VLAN_DIR/last-plan.json"
|
||||
local out
|
||||
out=$(
|
||||
python3 - <<'PYPREVIEW' 2>&1
|
||||
import json
|
||||
plan = json.load(open("/etc/quickactions/vlan/last-plan.json"))
|
||||
lines = []
|
||||
for v in plan.get("vlans", []):
|
||||
lines.append("network.%s=bridge-vlan device=%s vlan=%s" % (
|
||||
v.get("sid","vlan"), v.get("bridge",""), v.get("vlan","")))
|
||||
for i in plan.get("interfaces", []):
|
||||
lines.append("network.%s=interface device=%s proto=%s ip=%s" % (
|
||||
i.get("name",""), i.get("device",""), i.get("proto",""), i.get("ipaddr","")))
|
||||
print("\n".join(lines))
|
||||
PYPREVIEW
|
||||
)
|
||||
json_init
|
||||
json_add_string "diff" "$out"
|
||||
json_dump
|
||||
}
|
||||
|
||||
apply() {
|
||||
local plan safe
|
||||
_load plan plan safe safe
|
||||
[ -z "$plan" ] && { json_init; json_add_string "error" "no plan"; json_dump; return; }
|
||||
[ -z "$safe" ] && safe="0"
|
||||
|
||||
local ts
|
||||
ts=$(date +%Y%m%d-%H%M%S)
|
||||
cp /etc/config/network "$VLAN_DIR/network.bak.$ts" 2>/dev/null
|
||||
echo "auto before apply" > "$VLAN_DIR/network.bak.$ts.note"
|
||||
|
||||
echo "$plan" > "$VLAN_DIR/last-plan.json"
|
||||
|
||||
if ! command -v python3 >/dev/null 2>&1; then
|
||||
json_init
|
||||
json_add_string "error" "python3 required for VLAN apply"
|
||||
json_dump
|
||||
return
|
||||
fi
|
||||
|
||||
python3 - <<'PYAPPLY'
|
||||
import json, subprocess
|
||||
plan = json.load(open("/etc/quickactions/vlan/last-plan.json"))
|
||||
|
||||
def uci(*args):
|
||||
try:
|
||||
subprocess.run(["uci"] + list(args), check=True, capture_output=True)
|
||||
except subprocess.CalledProcessError:
|
||||
return False
|
||||
return True
|
||||
|
||||
for v in plan.get("vlans", []):
|
||||
name = v.get("sid") or ("vlan_%s_%s" % (v.get("bridge","br-lan"), v.get("vlan","0")))
|
||||
uci("set", "network.%s=bridge-vlan" % name)
|
||||
uci("set", "network.%s.device=%s" % (name, v.get("bridge","")))
|
||||
uci("set", "network.%s.vlan=%s" % (name, v.get("vlan","")))
|
||||
for p in v.get("tagged", []):
|
||||
uci("add_list", "network.%s.ports=%s:t" % (name, p))
|
||||
for p in v.get("untagged", []):
|
||||
uci("add_list", "network.%s.ports=%s:u*" % (name, p))
|
||||
|
||||
for i in plan.get("interfaces", []):
|
||||
n = i.get("name","")
|
||||
if not n: continue
|
||||
uci("set", "network.%s=interface" % n)
|
||||
uci("set", "network.%s.device=%s" % (n, i.get("device","")))
|
||||
uci("set", "network.%s.proto=%s" % (n, i.get("proto","static")))
|
||||
if i.get("ipaddr"): uci("set", "network.%s.ipaddr=%s" % (n, i["ipaddr"]))
|
||||
if i.get("netmask"): uci("set", "network.%s.netmask=%s" % (n, i["netmask"]))
|
||||
|
||||
for d in plan.get("dhcp", []):
|
||||
n = d.get("name","")
|
||||
if not n: continue
|
||||
uci("set", "dhcp.%s=dhcp" % n)
|
||||
uci("set", "dhcp.%s.interface=%s" % (n, d.get("interface","")))
|
||||
uci("set", "dhcp.%s.start=%s" % (n, d.get("start","100")))
|
||||
uci("set", "dhcp.%s.limit=%s" % (n, d.get("limit","150")))
|
||||
uci("set", "dhcp.%s.leasetime=%s" % (n, d.get("leasetime","12h")))
|
||||
|
||||
for z in plan.get("zones", []):
|
||||
n = z.get("name","")
|
||||
if not n: continue
|
||||
exists = subprocess.run(["uci","-q","get","firewall.%s" % n], capture_output=True).returncode == 0
|
||||
if not exists:
|
||||
uci("set", "firewall.%s=zone" % n)
|
||||
uci("set", "firewall.%s.name=%s" % (n, n))
|
||||
for net in z.get("network", []):
|
||||
uci("add_list", "firewall.%s.network=%s" % (n, net))
|
||||
uci("set", "firewall.%s.input=%s" % (n, z.get("input","REJECT")))
|
||||
uci("set", "firewall.%s.output=%s" % (n, z.get("output","ACCEPT")))
|
||||
uci("set", "firewall.%s.forward=%s" % (n, z.get("forward","REJECT")))
|
||||
|
||||
subprocess.run(["uci","commit","network"])
|
||||
subprocess.run(["uci","commit","dhcp"])
|
||||
subprocess.run(["uci","commit","firewall"])
|
||||
PYAPPLY
|
||||
|
||||
if [ "$safe" = "1" ]; then
|
||||
local now deadline
|
||||
now=$(date +%s)
|
||||
deadline=$((now + 90))
|
||||
echo "$deadline" > "$VLAN_DIR/pending_rollback"
|
||||
( sleep 90
|
||||
if [ -f "$VLAN_DIR/pending_rollback" ]; then
|
||||
dl=$(cat "$VLAN_DIR/pending_rollback" 2>/dev/null)
|
||||
if [ "$dl" = "$deadline" ]; then
|
||||
cp "$VLAN_DIR/network.bak.$ts" /etc/config/network
|
||||
uci commit network
|
||||
/etc/init.d/network reload
|
||||
rm -f "$VLAN_DIR/pending_rollback"
|
||||
fi
|
||||
fi ) >/dev/null 2>&1 &
|
||||
fi
|
||||
|
||||
/etc/init.d/network reload >/dev/null 2>&1
|
||||
sleep 2
|
||||
|
||||
json_init
|
||||
json_add_boolean "ok" 1
|
||||
json_add_string "snapshot" "$VLAN_DIR/network.bak.$ts"
|
||||
[ "$safe" = "1" ] && json_add_int "rollback_in" 90
|
||||
json_dump
|
||||
}
|
||||
|
||||
snapshot() {
|
||||
local note
|
||||
_load note note
|
||||
[ -z "$note" ] && note="manual"
|
||||
local ts path
|
||||
ts=$(date +%Y%m%d-%H%M%S)
|
||||
path="$VLAN_DIR/network.bak.$ts"
|
||||
cp /etc/config/network "$path" 2>/dev/null || { json_init; json_add_string "error" "cp failed"; json_dump; return; }
|
||||
echo "$note" > "$path.note" 2>/dev/null
|
||||
ls -1t $VLAN_DIR/network.bak.* 2>/dev/null | grep -v '\.note$' | tail -n +21 | while read -r old; do
|
||||
rm -f "$old" "$old.note"
|
||||
done
|
||||
json_init
|
||||
json_add_string "path" "$path"
|
||||
json_add_string "ts" "$ts"
|
||||
json_dump
|
||||
}
|
||||
|
||||
list_snapshots() {
|
||||
json_init
|
||||
json_add_array "snapshots"
|
||||
for f in $(ls -1t $VLAN_DIR/network.bak.* 2>/dev/null | grep -v '\.note$'); do
|
||||
[ -f "$f" ] || continue
|
||||
local sz note
|
||||
sz=$(wc -c < "$f" 2>/dev/null)
|
||||
note=""
|
||||
[ -f "$f.note" ] && note=$(cat "$f.note" 2>/dev/null)
|
||||
json_add_object
|
||||
json_add_string "path" "$f"
|
||||
json_add_string "size" "${sz:-0}"
|
||||
json_add_string "note" "$note"
|
||||
json_close_object
|
||||
done
|
||||
json_close_array
|
||||
json_add_string "pending" "$(cat $VLAN_DIR/pending_rollback 2>/dev/null)"
|
||||
json_dump
|
||||
}
|
||||
|
||||
restore() {
|
||||
local path
|
||||
_load path path
|
||||
[ -z "$path" ] || [ ! -f "$path" ] && { json_init; json_add_string "error" "bad path"; json_dump; return; }
|
||||
cp "$path" /etc/config/network
|
||||
uci commit network
|
||||
/etc/init.d/network reload >/dev/null 2>&1
|
||||
json_init
|
||||
json_add_boolean "ok" 1
|
||||
json_dump
|
||||
}
|
||||
|
||||
confirm() {
|
||||
rm -f "$VLAN_DIR/pending_rollback"
|
||||
json_init
|
||||
json_add_boolean "ok" 1
|
||||
json_dump
|
||||
}
|
||||
|
||||
generate_cli() {
|
||||
local plan target
|
||||
_load plan plan target target
|
||||
[ -z "$target" ] && target="generic"
|
||||
echo "$plan" > "$VLAN_DIR/last-plan.json"
|
||||
local out
|
||||
out=$(
|
||||
python3 - <<PYGEN
|
||||
import json
|
||||
plan = json.load(open("/etc/quickactions/vlan/last-plan.json"))
|
||||
target = "$target"
|
||||
out = []
|
||||
|
||||
if target == "mikrotik":
|
||||
bridge = plan["vlans"][0].get("bridge","bridge1") if plan.get("vlans") else "bridge1"
|
||||
pvid = {}
|
||||
for v in plan.get("vlans", []):
|
||||
for p in v.get("untagged", []):
|
||||
pvid[p] = v.get("vlan")
|
||||
out.append("/interface bridge")
|
||||
out.append("add name=%s vlan-filtering=yes" % bridge)
|
||||
out.append("/interface bridge port")
|
||||
for p, vid in pvid.items():
|
||||
out.append("add bridge=%s interface=%s pvid=%s" % (bridge, p, vid))
|
||||
out.append("/interface bridge vlan")
|
||||
for v in plan.get("vlans", []):
|
||||
t = ",".join(v.get("tagged",[]))
|
||||
u = ",".join(v.get("untagged",[]))
|
||||
parts = ["bridge=%s" % bridge, "vlan-ids=%s" % v.get("vlan","")]
|
||||
if t: parts.append("tagged=%s" % t)
|
||||
if u: parts.append("untagged=%s" % u)
|
||||
out.append("add " + " ".join(parts))
|
||||
|
||||
elif target == "cisco":
|
||||
for v in plan.get("vlans", []):
|
||||
out.append("vlan %s" % v.get("vlan",""))
|
||||
out.append(" name VLAN_%s" % v.get("vlan",""))
|
||||
out.append("!")
|
||||
trunks = set()
|
||||
for v in plan.get("vlans", []):
|
||||
for p in v.get("tagged", []):
|
||||
trunks.add(p)
|
||||
for p in sorted(trunks):
|
||||
out.append("interface %s" % p)
|
||||
out.append(" switchport trunk encapsulation dot1q")
|
||||
out.append(" switchport mode trunk")
|
||||
allowed = []
|
||||
for v in plan.get("vlans", []):
|
||||
if p in v.get("tagged", []):
|
||||
allowed.append(str(v.get("vlan")))
|
||||
out.append(" switchport trunk allowed vlan %s" % ",".join(allowed))
|
||||
out.append("!")
|
||||
for v in plan.get("vlans", []):
|
||||
for p in v.get("untagged", []):
|
||||
out.append("interface %s" % p)
|
||||
out.append(" switchport mode access")
|
||||
out.append(" switchport access vlan %s" % v.get("vlan",""))
|
||||
out.append("!")
|
||||
|
||||
elif target == "edgeos":
|
||||
for v in plan.get("vlans", []):
|
||||
vid = v.get("vlan","")
|
||||
for p in v.get("tagged", []):
|
||||
out.append("set interfaces ethernet %s vif %s description VLAN_%s" % (p, vid, vid))
|
||||
for p in v.get("untagged", []):
|
||||
out.append("set interfaces ethernet %s description VLAN_%s" % (p, vid))
|
||||
out.append("set interfaces ethernet %s pvid %s" % (p, vid))
|
||||
|
||||
else:
|
||||
out.append("VLAN Ports (T=tagged, U=untagged)")
|
||||
for v in plan.get("vlans", []):
|
||||
plist = []
|
||||
for p in v.get("tagged", []): plist.append("%s T" % p)
|
||||
for p in v.get("untagged", []): plist.append("%s U" % p)
|
||||
out.append("%-5s %s" % (v.get("vlan",""), ", ".join(plist)))
|
||||
|
||||
print("\n".join(out))
|
||||
PYGEN
|
||||
)
|
||||
json_init
|
||||
json_add_string "cli" "$out"
|
||||
json_add_string "target" "$target"
|
||||
json_dump
|
||||
}
|
||||
|
||||
save_template() {
|
||||
local name target plan notes
|
||||
_load name name target target plan plan notes notes
|
||||
[ -z "$name" ] && { json_init; json_add_string "error" "name required"; json_dump; return; }
|
||||
local fname
|
||||
fname=$(echo "$name" | tr -c 'a-zA-Z0-9._-' '_')
|
||||
printf '%s\n' "$plan" > "$TPL_DIR/$fname.json"
|
||||
printf '{"target":"%s","notes":"%s"}\n' "$target" "$notes" > "$TPL_DIR/$fname.meta"
|
||||
json_init
|
||||
json_add_string "name" "$fname"
|
||||
json_dump
|
||||
}
|
||||
|
||||
list_templates() {
|
||||
json_init
|
||||
json_add_array "templates"
|
||||
for f in $TPL_DIR/*.json; do
|
||||
[ -f "$f" ] || continue
|
||||
local b meta
|
||||
b=$(basename "$f" .json)
|
||||
meta="{}"
|
||||
[ -f "$TPL_DIR/$b.meta" ] && meta=$(cat "$TPL_DIR/$b.meta")
|
||||
json_add_object
|
||||
json_add_string "name" "$b"
|
||||
json_add_string "meta" "$meta"
|
||||
json_close_object
|
||||
done
|
||||
json_close_array
|
||||
json_dump
|
||||
}
|
||||
|
||||
load_template() {
|
||||
local name
|
||||
_load name name
|
||||
local fname
|
||||
fname=$(echo "$name" | tr -c 'a-zA-Z0-9._-' '_')
|
||||
if [ ! -f "$TPL_DIR/$fname.json" ]; then
|
||||
json_init; json_add_string "error" "not found"; json_dump; return
|
||||
fi
|
||||
json_init
|
||||
json_add_string "plan" "$(cat "$TPL_DIR/$fname.json")"
|
||||
[ -f "$TPL_DIR/$fname.meta" ] && json_add_string "meta" "$(cat "$TPL_DIR/$fname.meta")"
|
||||
json_dump
|
||||
}
|
||||
|
||||
delete_template() {
|
||||
local name
|
||||
_load name name
|
||||
local fname
|
||||
fname=$(echo "$name" | tr -c 'a-zA-Z0-9._-' '_')
|
||||
rm -f "$TPL_DIR/$fname.json" "$TPL_DIR/$fname.meta"
|
||||
json_init; json_add_boolean "ok" 1; json_dump
|
||||
}
|
||||
|
||||
save_generated() {
|
||||
local name target content
|
||||
_load name name target target content content
|
||||
[ -z "$name" ] && name="gen-$(date +%s)"
|
||||
local fname
|
||||
fname=$(echo "$name" | tr -c 'a-zA-Z0-9._-' '_')
|
||||
printf '%s\n' "$content" > "$GEN_DIR/$fname.txt"
|
||||
echo "$target" > "$GEN_DIR/$fname.target"
|
||||
ls -1t $GEN_DIR/*.txt 2>/dev/null | tail -n +51 | while read -r old; do
|
||||
rm -f "$old" "$old.target"
|
||||
done
|
||||
json_init; json_add_string "name" "$fname"; json_dump
|
||||
}
|
||||
|
||||
list_generated() {
|
||||
json_init
|
||||
json_add_array "generated"
|
||||
for f in $GEN_DIR/*.txt; do
|
||||
[ -f "$f" ] || continue
|
||||
local b tgt
|
||||
b=$(basename "$f" .txt)
|
||||
tgt=""
|
||||
[ -f "$GEN_DIR/$b.target" ] && tgt=$(cat "$GEN_DIR/$b.target")
|
||||
json_add_object
|
||||
json_add_string "name" "$b"
|
||||
json_add_string "target" "$tgt"
|
||||
json_close_object
|
||||
done
|
||||
json_close_array
|
||||
json_dump
|
||||
}
|
||||
|
||||
delete_generated() {
|
||||
local name
|
||||
_load name name
|
||||
local fname
|
||||
fname=$(echo "$name" | tr -c 'a-zA-Z0-9._-' '_')
|
||||
rm -f "$GEN_DIR/$fname.txt" "$GEN_DIR/$fname.target"
|
||||
json_init; json_add_boolean "ok" 1; json_dump
|
||||
}
|
||||
|
||||
lldp_neighbors() {
|
||||
if ! command -v lldpcli >/dev/null 2>&1; then
|
||||
json_init; json_add_string "error" "lldpcli not installed"; json_dump; return
|
||||
fi
|
||||
local out
|
||||
out=$(lldpcli show neighbors 2>&1)
|
||||
json_init
|
||||
json_add_string "output" "$out"
|
||||
json_dump
|
||||
}
|
||||
|
||||
snmp_query() {
|
||||
local ip community
|
||||
_load ip ip community community
|
||||
[ -z "$community" ] && community="public"
|
||||
if ! command -v snmpwalk >/dev/null 2>&1; then
|
||||
json_init; json_add_string "error" "snmpwalk not installed"; json_dump; return
|
||||
fi
|
||||
local out
|
||||
out=$(snmpwalk -v2c -c "$community" -t 3 -r 1 "$ip" 1.3.6.1.2.1.17.7.1.4.3.1.2 2>&1)
|
||||
json_init
|
||||
json_add_string "ip" "$ip"
|
||||
json_add_string "output" "$out"
|
||||
json_dump
|
||||
}
|
||||
|
||||
bridge_vlan_show() {
|
||||
local out
|
||||
out=$(bridge vlan show 2>&1)
|
||||
json_init
|
||||
json_add_string "output" "$out"
|
||||
json_dump
|
||||
}
|
||||
|
||||
iface_stats() {
|
||||
local ifaces
|
||||
_load ifaces ifaces
|
||||
json_init
|
||||
json_add_array "stats"
|
||||
for i in $ifaces; do
|
||||
[ -d "/sys/class/net/$i" ] || continue
|
||||
local rx tx
|
||||
rx=$(cat /sys/class/net/$i/statistics/rx_bytes 2>/dev/null)
|
||||
tx=$(cat /sys/class/net/$i/statistics/tx_bytes 2>/dev/null)
|
||||
json_add_object
|
||||
json_add_string "iface" "$i"
|
||||
json_add_int "rx" "${rx:-0}"
|
||||
json_add_int "tx" "${tx:-0}"
|
||||
json_close_object
|
||||
done
|
||||
json_close_array
|
||||
json_dump
|
||||
}
|
||||
|
||||
ping_test() {
|
||||
local iface ip
|
||||
_load iface iface ip ip
|
||||
[ -z "$iface" ] && { json_init; json_add_string "error" "missing iface"; json_dump; return; }
|
||||
[ -z "$ip" ] && { json_init; json_add_string "error" "missing ip"; json_dump; return; }
|
||||
local out rc
|
||||
out=$(ping -I "$iface" -c 3 -W 3 "$ip" 2>&1)
|
||||
rc=$?
|
||||
json_init
|
||||
json_add_string "output" "$out"
|
||||
json_add_int "exit_code" "$rc"
|
||||
json_dump
|
||||
}
|
||||
|
||||
call_method() {
|
||||
local method="$1"
|
||||
case "$method" in
|
||||
detect) detect ;;
|
||||
preview) preview ;;
|
||||
apply) apply ;;
|
||||
snapshot) snapshot ;;
|
||||
list_snapshots) list_snapshots ;;
|
||||
restore) restore ;;
|
||||
confirm) confirm ;;
|
||||
generate_cli) generate_cli ;;
|
||||
save_template) save_template ;;
|
||||
list_templates) list_templates ;;
|
||||
load_template) load_template ;;
|
||||
delete_template) delete_template ;;
|
||||
save_generated) save_generated ;;
|
||||
list_generated) list_generated ;;
|
||||
delete_generated) delete_generated ;;
|
||||
lldp_neighbors) lldp_neighbors ;;
|
||||
snmp_query) snmp_query ;;
|
||||
bridge_vlan_show) bridge_vlan_show ;;
|
||||
kernel_ifaces) kernel_ifaces ;;
|
||||
iface_stats) iface_stats ;;
|
||||
ping_test) ping_test ;;
|
||||
*) cat >/dev/null
|
||||
json_init
|
||||
json_add_string "error" "unknown_method"
|
||||
json_dump ;;
|
||||
esac
|
||||
}
|
||||
|
||||
case "$1" in
|
||||
list) list_methods ;;
|
||||
call) call_method "$2" ;;
|
||||
*) echo '{"error":"usage"}' ;;
|
||||
esac
|
||||
Reference in new issue
Block a user