filtron.sh 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452
  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. If needed, set PUBLIC_URL of your WEB service in the '${DOT_CONFIG#"$REPO_ROOT/"}' file::
  73. PUBLIC_URL : ${PUBLIC_URL}
  74. PUBLIC_HOST : ${PUBLIC_HOST}
  75. SERVICE_USER : ${SERVICE_USER}
  76. FILTRON_API : ${FILTRON_API}
  77. FILTRON_LISTEN : ${FILTRON_LISTEN}
  78. FILTRON_TARGET : ${FILTRON_TARGET}
  79. EOF
  80. [[ -n ${1} ]] && err_msg "$1"
  81. }
  82. main() {
  83. rst_title "$SERVICE_NAME" part
  84. required_commands \
  85. dpkg apt-get install git wget curl \
  86. || exit
  87. local _usage="unknown or missing $1 command $2"
  88. case $1 in
  89. --source-only) ;;
  90. -h|--help) usage; exit 0;;
  91. shell)
  92. sudo_or_exit
  93. interactive_shell "${SERVICE_USER}"
  94. ;;
  95. inspect)
  96. case $2 in
  97. service)
  98. sudo_or_exit
  99. inspect_service
  100. ;;
  101. *) usage "$_usage"; exit 42;;
  102. esac ;;
  103. install)
  104. sudo_or_exit
  105. case $2 in
  106. all) install_all ;;
  107. user) assert_user ;;
  108. rules)
  109. rst_title "Re-Install filtron rules"
  110. echo
  111. install_template --no-eval "$FILTRON_RULES" root root 644
  112. systemd_restart_service "${SERVICE_NAME}"
  113. ;;
  114. *) usage "$_usage"; exit 42;;
  115. esac ;;
  116. update)
  117. sudo_or_exit
  118. case $2 in
  119. filtron) update_filtron ;;
  120. *) usage "$_usage"; exit 42;;
  121. esac ;;
  122. remove)
  123. sudo_or_exit
  124. case $2 in
  125. all) remove_all;;
  126. user) drop_service_account "${SERVICE_USER}" ;;
  127. *) usage "$_usage"; exit 42;;
  128. esac ;;
  129. activate)
  130. sudo_or_exit
  131. case $2 in
  132. service) systemd_activate_service "${SERVICE_NAME}" ;;
  133. *) usage "$_usage"; exit 42;;
  134. esac ;;
  135. deactivate)
  136. sudo_or_exit
  137. case $2 in
  138. service) systemd_deactivate_service "${SERVICE_NAME}" ;;
  139. *) usage "$_usage"; exit 42;;
  140. esac ;;
  141. apache)
  142. sudo_or_exit
  143. case $2 in
  144. install) install_apache_site ;;
  145. remove) remove_apache_site ;;
  146. *) usage "$_usage"; exit 42;;
  147. esac ;;
  148. option)
  149. sudo_or_exit
  150. case $2 in
  151. debug-on) echo; enable_debug ;;
  152. debug-off) echo; disable_debug ;;
  153. *) usage "$_usage"; exit 42;;
  154. esac ;;
  155. *) usage "unknown or missing command $1"; exit 42;;
  156. esac
  157. }
  158. install_all() {
  159. rst_title "Install $SERVICE_NAME (service)"
  160. assert_user
  161. wait_key
  162. install_go "${GO_PKG_URL}" "${GO_TAR}" "${SERVICE_USER}"
  163. wait_key
  164. install_filtron
  165. wait_key
  166. systemd_install_service "${SERVICE_NAME}" "${SERVICE_SYSTEMD_UNIT}"
  167. wait_key
  168. echo
  169. if ! service_is_available "http://${FILTRON_LISTEN}" ; then
  170. err_msg "Filtron does not listening on: http://${FILTRON_LISTEN}"
  171. fi
  172. if apache_is_installed; then
  173. info_msg "Apache is installed on this host."
  174. if ask_yn "Do you want to install a reverse proxy (ProxyPass)" Yn; then
  175. install_apache_site
  176. fi
  177. fi
  178. if ask_yn "Do you want to inspect the installation?" Yn; then
  179. inspect_service
  180. fi
  181. }
  182. remove_all() {
  183. rst_title "De-Install $SERVICE_NAME (service)"
  184. rst_para "\
  185. It goes without saying that this script can only be used to remove
  186. installations that were installed with this script."
  187. if ! systemd_remove_service "${SERVICE_NAME}" "${SERVICE_SYSTEMD_UNIT}"; then
  188. return 42
  189. fi
  190. drop_service_account "${SERVICE_USER}"
  191. rm -r "$FILTRON_ETC" 2>&1 | prefix_stdout
  192. if service_is_available "${PUBLIC_URL}"; then
  193. MSG="** Don't forget to remove your public site! (${PUBLIC_URL}) **" wait_key 10
  194. fi
  195. }
  196. assert_user() {
  197. rst_title "user $SERVICE_USER" section
  198. echo
  199. tee_stderr 1 <<EOF | bash | prefix_stdout
  200. sudo -H adduser --shell /bin/bash --system --home $SERVICE_HOME \
  201. --disabled-password --group --gecos 'Filtron' $SERVICE_USER
  202. sudo -H usermod -a -G shadow $SERVICE_USER
  203. groups $SERVICE_USER
  204. EOF
  205. SERVICE_HOME="$(sudo -i -u "$SERVICE_USER" echo \$HOME)"
  206. export SERVICE_HOME
  207. echo "export SERVICE_HOME=$SERVICE_HOME"
  208. cat > "$GO_ENV" <<EOF
  209. export GOPATH=\$HOME/go-apps
  210. export PATH=\$PATH:\$HOME/local/go/bin:\$GOPATH/bin
  211. EOF
  212. echo "Environment $GO_ENV has been setup."
  213. tee_stderr <<EOF | sudo -i -u "$SERVICE_USER"
  214. grep -qFs -- 'source $GO_ENV' ~/.profile || echo 'source $GO_ENV' >> ~/.profile
  215. EOF
  216. }
  217. filtron_is_installed() {
  218. [[ -f $SERVICE_HOME/go-apps/bin/filtron ]]
  219. }
  220. _svcpr=" |${SERVICE_USER}| "
  221. install_filtron() {
  222. rst_title "Install filtron in user's ~/go-apps" section
  223. echo
  224. tee_stderr <<EOF | sudo -i -u "$SERVICE_USER" 2>&1 | prefix_stdout "$_svcpr"
  225. go get -v -u github.com/asciimoo/filtron
  226. EOF
  227. install_template --no-eval "$FILTRON_RULES" root root 644
  228. }
  229. update_filtron() {
  230. rst_title "Update filtron" section
  231. echo
  232. tee_stderr <<EOF | sudo -i -u "$SERVICE_USER" 2>&1 | prefix_stdout "$_svcpr"
  233. go get -v -u github.com/asciimoo/filtron
  234. EOF
  235. }
  236. inspect_service() {
  237. rst_title "service status & log"
  238. cat <<EOF
  239. sourced ${DOT_CONFIG#"$REPO_ROOT/"} :
  240. PUBLIC_URL : ${PUBLIC_URL}
  241. PUBLIC_HOST : ${PUBLIC_HOST}
  242. FILTRON_URL_PATH : ${FILTRON_URL_PATH}
  243. FILTRON_API : ${FILTRON_API}
  244. FILTRON_LISTEN : ${FILTRON_LISTEN}
  245. FILTRON_TARGET : ${FILTRON_TARGET}
  246. EOF
  247. apache_is_installed && info_msg "Apache is installed."
  248. if service_account_is_available "$SERVICE_USER"; then
  249. info_msg "service account $SERVICE_USER available."
  250. else
  251. err_msg "service account $SERVICE_USER not available!"
  252. fi
  253. if go_is_available "$SERVICE_USER"; then
  254. info_msg "~$SERVICE_USER: go is installed"
  255. else
  256. err_msg "~$SERVICE_USER: go is not installed"
  257. fi
  258. if filtron_is_installed; then
  259. info_msg "~$SERVICE_USER: filtron app is installed"
  260. else
  261. err_msg "~$SERVICE_USER: filtron app is not installed!"
  262. fi
  263. if ! service_is_available "http://${FILTRON_API}"; then
  264. err_msg "API not available at: http://${FILTRON_API}"
  265. fi
  266. if ! service_is_available "http://${FILTRON_LISTEN}" ; then
  267. err_msg "Filtron does not listening on: http://${FILTRON_LISTEN}"
  268. fi
  269. if service_is_available "http://${FILTRON_TARGET}" ; then
  270. info_msg "Filtron's target is available at: http://${FILTRON_TARGET}"
  271. fi
  272. if ! service_is_available "${PUBLIC_URL}"; then
  273. err_msg "Public service at ${PUBLIC_URL} is not available!"
  274. echo -e "${_Green}stop with [${_BCyan}CTRL-C${_Green}] or .."
  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. # ----------------------------------------------------------------------------