filtron.sh 12 KB

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