filtron.sh 12 KB

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