filtron.sh 12 KB

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