filtron.sh 13 KB

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