filtron.sh 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505
  1. #!/usr/bin/env bash
  2. # -*- coding: utf-8; mode: sh indent-tabs-mode: nil -*-
  3. # SPDX-License-Identifier: AGPL-3.0-or-later
  4. # shellcheck disable=SC2119,SC2001
  5. # shellcheck source=utils/lib.sh
  6. source "$(dirname "${BASH_SOURCE[0]}")/lib.sh"
  7. # shellcheck source=utils/brand.env
  8. source "${REPO_ROOT}/utils/brand.env"
  9. source_dot_config
  10. source "${REPO_ROOT}/utils/lxc-searx.env"
  11. in_container && lxc_set_suite_env
  12. # ----------------------------------------------------------------------------
  13. # config
  14. # ----------------------------------------------------------------------------
  15. PUBLIC_URL="${PUBLIC_URL:-http://$(uname -n)/searx}"
  16. PUBLIC_HOST="${PUBLIC_HOST:-$(echo "$PUBLIC_URL" | sed -e 's/[^/]*\/\/\([^@]*@\)\?\([^:/]*\).*/\2/')}"
  17. FILTRON_URL_PATH="${FILTRON_URL_PATH:-$(echo "${PUBLIC_URL}" \
  18. | sed -e 's,^.*://[^/]*\(/.*\),\1,g')}"
  19. [[ "${FILTRON_URL_PATH}" == "${PUBLIC_URL}" ]] && FILTRON_URL_PATH=/
  20. FILTRON_ETC="/etc/filtron"
  21. FILTRON_RULES="$FILTRON_ETC/rules.json"
  22. FILTRON_API="${FILTRON_API:-127.0.0.1:4005}"
  23. FILTRON_LISTEN="${FILTRON_LISTEN:-127.0.0.1:4004}"
  24. FILTRON_TARGET="${FILTRON_TARGET:-127.0.0.1:8888}"
  25. SERVICE_NAME="filtron"
  26. SERVICE_USER="${SERVICE_USER:-${SERVICE_NAME}}"
  27. SERVICE_HOME_BASE="${SERVICE_HOME_BASE:-/usr/local}"
  28. SERVICE_HOME="${SERVICE_HOME_BASE}/${SERVICE_USER}"
  29. SERVICE_SYSTEMD_UNIT="${SYSTEMD_UNITS}/${SERVICE_NAME}.service"
  30. # shellcheck disable=SC2034
  31. SERVICE_GROUP="${SERVICE_USER}"
  32. # shellcheck disable=SC2034
  33. SERVICE_GROUP="${SERVICE_USER}"
  34. GO_ENV="${SERVICE_HOME}/.go_env"
  35. GO_PKG_URL="https://dl.google.com/go/go1.13.5.linux-amd64.tar.gz"
  36. GO_TAR=$(basename "$GO_PKG_URL")
  37. # Apache Settings
  38. APACHE_FILTRON_SITE="searx.conf"
  39. # shellcheck disable=SC2034
  40. CONFIG_FILES=(
  41. "${FILTRON_RULES}"
  42. "${SERVICE_SYSTEMD_UNIT}"
  43. )
  44. # ----------------------------------------------------------------------------
  45. usage() {
  46. # ----------------------------------------------------------------------------
  47. # shellcheck disable=SC1117
  48. cat <<EOF
  49. usage::
  50. $(basename "$0") shell
  51. $(basename "$0") install [all|user|rules]
  52. $(basename "$0") update [filtron]
  53. $(basename "$0") remove [all]
  54. $(basename "$0") activate [service]
  55. $(basename "$0") deactivate [service]
  56. $(basename "$0") inspect [service]
  57. $(basename "$0") option [debug-on|debug-off]
  58. $(basename "$0") apache [install|remove]
  59. shell
  60. start interactive shell from user ${SERVICE_USER}
  61. install / remove
  62. :all: complete setup of filtron service
  63. :user: add/remove service user '$SERVICE_USER' ($SERVICE_HOME)
  64. :rules: reinstall filtron rules $FILTRON_RULES
  65. update filtron
  66. Update filtron installation ($SERVICE_HOME)
  67. activate service
  68. activate and start service daemon (systemd unit)
  69. deactivate service
  70. stop and deactivate service daemon (systemd unit)
  71. inspect service
  72. show service status and log
  73. option
  74. set one of the available options
  75. apache (${PUBLIC_URL})
  76. :install: apache site with a reverse proxy (ProxyPass)
  77. :remove: apache site ${APACHE_FILTRON_SITE}
  78. filtron rules: ${FILTRON_RULES}
  79. If needed, set PUBLIC_URL of your WEB service in the '${DOT_CONFIG#"$REPO_ROOT/"}' file::
  80. PUBLIC_URL : ${PUBLIC_URL}
  81. PUBLIC_HOST : ${PUBLIC_HOST}
  82. SERVICE_USER : ${SERVICE_USER}
  83. FILTRON_TARGET : ${FILTRON_TARGET}
  84. FILTRON_API : ${FILTRON_API}
  85. FILTRON_LISTEN : ${FILTRON_LISTEN}
  86. EOF
  87. if in_container; then
  88. # in containers the service is listening on 0.0.0.0 (see lxc-searx.env)
  89. for ip in $(global_IPs) ; do
  90. if [[ $ip =~ .*:.* ]]; then
  91. echo " container URL (IPv6): http://[${ip#*|}]:4005/"
  92. else
  93. # IPv4:
  94. echo " container URL (IPv4): http://${ip#*|}:4005/"
  95. fi
  96. done
  97. fi
  98. [[ -n ${1} ]] && err_msg "$1"
  99. }
  100. main() {
  101. rst_title "$SERVICE_NAME" part
  102. required_commands \
  103. sudo install git wget curl \
  104. || exit
  105. local _usage="unknown or missing $1 command $2"
  106. case $1 in
  107. --source-only) ;;
  108. -h|--help) usage; exit 0;;
  109. shell)
  110. sudo_or_exit
  111. interactive_shell "${SERVICE_USER}"
  112. ;;
  113. inspect)
  114. case $2 in
  115. service)
  116. sudo_or_exit
  117. inspect_service
  118. ;;
  119. *) usage "$_usage"; exit 42;;
  120. esac ;;
  121. install)
  122. sudo_or_exit
  123. case $2 in
  124. all) install_all ;;
  125. user) assert_user ;;
  126. rules)
  127. rst_title "Re-Install filtron rules"
  128. echo
  129. install_template --no-eval "$FILTRON_RULES" root root 644
  130. systemd_restart_service "${SERVICE_NAME}"
  131. ;;
  132. *) usage "$_usage"; exit 42;;
  133. esac ;;
  134. update)
  135. sudo_or_exit
  136. case $2 in
  137. filtron) update_filtron ;;
  138. *) usage "$_usage"; exit 42;;
  139. esac ;;
  140. remove)
  141. sudo_or_exit
  142. case $2 in
  143. all) remove_all;;
  144. user) drop_service_account "${SERVICE_USER}" ;;
  145. *) usage "$_usage"; exit 42;;
  146. esac ;;
  147. activate)
  148. sudo_or_exit
  149. case $2 in
  150. service) systemd_activate_service "${SERVICE_NAME}" ;;
  151. *) usage "$_usage"; exit 42;;
  152. esac ;;
  153. deactivate)
  154. sudo_or_exit
  155. case $2 in
  156. service) systemd_deactivate_service "${SERVICE_NAME}" ;;
  157. *) usage "$_usage"; exit 42;;
  158. esac ;;
  159. apache)
  160. sudo_or_exit
  161. case $2 in
  162. install) install_apache_site ;;
  163. remove) remove_apache_site ;;
  164. *) usage "$_usage"; exit 42;;
  165. esac ;;
  166. option)
  167. sudo_or_exit
  168. case $2 in
  169. debug-on) echo; enable_debug ;;
  170. debug-off) echo; disable_debug ;;
  171. *) usage "$_usage"; exit 42;;
  172. esac ;;
  173. doc) rst-doc ;;
  174. *) usage "unknown or missing command $1"; exit 42;;
  175. esac
  176. }
  177. install_all() {
  178. rst_title "Install $SERVICE_NAME (service)"
  179. assert_user
  180. wait_key
  181. install_go "${GO_PKG_URL}" "${GO_TAR}" "${SERVICE_USER}"
  182. wait_key
  183. install_filtron
  184. wait_key
  185. systemd_install_service "${SERVICE_NAME}" "${SERVICE_SYSTEMD_UNIT}"
  186. wait_key
  187. echo
  188. if ! service_is_available "http://${FILTRON_LISTEN}" ; then
  189. err_msg "Filtron does not listening on: http://${FILTRON_LISTEN}"
  190. fi
  191. if apache_is_installed; then
  192. info_msg "Apache is installed on this host."
  193. if ask_yn "Do you want to install a reverse proxy (ProxyPass)" Yn; then
  194. install_apache_site
  195. fi
  196. fi
  197. if ask_yn "Do you want to inspect the installation?" Ny; then
  198. inspect_service
  199. fi
  200. }
  201. remove_all() {
  202. rst_title "De-Install $SERVICE_NAME (service)"
  203. rst_para "\
  204. It goes without saying that this script can only be used to remove
  205. installations that were installed with this script."
  206. if ! systemd_remove_service "${SERVICE_NAME}" "${SERVICE_SYSTEMD_UNIT}"; then
  207. return 42
  208. fi
  209. drop_service_account "${SERVICE_USER}"
  210. rm -r "$FILTRON_ETC" 2>&1 | prefix_stdout
  211. if service_is_available "${PUBLIC_URL}"; then
  212. MSG="** Don't forget to remove your public site! (${PUBLIC_URL}) **" wait_key 10
  213. fi
  214. }
  215. assert_user() {
  216. rst_title "user $SERVICE_USER" section
  217. echo
  218. tee_stderr 1 <<EOF | bash | prefix_stdout
  219. useradd --shell /bin/bash --system \
  220. --home-dir "$SERVICE_HOME" \
  221. --comment 'Reverse HTTP proxy to filter requests' $SERVICE_USER
  222. mkdir "$SERVICE_HOME"
  223. chown -R "$SERVICE_GROUP:$SERVICE_GROUP" "$SERVICE_HOME"
  224. groups $SERVICE_USER
  225. EOF
  226. SERVICE_HOME="$(sudo -i -u "$SERVICE_USER" echo \$HOME)"
  227. export SERVICE_HOME
  228. echo "export SERVICE_HOME=$SERVICE_HOME"
  229. cat > "$GO_ENV" <<EOF
  230. export GOPATH=\$HOME/go-apps
  231. export PATH=\$PATH:\$HOME/local/go/bin:\$GOPATH/bin
  232. EOF
  233. echo "Environment $GO_ENV has been setup."
  234. tee_stderr <<EOF | sudo -i -u "$SERVICE_USER"
  235. grep -qFs -- 'source $GO_ENV' ~/.profile || echo 'source $GO_ENV' >> ~/.profile
  236. EOF
  237. }
  238. filtron_is_installed() {
  239. [[ -f $SERVICE_HOME/go-apps/bin/filtron ]]
  240. }
  241. _svcpr=" ${_Yellow}|${SERVICE_USER}|${_creset} "
  242. install_filtron() {
  243. rst_title "Install filtron in user's ~/go-apps" section
  244. echo
  245. tee_stderr <<EOF | sudo -i -u "$SERVICE_USER" 2>&1 | prefix_stdout "$_svcpr"
  246. go get -v -u github.com/asciimoo/filtron
  247. EOF
  248. install_template --no-eval "$FILTRON_RULES" root root 644
  249. }
  250. update_filtron() {
  251. rst_title "Update filtron" section
  252. echo
  253. tee_stderr <<EOF | sudo -i -u "$SERVICE_USER" 2>&1 | prefix_stdout "$_svcpr"
  254. go get -v -u github.com/asciimoo/filtron
  255. EOF
  256. }
  257. inspect_service() {
  258. rst_title "service status & log"
  259. cat <<EOF
  260. sourced ${DOT_CONFIG#"$REPO_ROOT/"} :
  261. PUBLIC_URL : ${PUBLIC_URL}
  262. PUBLIC_HOST : ${PUBLIC_HOST}
  263. FILTRON_URL_PATH : ${FILTRON_URL_PATH}
  264. FILTRON_API : ${FILTRON_API}
  265. FILTRON_LISTEN : ${FILTRON_LISTEN}
  266. FILTRON_TARGET : ${FILTRON_TARGET}
  267. EOF
  268. apache_is_installed && info_msg "Apache is installed."
  269. if service_account_is_available "$SERVICE_USER"; then
  270. info_msg "service account $SERVICE_USER available."
  271. else
  272. err_msg "service account $SERVICE_USER not available!"
  273. fi
  274. if go_is_available "$SERVICE_USER"; then
  275. info_msg "~$SERVICE_USER: go is installed"
  276. else
  277. err_msg "~$SERVICE_USER: go is not installed"
  278. fi
  279. if filtron_is_installed; then
  280. info_msg "~$SERVICE_USER: filtron app is installed"
  281. else
  282. err_msg "~$SERVICE_USER: filtron app is not installed!"
  283. fi
  284. if ! service_is_available "http://${FILTRON_API}"; then
  285. err_msg "API not available at: http://${FILTRON_API}"
  286. fi
  287. if ! service_is_available "http://${FILTRON_LISTEN}" ; then
  288. err_msg "Filtron does not listening on: http://${FILTRON_LISTEN}"
  289. fi
  290. if service_is_available "http://${FILTRON_TARGET}" ; then
  291. info_msg "Filtron's target is available at: http://${FILTRON_TARGET}"
  292. fi
  293. if ! service_is_available "${PUBLIC_URL}"; then
  294. warn_msg "Public service at ${PUBLIC_URL} is not available!"
  295. if ! in_container; then
  296. warn_msg "Check if public name is correct and routed or use the public IP from above."
  297. fi
  298. fi
  299. if in_container; then
  300. lxc_suite_info
  301. else
  302. info_msg "public URL --> ${PUBLIC_URL}"
  303. info_msg "internal URL --> http://${FILTRON_LISTEN}"
  304. fi
  305. local _debug_on
  306. if ask_yn "Enable filtron debug mode?"; then
  307. enable_debug
  308. _debug_on=1
  309. fi
  310. echo
  311. systemctl --no-pager -l status "${SERVICE_NAME}"
  312. echo
  313. info_msg "public URL --> ${PUBLIC_URL}"
  314. # shellcheck disable=SC2059
  315. printf "// use ${_BCyan}CTRL-C${_creset} to stop monitoring the log"
  316. read -r -s -n1 -t 5
  317. echo
  318. while true; do
  319. trap break 2
  320. journalctl -f -u "${SERVICE_NAME}"
  321. done
  322. if [[ $_debug_on == 1 ]]; then
  323. disable_debug
  324. fi
  325. return 0
  326. }
  327. enable_debug() {
  328. info_msg "try to enable debug mode ..."
  329. python <<EOF
  330. import sys, json
  331. debug = {
  332. u'name': u'debug request'
  333. , u'filters': []
  334. , u'interval': 0
  335. , u'limit': 0
  336. , u'actions': [{u'name': u'log'}]
  337. }
  338. with open('$FILTRON_RULES') as rules:
  339. j = json.load(rules)
  340. pos = None
  341. for i in range(len(j)):
  342. if j[i].get('name') == 'debug request':
  343. pos = i
  344. break
  345. if pos is not None:
  346. j[pos] = debug
  347. else:
  348. j.append(debug)
  349. with open('$FILTRON_RULES', 'w') as rules:
  350. json.dump(j, rules, indent=2, sort_keys=True)
  351. EOF
  352. systemctl restart "${SERVICE_NAME}.service"
  353. }
  354. disable_debug() {
  355. info_msg "try to disable debug mode ..."
  356. python <<EOF
  357. import sys, json
  358. with open('$FILTRON_RULES') as rules:
  359. j = json.load(rules)
  360. pos = None
  361. for i in range(len(j)):
  362. if j[i].get('name') == 'debug request':
  363. pos = i
  364. break
  365. if pos is not None:
  366. del j[pos]
  367. with open('$FILTRON_RULES', 'w') as rules:
  368. json.dump(j, rules, indent=2, sort_keys=True)
  369. EOF
  370. systemctl restart "${SERVICE_NAME}.service"
  371. }
  372. install_apache_site() {
  373. rst_title "Install Apache site $APACHE_FILTRON_SITE"
  374. rst_para "\
  375. This installs a reverse proxy (ProxyPass) into apache site (${APACHE_FILTRON_SITE})"
  376. ! apache_is_installed && err_msg "Apache is not installed."
  377. if ! ask_yn "Do you really want to continue?"; then
  378. return
  379. fi
  380. a2enmod headers
  381. a2enmod proxy
  382. a2enmod proxy_http
  383. echo
  384. apache_install_site --variant=filtron "${APACHE_FILTRON_SITE}"
  385. info_msg "testing public url .."
  386. if ! service_is_available "${PUBLIC_URL}"; then
  387. err_msg "Public service at ${PUBLIC_URL} is not available!"
  388. fi
  389. }
  390. remove_apache_site() {
  391. rst_title "Remove Apache site $APACHE_FILTRON_SITE"
  392. rst_para "\
  393. This removes apache site ${APACHE_FILTRON_SITE}."
  394. ! apache_is_installed && err_msg "Apache is not installed."
  395. if ! ask_yn "Do you really want to continue?"; then
  396. return
  397. fi
  398. apache_remove_site "$APACHE_FILTRON_SITE"
  399. }
  400. rst-doc() {
  401. eval "echo \"$(< "${REPO_ROOT}/docs/build-templates/filtron.rst")\""
  402. echo -e "\n.. START install systemd unit"
  403. cat <<EOF
  404. .. tabs::
  405. .. group-tab:: systemd
  406. .. code:: bash
  407. EOF
  408. eval "echo \"$(< "${TEMPLATES}/${SERVICE_SYSTEMD_UNIT}")\"" | prefix_stdout " "
  409. echo -e "\n.. END install systemd unit"
  410. # for DIST_NAME in ubuntu-20.04 arch fedora; do
  411. # (
  412. # DIST_ID=${DIST_NAME%-*}
  413. # DIST_VERS=${DIST_NAME#*-}
  414. # [[ $DIST_VERS =~ $DIST_ID ]] && DIST_VERS=
  415. # # ...
  416. # )
  417. # done
  418. }
  419. # ----------------------------------------------------------------------------
  420. main "$@"
  421. # ----------------------------------------------------------------------------