filtron.sh 12 KB

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