filtron.sh 12 KB

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