morty.sh 15 KB

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