morty.sh 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468
  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 source=utils/lib.sh
  5. source "$(dirname "${BASH_SOURCE[0]}")/lib.sh"
  6. # shellcheck source=utils/brand.env
  7. source "${REPO_ROOT}/utils/brand.env"
  8. source_dot_config
  9. source "${REPO_ROOT}/utils/lxc-searx.env"
  10. in_container && lxc_set_suite_env
  11. # ----------------------------------------------------------------------------
  12. # config
  13. # ----------------------------------------------------------------------------
  14. MORTY_LISTEN="${MORTY_LISTEN:-127.0.0.1:3000}"
  15. PUBLIC_URL_PATH_MORTY="${PUBLIC_URL_PATH_MORTY:-/morty}"
  16. SEARX_URL="${PUBLIC_URL:-http://$(uname -n)/searx}"
  17. PUBLIC_URL_MORTY="$(echo "$SEARX_URL" | sed -e's,^\(.*://[^/]*\).*,\1,g')${PUBLIC_URL_PATH_MORTY}"
  18. if in_container; then
  19. # container hostnames do not have a DNS entry, use primary IP
  20. PUBLIC_URL_MORTY="$(url_replace_hostname "$PUBLIC_URL_MORTY" "$(primary_ip)")"
  21. fi
  22. # shellcheck disable=SC2034
  23. MORTY_TIMEOUT=5
  24. SERVICE_NAME="morty"
  25. SERVICE_USER="${SERVICE_USER:-${SERVICE_NAME}}"
  26. SERVICE_HOME_BASE="${SERVICE_HOME_BASE:-/usr/local}"
  27. SERVICE_HOME="${SERVICE_HOME_BASE}/${SERVICE_USER}"
  28. SERVICE_SYSTEMD_UNIT="${SYSTEMD_UNITS}/${SERVICE_NAME}.service"
  29. # shellcheck disable=SC2034
  30. SERVICE_GROUP="${SERVICE_USER}"
  31. # shellcheck disable=SC2034
  32. SERVICE_ENV_DEBUG=false
  33. GO_ENV="${SERVICE_HOME}/.go_env"
  34. GO_PKG_URL="https://dl.google.com/go/go1.13.5.linux-amd64.tar.gz"
  35. GO_TAR=$(basename "$GO_PKG_URL")
  36. # shellcheck disable=SC2034
  37. CONFIG_FILES=()
  38. # Apache Settings
  39. APACHE_MORTY_SITE="morty.conf"
  40. # ----------------------------------------------------------------------------
  41. usage() {
  42. # ----------------------------------------------------------------------------
  43. # shellcheck disable=SC1117
  44. cat <<EOF
  45. usage::
  46. $(basename "$0") shell
  47. $(basename "$0") install [all|user]
  48. $(basename "$0") update [morty]
  49. $(basename "$0") remove [all]
  50. $(basename "$0") activate [service]
  51. $(basename "$0") deactivate [service]
  52. $(basename "$0") inspect [service]
  53. $(basename "$0") option [debug-on|debug-off]
  54. $(basename "$0") apache [install|remove]
  55. $(basename "$0") info [searx]
  56. shell
  57. start interactive shell from user ${SERVICE_USER}
  58. install / remove
  59. all: complete setup of morty service
  60. user: add/remove service user '$SERVICE_USER' ($SERVICE_HOME)
  61. update morty
  62. Update morty installation ($SERVICE_HOME)
  63. activate service
  64. activate and start service daemon (systemd unit)
  65. deactivate service
  66. stop and deactivate service daemon (systemd unit)
  67. inspect service
  68. show service status and log
  69. option
  70. set one of the available options
  71. apache : ${PUBLIC_URL_MORTY}
  72. :install: apache site with a reverse proxy (ProxyPass)
  73. :remove: apache site ${APACHE_MORTY_SITE}
  74. If needed, set the environment variables in the '${DOT_CONFIG#"$REPO_ROOT/"}' file::
  75. PUBLIC_URL_MORTY: ${PUBLIC_URL_MORTY}
  76. MORTY_LISTEN: ${MORTY_LISTEN}
  77. SERVICE_USER: ${SERVICE_USER}
  78. EOF
  79. if in_container; then
  80. # in containers the service is listening on 0.0.0.0 (see lxc-searx.env)
  81. for ip in $(global_IPs) ; do
  82. if [[ $ip =~ .*:.* ]]; then
  83. echo " container URL (IPv6): http://[${ip#*|}]:3000/"
  84. else
  85. # IPv4:
  86. echo " container URL (IPv4): http://${ip#*|}:3000/"
  87. fi
  88. done
  89. fi
  90. echo
  91. info_searx
  92. [[ -n ${1} ]] && err_msg "$1"
  93. }
  94. info_searx() {
  95. # shellcheck disable=SC1117
  96. cat <<EOF
  97. To activate result and image proxy in searx, edit settings.yml (read:
  98. ${DOCS_URL}/admin/morty.html)::
  99. result_proxy:
  100. url : ${PUBLIC_URL_MORTY}
  101. server:
  102. image_proxy : True
  103. EOF
  104. }
  105. main() {
  106. rst_title "$SERVICE_NAME" part
  107. required_commands \
  108. sudo install git wget curl \
  109. || exit
  110. local _usage="ERROR: unknown or missing $1 command $2"
  111. case $1 in
  112. --source-only) ;;
  113. -h|--help) usage; exit 0;;
  114. shell)
  115. sudo_or_exit
  116. interactive_shell "${SERVICE_USER}"
  117. ;;
  118. inspect)
  119. case $2 in
  120. service)
  121. sudo_or_exit
  122. inspect_service
  123. ;;
  124. *) usage "$_usage"; exit 42;;
  125. esac ;;
  126. install)
  127. sudo_or_exit
  128. case $2 in
  129. all) install_all ;;
  130. user) assert_user ;;
  131. *) usage "$_usage"; exit 42;;
  132. esac ;;
  133. update)
  134. sudo_or_exit
  135. case $2 in
  136. morty) update_morty ;;
  137. *) usage "$_usage"; exit 42;;
  138. esac ;;
  139. remove)
  140. sudo_or_exit
  141. case $2 in
  142. all) remove_all;;
  143. user) drop_service_account "${SERVICE_USER}" ;;
  144. *) usage "$_usage"; exit 42;;
  145. esac ;;
  146. activate)
  147. sudo_or_exit
  148. case $2 in
  149. service) systemd_activate_service "${SERVICE_NAME}" ;;
  150. *) usage "$_usage"; exit 42;;
  151. esac ;;
  152. deactivate)
  153. sudo_or_exit
  154. case $2 in
  155. service) systemd_deactivate_service "${SERVICE_NAME}" ;;
  156. *) usage "$_usage"; exit 42;;
  157. esac ;;
  158. apache)
  159. sudo_or_exit
  160. case $2 in
  161. install) install_apache_site ;;
  162. remove) remove_apache_site ;;
  163. *) usage "$_usage"; exit 42;;
  164. esac ;;
  165. info)
  166. case $2 in
  167. searx) info_searx ;;
  168. *) usage "$_usage"; exit 42;;
  169. esac ;;
  170. option)
  171. sudo_or_exit
  172. case $2 in
  173. debug-on) enable_debug ;;
  174. debug-off) disable_debug ;;
  175. *) usage "$_usage"; exit 42;;
  176. esac ;;
  177. doc) rst-doc ;;
  178. *) usage "ERROR: unknown or missing command $1"; exit 42;;
  179. esac
  180. }
  181. install_all() {
  182. rst_title "Install $SERVICE_NAME (service)"
  183. assert_user
  184. wait_key
  185. install_go "${GO_PKG_URL}" "${GO_TAR}" "${SERVICE_USER}"
  186. wait_key
  187. install_morty
  188. wait_key
  189. systemd_install_service "${SERVICE_NAME}" "${SERVICE_SYSTEMD_UNIT}"
  190. wait_key
  191. if ! service_is_available "http://${MORTY_LISTEN}" ; then
  192. err_msg "Morty does not listening on: http://${MORTY_LISTEN}"
  193. fi
  194. if apache_is_installed; then
  195. info_msg "Apache is installed on this host."
  196. if ask_yn "Do you want to install a reverse proxy (ProxyPass)" Yn; then
  197. install_apache_site
  198. fi
  199. fi
  200. info_searx
  201. if ask_yn "Add image and result proxy to searx settings.yml?" Yn; then
  202. "${REPO_ROOT}/utils/searx.sh" option result-proxy "${PUBLIC_URL_MORTY}"
  203. "${REPO_ROOT}/utils/searx.sh" option image-proxy-on
  204. fi
  205. if ask_yn "Do you want to inspect the installation?" Ny; then
  206. inspect_service
  207. fi
  208. }
  209. remove_all() {
  210. rst_title "De-Install $SERVICE_NAME (service)"
  211. rst_para "\
  212. It goes without saying that this script can only be used to remove
  213. installations that were installed with this script."
  214. if systemd_remove_service "${SERVICE_NAME}" "${SERVICE_SYSTEMD_UNIT}"; then
  215. drop_service_account "${SERVICE_USER}"
  216. fi
  217. }
  218. assert_user() {
  219. rst_title "user $SERVICE_USER" section
  220. echo
  221. tee_stderr 1 <<EOF | bash | prefix_stdout
  222. useradd --shell /bin/bash --system \
  223. --home-dir "$SERVICE_HOME" \
  224. --comment 'Web content sanitizer proxy' $SERVICE_USER
  225. mkdir "$SERVICE_HOME"
  226. chown -R "$SERVICE_GROUP:$SERVICE_GROUP" "$SERVICE_HOME"
  227. groups $SERVICE_USER
  228. EOF
  229. SERVICE_HOME="$(sudo -i -u "$SERVICE_USER" echo \$HOME)"
  230. export SERVICE_HOME
  231. echo "export SERVICE_HOME=$SERVICE_HOME"
  232. cat > "$GO_ENV" <<EOF
  233. export GOPATH=\$HOME/go-apps
  234. export PATH=\$PATH:\$HOME/local/go/bin:\$GOPATH/bin
  235. EOF
  236. echo "Environment $GO_ENV has been setup."
  237. tee_stderr <<EOF | sudo -i -u "$SERVICE_USER"
  238. grep -qFs -- 'source $GO_ENV' ~/.profile || echo 'source $GO_ENV' >> ~/.profile
  239. EOF
  240. }
  241. morty_is_installed() {
  242. [[ -f $SERVICE_HOME/go-apps/bin/morty ]]
  243. }
  244. _svcpr=" ${_Yellow}|${SERVICE_USER}|${_creset} "
  245. install_morty() {
  246. rst_title "Install morty in user's ~/go-apps" section
  247. echo
  248. tee_stderr <<EOF | sudo -i -u "$SERVICE_USER" 2>&1 | prefix_stdout "$_svcpr"
  249. go get -v -u github.com/asciimoo/morty
  250. EOF
  251. tee_stderr <<EOF | sudo -i -u "$SERVICE_USER" 2>&1 | prefix_stdout "$_svcpr"
  252. cd \$GOPATH/src/github.com/asciimoo/morty
  253. go test
  254. go test -benchmem -bench .
  255. EOF
  256. }
  257. update_morty() {
  258. rst_title "Update morty" section
  259. echo
  260. tee_stderr <<EOF | sudo -i -u "$SERVICE_USER" 2>&1 | prefix_stdout "$_svcpr"
  261. go get -v -u github.com/asciimoo/morty
  262. EOF
  263. tee_stderr <<EOF | sudo -i -u "$SERVICE_USER" 2>&1 | prefix_stdout "$_svcpr"
  264. cd \$GOPATH/src/github.com/asciimoo/morty
  265. go test
  266. go test -benchmem -bench .
  267. EOF
  268. }
  269. set_service_env_debug() {
  270. # usage: set_service_env_debug [false|true]
  271. # shellcheck disable=SC2034
  272. local SERVICE_ENV_DEBUG="${1:-false}"
  273. if systemd_remove_service "${SERVICE_NAME}" "${SERVICE_SYSTEMD_UNIT}"; then
  274. systemd_install_service "${SERVICE_NAME}" "${SERVICE_SYSTEMD_UNIT}"
  275. fi
  276. }
  277. inspect_service() {
  278. rst_title "service status & log"
  279. cat <<EOF
  280. sourced ${DOT_CONFIG#"$REPO_ROOT/"} :
  281. MORTY_LISTEN : ${MORTY_LISTEN}
  282. EOF
  283. if service_account_is_available "$SERVICE_USER"; then
  284. info_msg "service account $SERVICE_USER available."
  285. else
  286. err_msg "service account $SERVICE_USER not available!"
  287. fi
  288. if go_is_available "$SERVICE_USER"; then
  289. info_msg "~$SERVICE_USER: go is installed"
  290. else
  291. err_msg "~$SERVICE_USER: go is not installed"
  292. fi
  293. if morty_is_installed; then
  294. info_msg "~$SERVICE_USER: morty app is installed"
  295. else
  296. err_msg "~$SERVICE_USER: morty app is not installed!"
  297. fi
  298. if ! service_is_available "http://${MORTY_LISTEN}" ; then
  299. err_msg "Morty does not listening on: http://${MORTY_LISTEN}"
  300. echo -e "${_Green}stop with [${_BCyan}CTRL-C${_Green}] or .."
  301. wait_key
  302. fi
  303. if ! service_is_available "${PUBLIC_URL}"; then
  304. warn_msg "Public service at ${PUBLIC_URL} is not available!"
  305. if ! in_container; then
  306. warn_msg "Check if public name is correct and routed or use the public IP from above."
  307. fi
  308. fi
  309. if in_container; then
  310. lxc_suite_info
  311. else
  312. info_msg "public URL --> ${PUBLIC_URL_MORTY}"
  313. info_msg "morty URL --> http://${MORTY_LISTEN}"
  314. fi
  315. local _debug_on
  316. if ask_yn "Enable filtron debug mode (needs reinstall of systemd service)?"; then
  317. enable_debug
  318. _debug_on=1
  319. else
  320. systemctl --no-pager -l status "${SERVICE_NAME}"
  321. fi
  322. echo
  323. # shellcheck disable=SC2059
  324. printf "// use ${_BCyan}CTRL-C${_creset} to stop monitoring the log"
  325. read -r -s -n1 -t 5
  326. echo
  327. while true; do
  328. trap break 2
  329. journalctl -f -u "${SERVICE_NAME}"
  330. done
  331. if [[ $_debug_on == 1 ]]; then
  332. FORCE_SELECTION=Y disable_debug
  333. fi
  334. return 0
  335. }
  336. enable_debug() {
  337. warn_msg "Do not enable debug in production enviroments!!"
  338. info_msg "Enabling debug option needs to reinstall systemd service!"
  339. set_service_env_debug true
  340. }
  341. disable_debug() {
  342. info_msg "Disabling debug option needs to reinstall systemd service!"
  343. set_service_env_debug false
  344. }
  345. install_apache_site() {
  346. rst_title "Install Apache site $APACHE_MORTY_SITE"
  347. rst_para "\
  348. This installs a reverse proxy (ProxyPass) into apache site (${APACHE_MORTY_SITE})"
  349. ! apache_is_installed && err_msg "Apache is not installed."
  350. if ! ask_yn "Do you really want to continue?" Yn; then
  351. return
  352. else
  353. install_apache
  354. fi
  355. apache_install_site "${APACHE_MORTY_SITE}"
  356. info_msg "testing public url .."
  357. if ! service_is_available "${PUBLIC_URL_MORTY}"; then
  358. err_msg "Public service at ${PUBLIC_URL_MORTY} is not available!"
  359. fi
  360. }
  361. remove_apache_site() {
  362. rst_title "Remove Apache site $APACHE_MORTY_SITE"
  363. rst_para "\
  364. This removes apache site ${APACHE_MORTY_SITE}."
  365. ! apache_is_installed && err_msg "Apache is not installed."
  366. if ! ask_yn "Do you really want to continue?" Yn; then
  367. return
  368. fi
  369. apache_remove_site "$APACHE_MORTY_SITE"
  370. }
  371. rst-doc() {
  372. eval "echo \"$(< "${REPO_ROOT}/docs/build-templates/morty.rst")\""
  373. echo -e "\n.. START install systemd unit"
  374. cat <<EOF
  375. .. tabs::
  376. .. group-tab:: systemd
  377. .. code:: bash
  378. EOF
  379. eval "echo \"$(< "${TEMPLATES}/${SERVICE_SYSTEMD_UNIT}")\"" | prefix_stdout " "
  380. echo -e "\n.. END install systemd unit"
  381. # for DIST_NAME in ubuntu-20.04 arch fedora; do
  382. # (
  383. # DIST_ID=${DIST_NAME%-*}
  384. # DIST_VERS=${DIST_NAME#*-}
  385. # [[ $DIST_VERS =~ $DIST_ID ]] && DIST_VERS=
  386. # # ...
  387. # )
  388. # done
  389. }
  390. # ----------------------------------------------------------------------------
  391. main "$@"
  392. # ----------------------------------------------------------------------------