filtron.sh 13 KB

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