filtron.sh 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496
  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) rst-doc ;;
  163. *) usage "unknown or missing command $1"; exit 42;;
  164. esac
  165. }
  166. install_all() {
  167. rst_title "Install $SERVICE_NAME (service)"
  168. assert_user
  169. wait_key
  170. install_go "${GO_PKG_URL}" "${GO_TAR}" "${SERVICE_USER}"
  171. wait_key
  172. install_filtron
  173. wait_key
  174. systemd_install_service "${SERVICE_NAME}" "${SERVICE_SYSTEMD_UNIT}"
  175. wait_key
  176. echo
  177. if ! service_is_available "http://${FILTRON_LISTEN}" ; then
  178. err_msg "Filtron does not listening on: http://${FILTRON_LISTEN}"
  179. fi
  180. if apache_is_installed; then
  181. info_msg "Apache is installed on this host."
  182. if ask_yn "Do you want to install a reverse proxy (ProxyPass)" Yn; then
  183. install_apache_site
  184. fi
  185. fi
  186. if ask_yn "Do you want to inspect the installation?" Ny; then
  187. inspect_service
  188. fi
  189. }
  190. remove_all() {
  191. rst_title "De-Install $SERVICE_NAME (service)"
  192. rst_para "\
  193. It goes without saying that this script can only be used to remove
  194. installations that were installed with this script."
  195. if ! systemd_remove_service "${SERVICE_NAME}" "${SERVICE_SYSTEMD_UNIT}"; then
  196. return 42
  197. fi
  198. drop_service_account "${SERVICE_USER}"
  199. rm -r "$FILTRON_ETC" 2>&1 | prefix_stdout
  200. if service_is_available "${PUBLIC_URL}"; then
  201. MSG="** Don't forget to remove your public site! (${PUBLIC_URL}) **" wait_key 10
  202. fi
  203. }
  204. assert_user() {
  205. rst_title "user $SERVICE_USER" section
  206. echo
  207. tee_stderr 1 <<EOF | bash | prefix_stdout
  208. useradd --shell /bin/bash --system \
  209. --home-dir "$SERVICE_HOME" \
  210. --comment 'Reverse HTTP proxy to filter requests' $SERVICE_USER
  211. mkdir "$SERVICE_HOME"
  212. chown -R "$SERVICE_GROUP:$SERVICE_GROUP" "$SERVICE_HOME"
  213. groups $SERVICE_USER
  214. EOF
  215. SERVICE_HOME="$(sudo -i -u "$SERVICE_USER" echo \$HOME)"
  216. export SERVICE_HOME
  217. echo "export SERVICE_HOME=$SERVICE_HOME"
  218. cat > "$GO_ENV" <<EOF
  219. export GOPATH=\$HOME/go-apps
  220. export PATH=\$PATH:\$HOME/local/go/bin:\$GOPATH/bin
  221. EOF
  222. echo "Environment $GO_ENV has been setup."
  223. tee_stderr <<EOF | sudo -i -u "$SERVICE_USER"
  224. grep -qFs -- 'source $GO_ENV' ~/.profile || echo 'source $GO_ENV' >> ~/.profile
  225. EOF
  226. }
  227. filtron_is_installed() {
  228. [[ -f $SERVICE_HOME/go-apps/bin/filtron ]]
  229. }
  230. _svcpr=" ${_Yellow}|${SERVICE_USER}|${_creset} "
  231. install_filtron() {
  232. rst_title "Install filtron in user's ~/go-apps" section
  233. echo
  234. tee_stderr <<EOF | sudo -i -u "$SERVICE_USER" 2>&1 | prefix_stdout "$_svcpr"
  235. go get -v -u github.com/asciimoo/filtron
  236. EOF
  237. install_template --no-eval "$FILTRON_RULES" root root 644
  238. }
  239. update_filtron() {
  240. rst_title "Update filtron" section
  241. echo
  242. tee_stderr <<EOF | sudo -i -u "$SERVICE_USER" 2>&1 | prefix_stdout "$_svcpr"
  243. go get -v -u github.com/asciimoo/filtron
  244. EOF
  245. }
  246. inspect_service() {
  247. rst_title "service status & log"
  248. cat <<EOF
  249. sourced ${DOT_CONFIG#"$REPO_ROOT/"} :
  250. PUBLIC_URL : ${PUBLIC_URL}
  251. PUBLIC_HOST : ${PUBLIC_HOST}
  252. FILTRON_URL_PATH : ${FILTRON_URL_PATH}
  253. FILTRON_API : ${FILTRON_API}
  254. FILTRON_LISTEN : ${FILTRON_LISTEN}
  255. FILTRON_TARGET : ${FILTRON_TARGET}
  256. EOF
  257. apache_is_installed && info_msg "Apache is installed."
  258. if service_account_is_available "$SERVICE_USER"; then
  259. info_msg "service account $SERVICE_USER available."
  260. else
  261. err_msg "service account $SERVICE_USER not available!"
  262. fi
  263. if go_is_available "$SERVICE_USER"; then
  264. info_msg "~$SERVICE_USER: go is installed"
  265. else
  266. err_msg "~$SERVICE_USER: go is not installed"
  267. fi
  268. if filtron_is_installed; then
  269. info_msg "~$SERVICE_USER: filtron app is installed"
  270. else
  271. err_msg "~$SERVICE_USER: filtron app is not installed!"
  272. fi
  273. if ! service_is_available "http://${FILTRON_API}"; then
  274. err_msg "API not available at: http://${FILTRON_API}"
  275. fi
  276. if ! service_is_available "http://${FILTRON_LISTEN}" ; then
  277. err_msg "Filtron does not listening on: http://${FILTRON_LISTEN}"
  278. fi
  279. if service_is_available "http://${FILTRON_TARGET}" ; then
  280. info_msg "Filtron's target is available at: http://${FILTRON_TARGET}"
  281. fi
  282. if ! service_is_available "${PUBLIC_URL}"; then
  283. warn_msg "Public service at ${PUBLIC_URL} is not available!"
  284. if ! in_container; then
  285. warn_msg "Check if public name is correct and routed or use the public IP from above."
  286. fi
  287. fi
  288. if in_container; then
  289. lxc_suite_info
  290. else
  291. info_msg "public URL --> ${PUBLIC_URL}"
  292. info_msg "internal URL --> http://${FILTRON_LISTEN}"
  293. fi
  294. local _debug_on
  295. if ask_yn "Enable filtron debug mode?"; then
  296. enable_debug
  297. _debug_on=1
  298. fi
  299. echo
  300. systemctl --no-pager -l status "${SERVICE_NAME}"
  301. echo
  302. info_msg "public URL --> ${PUBLIC_URL}"
  303. # shellcheck disable=SC2059
  304. printf "// use ${_BCyan}CTRL-C${_creset} to stop monitoring the log"
  305. read -r -s -n1 -t 5
  306. echo
  307. while true; do
  308. trap break 2
  309. journalctl -f -u "${SERVICE_NAME}"
  310. done
  311. if [[ $_debug_on == 1 ]]; then
  312. disable_debug
  313. fi
  314. return 0
  315. }
  316. enable_debug() {
  317. info_msg "try to enable debug mode ..."
  318. python <<EOF
  319. import sys, json
  320. debug = {
  321. u'name': u'debug request'
  322. , u'filters': []
  323. , u'interval': 0
  324. , u'limit': 0
  325. , u'actions': [{u'name': u'log'}]
  326. }
  327. with open('$FILTRON_RULES') as rules:
  328. j = json.load(rules)
  329. pos = None
  330. for i in range(len(j)):
  331. if j[i].get('name') == 'debug request':
  332. pos = i
  333. break
  334. if pos is not None:
  335. j[pos] = debug
  336. else:
  337. j.append(debug)
  338. with open('$FILTRON_RULES', 'w') as rules:
  339. json.dump(j, rules, indent=2, sort_keys=True)
  340. EOF
  341. systemctl restart "${SERVICE_NAME}.service"
  342. }
  343. disable_debug() {
  344. info_msg "try to disable debug mode ..."
  345. python <<EOF
  346. import sys, json
  347. with open('$FILTRON_RULES') as rules:
  348. j = json.load(rules)
  349. pos = None
  350. for i in range(len(j)):
  351. if j[i].get('name') == 'debug request':
  352. pos = i
  353. break
  354. if pos is not None:
  355. del j[pos]
  356. with open('$FILTRON_RULES', 'w') as rules:
  357. json.dump(j, rules, indent=2, sort_keys=True)
  358. EOF
  359. systemctl restart "${SERVICE_NAME}.service"
  360. }
  361. install_apache_site() {
  362. rst_title "Install Apache site $APACHE_FILTRON_SITE"
  363. rst_para "\
  364. This installs a reverse proxy (ProxyPass) into apache site (${APACHE_FILTRON_SITE})"
  365. ! apache_is_installed && err_msg "Apache is not installed."
  366. if ! ask_yn "Do you really want to continue?"; then
  367. return
  368. fi
  369. a2enmod headers
  370. a2enmod proxy
  371. a2enmod proxy_http
  372. echo
  373. apache_install_site --variant=filtron "${APACHE_FILTRON_SITE}"
  374. info_msg "testing public url .."
  375. if ! service_is_available "${PUBLIC_URL}"; then
  376. err_msg "Public service at ${PUBLIC_URL} is not available!"
  377. fi
  378. }
  379. remove_apache_site() {
  380. rst_title "Remove Apache site $APACHE_FILTRON_SITE"
  381. rst_para "\
  382. This removes apache site ${APACHE_FILTRON_SITE}."
  383. ! apache_is_installed && err_msg "Apache is not installed."
  384. if ! ask_yn "Do you really want to continue?"; then
  385. return
  386. fi
  387. apache_remove_site "$APACHE_FILTRON_SITE"
  388. }
  389. rst-doc() {
  390. eval "echo \"$(< "${REPO_ROOT}/docs/build-templates/filtron.rst")\""
  391. echo -e "\n.. START install systemd unit"
  392. cat <<EOF
  393. .. tabs::
  394. .. group-tab:: systemd
  395. .. code:: bash
  396. EOF
  397. eval "echo \"$(< "${TEMPLATES}/${SERVICE_SYSTEMD_UNIT}")\"" | prefix_stdout " "
  398. echo -e "\n.. END install systemd unit"
  399. # for DIST_NAME in ubuntu-20.04 arch fedora; do
  400. # (
  401. # DIST_ID=${DIST_NAME%-*}
  402. # DIST_VERS=${DIST_NAME#*-}
  403. # [[ $DIST_VERS =~ $DIST_ID ]] && DIST_VERS=
  404. # # ...
  405. # )
  406. # done
  407. }
  408. # ----------------------------------------------------------------------------
  409. main "$@"
  410. # ----------------------------------------------------------------------------