secubox-openwrt/package/secubox/luci-app-haproxy/root/usr/libexec/rpcd/luci.haproxy
CyberMind-FR 3a5655451e feat(haproxy): Add edit functionality for backends, servers, and vhosts
- Add showEditVhostModal() for editing virtual host properties
- Add showEditBackendModal() for editing backend configuration
- Add showEditServerModal() for editing server properties
- Modern card-based UI with inline edit/delete actions
- Toggle enable/disable for backends
- Fix haproxyctl to read server option from backend UCI sections
- Add debug logging to container startup script

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-25 05:56:03 +01:00

1287 lines
32 KiB
Bash

#!/bin/sh
# SPDX-License-Identifier: MIT
# LuCI RPCD backend for HAProxy
# Copyright (C) 2025 CyberMind.fr
. /lib/functions.sh
. /usr/share/libubox/jshn.sh
HAPROXYCTL="/usr/sbin/haproxyctl"
UCI_CONFIG="haproxy"
# Helper: Run haproxyctl command
run_ctl() {
if [ -x "$HAPROXYCTL" ]; then
"$HAPROXYCTL" "$@" 2>&1
else
echo "haproxyctl not found"
return 1
fi
}
# Helper: Get UCI value
get_uci() {
local section="$1"
local option="$2"
local default="$3"
local value
value=$(uci -q get "$UCI_CONFIG.$section.$option")
echo "${value:-$default}"
}
# Helper: Set UCI value
set_uci() {
local section="$1"
local option="$2"
local value="$3"
uci set "$UCI_CONFIG.$section.$option=$value"
}
# Helper: List UCI sections of type
list_sections() {
local type="$1"
uci -q show "$UCI_CONFIG" | grep "=$type\$" | cut -d. -f2 | cut -d= -f1
}
# Status method
method_status() {
local enabled http_port https_port stats_port stats_enabled
local container_running haproxy_running
enabled=$(get_uci main enabled 0)
http_port=$(get_uci main http_port 80)
https_port=$(get_uci main https_port 443)
stats_port=$(get_uci main stats_port 8404)
stats_enabled=$(get_uci main stats_enabled 1)
# Check container status
if lxc-info -n haproxy >/dev/null 2>&1; then
container_running=$(lxc-info -n haproxy -s 2>/dev/null | grep -q "RUNNING" && echo "1" || echo "0")
else
container_running="0"
fi
# Check HAProxy process in container
if [ "$container_running" = "1" ]; then
haproxy_running=$(lxc-attach -n haproxy -- pgrep haproxy >/dev/null 2>&1 && echo "1" || echo "0")
else
haproxy_running="0"
fi
json_init
json_add_boolean "enabled" "$enabled"
json_add_int "http_port" "$http_port"
json_add_int "https_port" "$https_port"
json_add_int "stats_port" "$stats_port"
json_add_boolean "stats_enabled" "$stats_enabled"
json_add_boolean "container_running" "$container_running"
json_add_boolean "haproxy_running" "$haproxy_running"
json_dump
}
# Get stats
method_get_stats() {
local stats_output
if lxc-info -n haproxy -s 2>/dev/null | grep -q "RUNNING"; then
# Get stats via HAProxy socket
stats_output=$(run_ctl stats 2>/dev/null)
if [ -n "$stats_output" ]; then
json_init
json_add_boolean "success" 1
json_add_string "stats" "$stats_output"
json_dump
return
fi
fi
json_init
json_add_boolean "success" 0
json_add_string "error" "HAProxy not running or stats unavailable"
json_dump
}
# List vhosts
method_list_vhosts() {
json_init
json_add_array "vhosts"
config_load "$UCI_CONFIG"
config_foreach _add_vhost vhost
json_close_array
json_dump
}
_add_vhost() {
local section="$1"
local domain backend ssl ssl_redirect acme enabled
config_get domain "$section" domain ""
config_get backend "$section" backend ""
config_get ssl "$section" ssl "0"
config_get ssl_redirect "$section" ssl_redirect "1"
config_get acme "$section" acme "0"
config_get enabled "$section" enabled "1"
json_add_object
json_add_string "id" "$section"
json_add_string "domain" "$domain"
json_add_string "backend" "$backend"
json_add_boolean "ssl" "$ssl"
json_add_boolean "ssl_redirect" "$ssl_redirect"
json_add_boolean "acme" "$acme"
json_add_boolean "enabled" "$enabled"
json_close_object
}
# Get vhost
method_get_vhost() {
local id
read -r input
json_load "$input"
json_get_var id id
if [ -z "$id" ]; then
json_init
json_add_boolean "success" 0
json_add_string "error" "Missing vhost id"
json_dump
return
fi
local domain backend ssl ssl_redirect acme enabled
domain=$(get_uci "$id" domain "")
backend=$(get_uci "$id" backend "")
ssl=$(get_uci "$id" ssl "0")
ssl_redirect=$(get_uci "$id" ssl_redirect "1")
acme=$(get_uci "$id" acme "0")
enabled=$(get_uci "$id" enabled "1")
json_init
json_add_boolean "success" 1
json_add_string "id" "$id"
json_add_string "domain" "$domain"
json_add_string "backend" "$backend"
json_add_boolean "ssl" "$ssl"
json_add_boolean "ssl_redirect" "$ssl_redirect"
json_add_boolean "acme" "$acme"
json_add_boolean "enabled" "$enabled"
json_dump
}
# Create vhost
method_create_vhost() {
local domain backend ssl ssl_redirect acme enabled
local section_id
read -r input
json_load "$input"
json_get_var domain domain
json_get_var backend backend
json_get_var ssl ssl "0"
json_get_var ssl_redirect ssl_redirect "1"
json_get_var acme acme "0"
json_get_var enabled enabled "1"
if [ -z "$domain" ]; then
json_init
json_add_boolean "success" 0
json_add_string "error" "Domain is required"
json_dump
return
fi
# Generate section ID from domain
section_id=$(echo "$domain" | sed 's/[^a-zA-Z0-9]/_/g')
uci set "$UCI_CONFIG.$section_id=vhost"
uci set "$UCI_CONFIG.$section_id.domain=$domain"
uci set "$UCI_CONFIG.$section_id.backend=$backend"
uci set "$UCI_CONFIG.$section_id.ssl=$ssl"
uci set "$UCI_CONFIG.$section_id.ssl_redirect=$ssl_redirect"
uci set "$UCI_CONFIG.$section_id.acme=$acme"
uci set "$UCI_CONFIG.$section_id.enabled=$enabled"
uci commit "$UCI_CONFIG"
# Regenerate HAProxy config
run_ctl generate >/dev/null 2>&1
json_init
json_add_boolean "success" 1
json_add_string "id" "$section_id"
json_dump
}
# Update vhost
method_update_vhost() {
local id domain backend ssl ssl_redirect acme enabled
read -r input
json_load "$input"
json_get_var id id
json_get_var domain domain
json_get_var backend backend
json_get_var ssl ssl
json_get_var ssl_redirect ssl_redirect
json_get_var acme acme
json_get_var enabled enabled
if [ -z "$id" ]; then
json_init
json_add_boolean "success" 0
json_add_string "error" "Missing vhost id"
json_dump
return
fi
[ -n "$domain" ] && uci set "$UCI_CONFIG.$id.domain=$domain"
[ -n "$backend" ] && uci set "$UCI_CONFIG.$id.backend=$backend"
[ -n "$ssl" ] && uci set "$UCI_CONFIG.$id.ssl=$ssl"
[ -n "$ssl_redirect" ] && uci set "$UCI_CONFIG.$id.ssl_redirect=$ssl_redirect"
[ -n "$acme" ] && uci set "$UCI_CONFIG.$id.acme=$acme"
[ -n "$enabled" ] && uci set "$UCI_CONFIG.$id.enabled=$enabled"
uci commit "$UCI_CONFIG"
run_ctl generate >/dev/null 2>&1
json_init
json_add_boolean "success" 1
json_dump
}
# Delete vhost
method_delete_vhost() {
local id
read -r input
json_load "$input"
json_get_var id id
if [ -z "$id" ]; then
json_init
json_add_boolean "success" 0
json_add_string "error" "Missing vhost id"
json_dump
return
fi
uci delete "$UCI_CONFIG.$id"
uci commit "$UCI_CONFIG"
run_ctl generate >/dev/null 2>&1
json_init
json_add_boolean "success" 1
json_dump
}
# List backends
method_list_backends() {
json_init
json_add_array "backends"
config_load "$UCI_CONFIG"
config_foreach _add_backend backend
json_close_array
json_dump
}
_add_backend() {
local section="$1"
local name mode balance health_check enabled
config_get name "$section" name "$section"
config_get mode "$section" mode "http"
config_get balance "$section" balance "roundrobin"
config_get health_check "$section" health_check ""
config_get enabled "$section" enabled "1"
json_add_object
json_add_string "id" "$section"
json_add_string "name" "$name"
json_add_string "mode" "$mode"
json_add_string "balance" "$balance"
json_add_string "health_check" "$health_check"
json_add_boolean "enabled" "$enabled"
json_close_object
}
# Get backend
method_get_backend() {
local id
read -r input
json_load "$input"
json_get_var id id
if [ -z "$id" ]; then
json_init
json_add_boolean "success" 0
json_add_string "error" "Missing backend id"
json_dump
return
fi
local name mode balance health_check enabled
name=$(get_uci "$id" name "$id")
mode=$(get_uci "$id" mode "http")
balance=$(get_uci "$id" balance "roundrobin")
health_check=$(get_uci "$id" health_check "")
enabled=$(get_uci "$id" enabled "1")
json_init
json_add_boolean "success" 1
json_add_string "id" "$id"
json_add_string "name" "$name"
json_add_string "mode" "$mode"
json_add_string "balance" "$balance"
json_add_string "health_check" "$health_check"
json_add_boolean "enabled" "$enabled"
# Add servers for this backend
json_add_array "servers"
config_load "$UCI_CONFIG"
config_foreach _add_server_for_backend server "$id"
json_close_array
json_dump
}
_add_server_for_backend() {
local section="$1"
local backend_filter="$2"
local backend name address port weight check enabled
config_get backend "$section" backend ""
[ "$backend" != "$backend_filter" ] && return
config_get name "$section" name "$section"
config_get address "$section" address ""
config_get port "$section" port ""
config_get weight "$section" weight "100"
config_get check "$section" check "1"
config_get enabled "$section" enabled "1"
json_add_object
json_add_string "id" "$section"
json_add_string "name" "$name"
json_add_string "address" "$address"
json_add_int "port" "$port"
json_add_int "weight" "$weight"
json_add_boolean "check" "$check"
json_add_boolean "enabled" "$enabled"
json_close_object
}
# Create backend
method_create_backend() {
local name mode balance health_check enabled
local section_id
read -r input
json_load "$input"
json_get_var name name
json_get_var mode mode "http"
json_get_var balance balance "roundrobin"
json_get_var health_check health_check ""
json_get_var enabled enabled "1"
if [ -z "$name" ]; then
json_init
json_add_boolean "success" 0
json_add_string "error" "Backend name is required"
json_dump
return
fi
section_id=$(echo "$name" | sed 's/[^a-zA-Z0-9]/_/g')
uci set "$UCI_CONFIG.$section_id=backend"
uci set "$UCI_CONFIG.$section_id.name=$name"
uci set "$UCI_CONFIG.$section_id.mode=$mode"
uci set "$UCI_CONFIG.$section_id.balance=$balance"
[ -n "$health_check" ] && uci set "$UCI_CONFIG.$section_id.health_check=$health_check"
uci set "$UCI_CONFIG.$section_id.enabled=$enabled"
uci commit "$UCI_CONFIG"
run_ctl generate >/dev/null 2>&1
json_init
json_add_boolean "success" 1
json_add_string "id" "$section_id"
json_dump
}
# Update backend
method_update_backend() {
local id name mode balance health_check enabled
read -r input
json_load "$input"
json_get_var id id
json_get_var name name
json_get_var mode mode
json_get_var balance balance
json_get_var health_check health_check
json_get_var enabled enabled
if [ -z "$id" ]; then
json_init
json_add_boolean "success" 0
json_add_string "error" "Missing backend id"
json_dump
return
fi
[ -n "$name" ] && uci set "$UCI_CONFIG.$id.name=$name"
[ -n "$mode" ] && uci set "$UCI_CONFIG.$id.mode=$mode"
[ -n "$balance" ] && uci set "$UCI_CONFIG.$id.balance=$balance"
[ -n "$health_check" ] && uci set "$UCI_CONFIG.$id.health_check=$health_check"
[ -n "$enabled" ] && uci set "$UCI_CONFIG.$id.enabled=$enabled"
uci commit "$UCI_CONFIG"
run_ctl generate >/dev/null 2>&1
json_init
json_add_boolean "success" 1
json_dump
}
# Delete backend
method_delete_backend() {
local id
read -r input
json_load "$input"
json_get_var id id
if [ -z "$id" ]; then
json_init
json_add_boolean "success" 0
json_add_string "error" "Missing backend id"
json_dump
return
fi
# Delete associated servers
config_load "$UCI_CONFIG"
config_foreach _delete_server_for_backend server "$id"
uci delete "$UCI_CONFIG.$id"
uci commit "$UCI_CONFIG"
run_ctl generate >/dev/null 2>&1
json_init
json_add_boolean "success" 1
json_dump
}
_delete_server_for_backend() {
local section="$1"
local backend_filter="$2"
local backend
config_get backend "$section" backend ""
[ "$backend" = "$backend_filter" ] && uci delete "$UCI_CONFIG.$section"
}
# List servers
method_list_servers() {
local backend_filter
read -r input
json_load "$input"
json_get_var backend_filter backend ""
json_init
json_add_array "servers"
config_load "$UCI_CONFIG"
if [ -n "$backend_filter" ]; then
config_foreach _add_server_for_backend server "$backend_filter"
else
config_foreach _add_server server
fi
json_close_array
json_dump
}
_add_server() {
local section="$1"
local backend name address port weight check enabled
config_get backend "$section" backend ""
config_get name "$section" name "$section"
config_get address "$section" address ""
config_get port "$section" port ""
config_get weight "$section" weight "100"
config_get check "$section" check "1"
config_get enabled "$section" enabled "1"
json_add_object
json_add_string "id" "$section"
json_add_string "backend" "$backend"
json_add_string "name" "$name"
json_add_string "address" "$address"
json_add_int "port" "$port"
json_add_int "weight" "$weight"
json_add_boolean "check" "$check"
json_add_boolean "enabled" "$enabled"
json_close_object
}
# Create server
method_create_server() {
local backend name address port weight check enabled
local section_id
read -r input
json_load "$input"
json_get_var backend backend
json_get_var name name
json_get_var address address
json_get_var port port
json_get_var weight weight "100"
json_get_var check check "1"
json_get_var enabled enabled "1"
if [ -z "$backend" ] || [ -z "$name" ] || [ -z "$address" ] || [ -z "$port" ]; then
json_init
json_add_boolean "success" 0
json_add_string "error" "Backend, name, address and port are required"
json_dump
return
fi
section_id="${backend}_$(echo "$name" | sed 's/[^a-zA-Z0-9]/_/g')"
uci set "$UCI_CONFIG.$section_id=server"
uci set "$UCI_CONFIG.$section_id.backend=$backend"
uci set "$UCI_CONFIG.$section_id.name=$name"
uci set "$UCI_CONFIG.$section_id.address=$address"
uci set "$UCI_CONFIG.$section_id.port=$port"
uci set "$UCI_CONFIG.$section_id.weight=$weight"
uci set "$UCI_CONFIG.$section_id.check=$check"
uci set "$UCI_CONFIG.$section_id.enabled=$enabled"
uci commit "$UCI_CONFIG"
run_ctl generate >/dev/null 2>&1
json_init
json_add_boolean "success" 1
json_add_string "id" "$section_id"
json_dump
}
# Update server
method_update_server() {
local id backend name address port weight check enabled
read -r input
json_load "$input"
json_get_var id id
json_get_var backend backend
json_get_var name name
json_get_var address address
json_get_var port port
json_get_var weight weight
json_get_var check check
json_get_var enabled enabled
if [ -z "$id" ]; then
json_init
json_add_boolean "success" 0
json_add_string "error" "Missing server id"
json_dump
return
fi
[ -n "$backend" ] && uci set "$UCI_CONFIG.$id.backend=$backend"
[ -n "$name" ] && uci set "$UCI_CONFIG.$id.name=$name"
[ -n "$address" ] && uci set "$UCI_CONFIG.$id.address=$address"
[ -n "$port" ] && uci set "$UCI_CONFIG.$id.port=$port"
[ -n "$weight" ] && uci set "$UCI_CONFIG.$id.weight=$weight"
[ -n "$check" ] && uci set "$UCI_CONFIG.$id.check=$check"
[ -n "$enabled" ] && uci set "$UCI_CONFIG.$id.enabled=$enabled"
uci commit "$UCI_CONFIG"
run_ctl generate >/dev/null 2>&1
json_init
json_add_boolean "success" 1
json_dump
}
# Delete server
method_delete_server() {
local id
read -r input
json_load "$input"
json_get_var id id
if [ -z "$id" ]; then
json_init
json_add_boolean "success" 0
json_add_string "error" "Missing server id"
json_dump
return
fi
uci delete "$UCI_CONFIG.$id"
uci commit "$UCI_CONFIG"
run_ctl generate >/dev/null 2>&1
json_init
json_add_boolean "success" 1
json_dump
}
# List certificates
method_list_certificates() {
json_init
json_add_array "certificates"
config_load "$UCI_CONFIG"
config_foreach _add_certificate certificate
json_close_array
json_dump
}
_add_certificate() {
local section="$1"
local domain type enabled
config_get domain "$section" domain ""
config_get type "$section" type "acme"
config_get enabled "$section" enabled "1"
json_add_object
json_add_string "id" "$section"
json_add_string "domain" "$domain"
json_add_string "type" "$type"
json_add_boolean "enabled" "$enabled"
json_close_object
}
# Request certificate (ACME)
method_request_certificate() {
local domain
read -r input
json_load "$input"
json_get_var domain domain
if [ -z "$domain" ]; then
json_init
json_add_boolean "success" 0
json_add_string "error" "Domain is required"
json_dump
return
fi
local result
result=$(run_ctl cert add "$domain" 2>&1)
local rc=$?
json_init
if [ $rc -eq 0 ]; then
json_add_boolean "success" 1
json_add_string "message" "Certificate requested for $domain"
else
json_add_boolean "success" 0
json_add_string "error" "$result"
fi
json_dump
}
# Import certificate
method_import_certificate() {
local domain cert_data key_data
read -r input
json_load "$input"
json_get_var domain domain
json_get_var cert_data cert
json_get_var key_data key
if [ -z "$domain" ] || [ -z "$cert_data" ] || [ -z "$key_data" ]; then
json_init
json_add_boolean "success" 0
json_add_string "error" "Domain, certificate and key are required"
json_dump
return
fi
local result
result=$(run_ctl cert import "$domain" "$cert_data" "$key_data" 2>&1)
local rc=$?
json_init
if [ $rc -eq 0 ]; then
json_add_boolean "success" 1
json_add_string "message" "Certificate imported for $domain"
else
json_add_boolean "success" 0
json_add_string "error" "$result"
fi
json_dump
}
# Delete certificate
method_delete_certificate() {
local id
read -r input
json_load "$input"
json_get_var id id
if [ -z "$id" ]; then
json_init
json_add_boolean "success" 0
json_add_string "error" "Missing certificate id"
json_dump
return
fi
local domain
domain=$(get_uci "$id" domain "")
# Remove certificate files
run_ctl cert remove "$domain" >/dev/null 2>&1
uci delete "$UCI_CONFIG.$id"
uci commit "$UCI_CONFIG"
json_init
json_add_boolean "success" 1
json_dump
}
# List ACLs
method_list_acls() {
json_init
json_add_array "acls"
config_load "$UCI_CONFIG"
config_foreach _add_acl acl
json_close_array
json_dump
}
_add_acl() {
local section="$1"
local name type pattern backend enabled
config_get name "$section" name "$section"
config_get type "$section" type ""
config_get pattern "$section" pattern ""
config_get backend "$section" backend ""
config_get enabled "$section" enabled "1"
json_add_object
json_add_string "id" "$section"
json_add_string "name" "$name"
json_add_string "type" "$type"
json_add_string "pattern" "$pattern"
json_add_string "backend" "$backend"
json_add_boolean "enabled" "$enabled"
json_close_object
}
# Create ACL
method_create_acl() {
local name type pattern backend enabled
local section_id
read -r input
json_load "$input"
json_get_var name name
json_get_var type type
json_get_var pattern pattern
json_get_var backend backend
json_get_var enabled enabled "1"
if [ -z "$name" ] || [ -z "$type" ] || [ -z "$pattern" ]; then
json_init
json_add_boolean "success" 0
json_add_string "error" "Name, type and pattern are required"
json_dump
return
fi
section_id="acl_$(echo "$name" | sed 's/[^a-zA-Z0-9]/_/g')"
uci set "$UCI_CONFIG.$section_id=acl"
uci set "$UCI_CONFIG.$section_id.name=$name"
uci set "$UCI_CONFIG.$section_id.type=$type"
uci set "$UCI_CONFIG.$section_id.pattern=$pattern"
[ -n "$backend" ] && uci set "$UCI_CONFIG.$section_id.backend=$backend"
uci set "$UCI_CONFIG.$section_id.enabled=$enabled"
uci commit "$UCI_CONFIG"
run_ctl generate >/dev/null 2>&1
json_init
json_add_boolean "success" 1
json_add_string "id" "$section_id"
json_dump
}
# Update ACL
method_update_acl() {
local id name type pattern backend enabled
read -r input
json_load "$input"
json_get_var id id
json_get_var name name
json_get_var type type
json_get_var pattern pattern
json_get_var backend backend
json_get_var enabled enabled
if [ -z "$id" ]; then
json_init
json_add_boolean "success" 0
json_add_string "error" "Missing ACL id"
json_dump
return
fi
[ -n "$name" ] && uci set "$UCI_CONFIG.$id.name=$name"
[ -n "$type" ] && uci set "$UCI_CONFIG.$id.type=$type"
[ -n "$pattern" ] && uci set "$UCI_CONFIG.$id.pattern=$pattern"
[ -n "$backend" ] && uci set "$UCI_CONFIG.$id.backend=$backend"
[ -n "$enabled" ] && uci set "$UCI_CONFIG.$id.enabled=$enabled"
uci commit "$UCI_CONFIG"
run_ctl generate >/dev/null 2>&1
json_init
json_add_boolean "success" 1
json_dump
}
# Delete ACL
method_delete_acl() {
local id
read -r input
json_load "$input"
json_get_var id id
if [ -z "$id" ]; then
json_init
json_add_boolean "success" 0
json_add_string "error" "Missing ACL id"
json_dump
return
fi
uci delete "$UCI_CONFIG.$id"
uci commit "$UCI_CONFIG"
run_ctl generate >/dev/null 2>&1
json_init
json_add_boolean "success" 1
json_dump
}
# List redirects
method_list_redirects() {
json_init
json_add_array "redirects"
config_load "$UCI_CONFIG"
config_foreach _add_redirect redirect
json_close_array
json_dump
}
_add_redirect() {
local section="$1"
local name match_host target_host strip_www code enabled
config_get name "$section" name "$section"
config_get match_host "$section" match_host ""
config_get target_host "$section" target_host ""
config_get strip_www "$section" strip_www "0"
config_get code "$section" code "301"
config_get enabled "$section" enabled "1"
json_add_object
json_add_string "id" "$section"
json_add_string "name" "$name"
json_add_string "match_host" "$match_host"
json_add_string "target_host" "$target_host"
json_add_boolean "strip_www" "$strip_www"
json_add_int "code" "$code"
json_add_boolean "enabled" "$enabled"
json_close_object
}
# Create redirect
method_create_redirect() {
local name match_host target_host strip_www code enabled
local section_id
read -r input
json_load "$input"
json_get_var name name
json_get_var match_host match_host
json_get_var target_host target_host
json_get_var strip_www strip_www "0"
json_get_var code code "301"
json_get_var enabled enabled "1"
if [ -z "$name" ] || [ -z "$match_host" ]; then
json_init
json_add_boolean "success" 0
json_add_string "error" "Name and match_host are required"
json_dump
return
fi
section_id="redirect_$(echo "$name" | sed 's/[^a-zA-Z0-9]/_/g')"
uci set "$UCI_CONFIG.$section_id=redirect"
uci set "$UCI_CONFIG.$section_id.name=$name"
uci set "$UCI_CONFIG.$section_id.match_host=$match_host"
[ -n "$target_host" ] && uci set "$UCI_CONFIG.$section_id.target_host=$target_host"
uci set "$UCI_CONFIG.$section_id.strip_www=$strip_www"
uci set "$UCI_CONFIG.$section_id.code=$code"
uci set "$UCI_CONFIG.$section_id.enabled=$enabled"
uci commit "$UCI_CONFIG"
run_ctl generate >/dev/null 2>&1
json_init
json_add_boolean "success" 1
json_add_string "id" "$section_id"
json_dump
}
# Delete redirect
method_delete_redirect() {
local id
read -r input
json_load "$input"
json_get_var id id
if [ -z "$id" ]; then
json_init
json_add_boolean "success" 0
json_add_string "error" "Missing redirect id"
json_dump
return
fi
uci delete "$UCI_CONFIG.$id"
uci commit "$UCI_CONFIG"
run_ctl generate >/dev/null 2>&1
json_init
json_add_boolean "success" 1
json_dump
}
# Get settings
method_get_settings() {
json_init
# Main settings
json_add_object "main"
json_add_boolean "enabled" "$(get_uci main enabled 0)"
json_add_int "http_port" "$(get_uci main http_port 80)"
json_add_int "https_port" "$(get_uci main https_port 443)"
json_add_int "stats_port" "$(get_uci main stats_port 8404)"
json_add_boolean "stats_enabled" "$(get_uci main stats_enabled 1)"
json_add_string "stats_user" "$(get_uci main stats_user admin)"
json_add_string "stats_password" "$(get_uci main stats_password secubox)"
json_add_string "data_path" "$(get_uci main data_path /srv/haproxy)"
json_add_string "memory_limit" "$(get_uci main memory_limit 256M)"
json_add_int "maxconn" "$(get_uci main maxconn 4096)"
json_add_string "log_level" "$(get_uci main log_level warning)"
json_close_object
# Defaults
json_add_object "defaults"
json_add_string "mode" "$(get_uci defaults mode http)"
json_add_string "timeout_connect" "$(get_uci defaults timeout_connect 5s)"
json_add_string "timeout_client" "$(get_uci defaults timeout_client 30s)"
json_add_string "timeout_server" "$(get_uci defaults timeout_server 30s)"
json_add_string "timeout_http_request" "$(get_uci defaults timeout_http_request 10s)"
json_add_string "timeout_http_keep_alive" "$(get_uci defaults timeout_http_keep_alive 10s)"
json_add_int "retries" "$(get_uci defaults retries 3)"
json_close_object
# ACME settings
json_add_object "acme"
json_add_boolean "enabled" "$(get_uci acme enabled 1)"
json_add_string "email" "$(get_uci acme email admin@example.com)"
json_add_boolean "staging" "$(get_uci acme staging 0)"
json_add_string "key_type" "$(get_uci acme key_type ec-256)"
json_add_int "renew_days" "$(get_uci acme renew_days 30)"
json_close_object
json_dump
}
# Save settings
method_save_settings() {
read -r input
json_load "$input"
# Main settings
json_select "main" 2>/dev/null && {
local val
json_get_var val enabled && uci set "$UCI_CONFIG.main.enabled=$val"
json_get_var val http_port && uci set "$UCI_CONFIG.main.http_port=$val"
json_get_var val https_port && uci set "$UCI_CONFIG.main.https_port=$val"
json_get_var val stats_port && uci set "$UCI_CONFIG.main.stats_port=$val"
json_get_var val stats_enabled && uci set "$UCI_CONFIG.main.stats_enabled=$val"
json_get_var val stats_user && uci set "$UCI_CONFIG.main.stats_user=$val"
json_get_var val stats_password && uci set "$UCI_CONFIG.main.stats_password=$val"
json_get_var val data_path && uci set "$UCI_CONFIG.main.data_path=$val"
json_get_var val memory_limit && uci set "$UCI_CONFIG.main.memory_limit=$val"
json_get_var val maxconn && uci set "$UCI_CONFIG.main.maxconn=$val"
json_get_var val log_level && uci set "$UCI_CONFIG.main.log_level=$val"
json_select ..
}
# Defaults
json_select "defaults" 2>/dev/null && {
local val
json_get_var val mode && uci set "$UCI_CONFIG.defaults.mode=$val"
json_get_var val timeout_connect && uci set "$UCI_CONFIG.defaults.timeout_connect=$val"
json_get_var val timeout_client && uci set "$UCI_CONFIG.defaults.timeout_client=$val"
json_get_var val timeout_server && uci set "$UCI_CONFIG.defaults.timeout_server=$val"
json_get_var val timeout_http_request && uci set "$UCI_CONFIG.defaults.timeout_http_request=$val"
json_get_var val timeout_http_keep_alive && uci set "$UCI_CONFIG.defaults.timeout_http_keep_alive=$val"
json_get_var val retries && uci set "$UCI_CONFIG.defaults.retries=$val"
json_select ..
}
# ACME settings
json_select "acme" 2>/dev/null && {
local val
json_get_var val enabled && uci set "$UCI_CONFIG.acme.enabled=$val"
json_get_var val email && uci set "$UCI_CONFIG.acme.email=$val"
json_get_var val staging && uci set "$UCI_CONFIG.acme.staging=$val"
json_get_var val key_type && uci set "$UCI_CONFIG.acme.key_type=$val"
json_get_var val renew_days && uci set "$UCI_CONFIG.acme.renew_days=$val"
json_select ..
}
uci commit "$UCI_CONFIG"
run_ctl generate >/dev/null 2>&1
json_init
json_add_boolean "success" 1
json_dump
}
# Service control: install
method_install() {
local result
result=$(run_ctl install 2>&1)
local rc=$?
json_init
if [ $rc -eq 0 ]; then
json_add_boolean "success" 1
json_add_string "message" "HAProxy installed successfully"
else
json_add_boolean "success" 0
json_add_string "error" "$result"
fi
json_dump
}
# Service control: start
method_start() {
/etc/init.d/haproxy start >/dev/null 2>&1
json_init
json_add_boolean "success" 1
json_dump
}
# Service control: stop
method_stop() {
/etc/init.d/haproxy stop >/dev/null 2>&1
json_init
json_add_boolean "success" 1
json_dump
}
# Service control: restart
method_restart() {
/etc/init.d/haproxy restart >/dev/null 2>&1
json_init
json_add_boolean "success" 1
json_dump
}
# Service control: reload
method_reload() {
run_ctl reload >/dev/null 2>&1
json_init
json_add_boolean "success" 1
json_dump
}
# Generate config
method_generate() {
local result
result=$(run_ctl generate 2>&1)
local rc=$?
json_init
if [ $rc -eq 0 ]; then
json_add_boolean "success" 1
json_add_string "message" "Configuration generated"
else
json_add_boolean "success" 0
json_add_string "error" "$result"
fi
json_dump
}
# Validate config
method_validate() {
local result
result=$(run_ctl validate 2>&1)
local rc=$?
json_init
if [ $rc -eq 0 ]; then
json_add_boolean "valid" 1
json_add_string "message" "Configuration is valid"
else
json_add_boolean "valid" 0
json_add_string "error" "$result"
fi
json_dump
}
# Get logs
method_get_logs() {
local lines
read -r input
json_load "$input"
json_get_var lines lines "100"
local logs
logs=$(logread -l "$lines" 2>/dev/null | grep -i haproxy || echo "No HAProxy logs found")
json_init
json_add_string "logs" "$logs"
json_dump
}
# Main RPC interface
case "$1" in
list)
cat <<'EOF'
{
"status": {},
"get_stats": {},
"list_vhosts": {},
"get_vhost": { "id": "string" },
"create_vhost": { "domain": "string", "backend": "string", "ssl": "boolean", "ssl_redirect": "boolean", "acme": "boolean", "enabled": "boolean" },
"update_vhost": { "id": "string", "domain": "string", "backend": "string", "ssl": "boolean", "ssl_redirect": "boolean", "acme": "boolean", "enabled": "boolean" },
"delete_vhost": { "id": "string" },
"list_backends": {},
"get_backend": { "id": "string" },
"create_backend": { "name": "string", "mode": "string", "balance": "string", "health_check": "string", "enabled": "boolean" },
"update_backend": { "id": "string", "name": "string", "mode": "string", "balance": "string", "health_check": "string", "enabled": "boolean" },
"delete_backend": { "id": "string" },
"list_servers": { "backend": "string" },
"create_server": { "backend": "string", "name": "string", "address": "string", "port": "integer", "weight": "integer", "check": "boolean", "enabled": "boolean" },
"update_server": { "id": "string", "backend": "string", "name": "string", "address": "string", "port": "integer", "weight": "integer", "check": "boolean", "enabled": "boolean" },
"delete_server": { "id": "string" },
"list_certificates": {},
"request_certificate": { "domain": "string" },
"import_certificate": { "domain": "string", "cert": "string", "key": "string" },
"delete_certificate": { "id": "string" },
"list_acls": {},
"create_acl": { "name": "string", "type": "string", "pattern": "string", "backend": "string", "enabled": "boolean" },
"update_acl": { "id": "string", "name": "string", "type": "string", "pattern": "string", "backend": "string", "enabled": "boolean" },
"delete_acl": { "id": "string" },
"list_redirects": {},
"create_redirect": { "name": "string", "match_host": "string", "target_host": "string", "strip_www": "boolean", "code": "integer", "enabled": "boolean" },
"delete_redirect": { "id": "string" },
"get_settings": {},
"save_settings": { "main": "object", "defaults": "object", "acme": "object" },
"install": {},
"start": {},
"stop": {},
"restart": {},
"reload": {},
"generate": {},
"validate": {},
"get_logs": { "lines": "integer" }
}
EOF
;;
call)
case "$2" in
status) method_status ;;
get_stats) method_get_stats ;;
list_vhosts) method_list_vhosts ;;
get_vhost) method_get_vhost ;;
create_vhost) method_create_vhost ;;
update_vhost) method_update_vhost ;;
delete_vhost) method_delete_vhost ;;
list_backends) method_list_backends ;;
get_backend) method_get_backend ;;
create_backend) method_create_backend ;;
update_backend) method_update_backend ;;
delete_backend) method_delete_backend ;;
list_servers) method_list_servers ;;
create_server) method_create_server ;;
update_server) method_update_server ;;
delete_server) method_delete_server ;;
list_certificates) method_list_certificates ;;
request_certificate) method_request_certificate ;;
import_certificate) method_import_certificate ;;
delete_certificate) method_delete_certificate ;;
list_acls) method_list_acls ;;
create_acl) method_create_acl ;;
update_acl) method_update_acl ;;
delete_acl) method_delete_acl ;;
list_redirects) method_list_redirects ;;
create_redirect) method_create_redirect ;;
delete_redirect) method_delete_redirect ;;
get_settings) method_get_settings ;;
save_settings) method_save_settings ;;
install) method_install ;;
start) method_start ;;
stop) method_stop ;;
restart) method_restart ;;
reload) method_reload ;;
generate) method_generate ;;
validate) method_validate ;;
get_logs) method_get_logs ;;
esac
;;
esac