lib_redis.sh 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348
  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. #
  5. # Tools to build and install redis [1] binaries & packages.
  6. #
  7. # [1] https://redis.io/download#installation
  8. #
  9. # 1. redis.devpkg (sudo)
  10. # 2. redis.build
  11. # 3. redis.install (sudo)
  12. #
  13. # systemd commands::
  14. #
  15. # sudo -H systemctl status searxng-redis
  16. # sudo -H journalctl -u searxng-redis
  17. # sudo -H journalctl --vacuum-size=1M
  18. #
  19. # Test socket connection from client (local user)::
  20. #
  21. # $ sudo -H ./manage redis.addgrp "${USER}"
  22. # # logout & login to get member of group
  23. # $ groups
  24. # ... searxng-redis ...
  25. # $ source /usr/local/searxng-redis/.redis_env
  26. # $ which redis-cli
  27. # /usr/local/searxng-redis/.local/bin/redis-cli
  28. #
  29. # $ redis-cli -s /usr/local/searxng-redis/redis.sock
  30. # redis /usr/local/searxng-redis/redis.sock> set foo bar
  31. # OK
  32. # redis /usr/local/searxng-redis/redis.sock> get foo
  33. # "bar"
  34. # [CTRL-D]
  35. # shellcheck disable=SC2091
  36. # shellcheck source=utils/lib.sh
  37. . /dev/null
  38. REDIS_GIT_URL="https://github.com/redis/redis.git"
  39. REDIS_GIT_TAG="${REDIS_GIT_TAG:-6.2.6}"
  40. REDIS_USER="searxng-redis"
  41. REDIS_HOME="/usr/local/${REDIS_USER}"
  42. REDIS_HOME_BIN="${REDIS_HOME}/.local/bin"
  43. REDIS_ENV="${REDIS_HOME}/.redis_env"
  44. REDIS_SERVICE_NAME="searxng-redis"
  45. REDIS_SYSTEMD_UNIT="${SYSTEMD_UNITS}/${REDIS_SERVICE_NAME}.service"
  46. # binaries to compile & install
  47. REDIS_INSTALL_EXE=(redis-server redis-benchmark redis-cli)
  48. # link names of redis-server binary
  49. REDIS_LINK_EXE=(redis-sentinel redis-check-rdb redis-check-aof)
  50. REDIS_CONF="${REDIS_HOME}/redis.conf"
  51. REDIS_CONF_TEMPLATE=$(cat <<EOF
  52. # Note that in order to read the configuration file, Redis must be
  53. # started with the file path as first argument:
  54. #
  55. # ./redis-server /path/to/redis.conf
  56. # bind 127.0.0.1 -::1
  57. protected-mode yes
  58. # Accept connections on the specified port, default is 6379 (IANA #815344).
  59. # If port 0 is specified Redis will not listen on a TCP socket.
  60. port 0
  61. # Specify the path for the Unix socket that will be used to listen for
  62. # incoming connections.
  63. unixsocket ${REDIS_HOME}/run/redis.sock
  64. unixsocketperm 770
  65. # The working directory.
  66. dir ${REDIS_HOME}/run
  67. # If you run Redis from upstart or systemd, Redis can interact with your
  68. # supervision tree.
  69. supervised auto
  70. pidfile ${REDIS_HOME}/run/redis.pid
  71. # log to the system logger
  72. syslog-enabled yes
  73. EOF
  74. )
  75. redis.help(){
  76. cat <<EOF
  77. redis.:
  78. devpkg : install essential packages to compile redis
  79. build : build redis binaries at $(redis._get_dist)
  80. install : create user (${REDIS_USER}) and install systemd service (${REDIS_SERVICE_NAME})
  81. remove : delete user (${REDIS_USER}) and remove service (${REDIS_SERVICE_NAME})
  82. shell : start bash interpreter from user ${REDIS_USER}
  83. src : clone redis source code to <path> and checkput ${REDIS_GIT_TAG}
  84. useradd : create user (${REDIS_USER}) at ${REDIS_HOME}
  85. userdel : delete user (${REDIS_USER})
  86. addgrp : add <user> to group (${REDIS_USER})
  87. rmgrp : remove <user> from group (${REDIS_USER})
  88. EOF
  89. }
  90. redis.devpkg() {
  91. # Uses OS package manager to install the essential packages to build and
  92. # compile sources
  93. sudo_or_exit
  94. case ${DIST_ID} in
  95. ubuntu|debian)
  96. pkg_install git build-essential
  97. ;;
  98. arch)
  99. pkg_install git base-devel
  100. ;;
  101. fedora)
  102. pkg_install git @development-tools
  103. ;;
  104. centos)
  105. pkg_install git
  106. yum groupinstall "Development Tools" -y
  107. ;;
  108. *)
  109. err_msg "$DIST_ID-$DIST_VERS: No rules to install development tools from OS."
  110. return 42
  111. ;;
  112. esac
  113. }
  114. redis.build() {
  115. # usage: redis.build
  116. rst_title "get redis sources" section
  117. redis.src "${CACHE}/redis"
  118. if ! required_commands gcc nm make gawk; then
  119. sudo -H "$0" redis.devpkg
  120. fi
  121. rst_title "compile redis sources" section
  122. pushd "${CACHE}/redis" &>/dev/null
  123. if ask_yn "Do you run 'make distclean' first'?" Ny; then
  124. $(bash.cmd) -c "make distclean" 2>&1 | prefix_stdout
  125. fi
  126. $(bash.cmd) -c "make" 2>&1 | prefix_stdout
  127. if ask_yn "Do you run 'make test'?" Ny; then
  128. $(bash.cmd) -c "make test" | prefix_stdout
  129. fi
  130. popd &>/dev/null
  131. tee_stderr 0.1 <<EOF | $(bash.cmd) 2>&1 | prefix_stdout
  132. mkdir -p "$(redis._get_dist)"
  133. cd "${CACHE}/redis/src"
  134. cp ${REDIS_INSTALL_EXE[@]} "$(redis._get_dist)"
  135. EOF
  136. info_msg "redis binaries available at $(redis._get_dist)"
  137. }
  138. redis.install() {
  139. sudo_or_exit
  140. (
  141. set -e
  142. redis.useradd
  143. redis._install_bin
  144. redis._install_conf
  145. redis._install_service
  146. )
  147. dump_return $?
  148. }
  149. redis.remove() {
  150. sudo_or_exit
  151. (
  152. set -e
  153. redis._remove_service
  154. redis.userdel
  155. )
  156. dump_return $?
  157. }
  158. redis.shell() {
  159. interactive_shell "${REDIS_USER}"
  160. }
  161. redis.src() {
  162. # usage: redis.src "${CACHE}/redis"
  163. local dest="${1:-${CACHE}/redis}"
  164. if [ -d "${dest}" ] ; then
  165. info_msg "already cloned: $dest"
  166. tee_stderr 0.1 <<EOF | $(bash.cmd) 2>&1 | prefix_stdout
  167. cd "${dest}"
  168. git fetch --all
  169. git reset --hard tags/${REDIS_GIT_TAG}
  170. EOF
  171. else
  172. tee_stderr 0.1 <<EOF | $(bash.cmd) 2>&1 | prefix_stdout
  173. mkdir -p "$(dirname "$dest")"
  174. cd "$(dirname "$dest")"
  175. git clone "${REDIS_GIT_URL}" "${dest}"
  176. EOF
  177. tee_stderr 0.1 <<EOF | $(bash.cmd) 2>&1 | prefix_stdout
  178. cd "${dest}"
  179. git checkout tags/${REDIS_GIT_TAG} -b "build-branch"
  180. EOF
  181. fi
  182. }
  183. redis.useradd(){
  184. # usage: redis.useradd
  185. rst_title "add user ${REDIS_USER}" section
  186. echo
  187. sudo_or_exit
  188. # create user account
  189. tee_stderr 0.5 <<EOF | sudo -H bash | prefix_stdout
  190. useradd --shell /bin/bash --system \
  191. --home-dir "${REDIS_HOME}" \
  192. --comment 'user that runs a redis instance' "${REDIS_USER}"
  193. mkdir -p "${REDIS_HOME}"
  194. chown -R "${REDIS_USER}:${REDIS_USER}" "${REDIS_HOME}"
  195. groups "${REDIS_USER}"
  196. EOF
  197. # create App-ENV and add source it in the .profile
  198. tee_stderr 0.5 <<EOF | sudo -H -u "${REDIS_USER}" bash | prefix_stdout
  199. mkdir -p "${REDIS_HOME_BIN}"
  200. echo "export PATH=${REDIS_HOME_BIN}:\\\$PATH" > "${REDIS_ENV}"
  201. grep -qFs -- 'source "${REDIS_ENV}"' ~/.profile || echo 'source "${REDIS_ENV}"' >> ~/.profile
  202. EOF
  203. }
  204. redis.userdel() {
  205. sudo_or_exit
  206. drop_service_account "${REDIS_USER}"
  207. groupdel "${REDIS_USER}" 2>&1 | prefix_stdout || true
  208. }
  209. redis.addgrp() {
  210. # usage: redis.addgrp <user>
  211. [[ -z $1 ]] && die_caller 42 "missing argument <user>"
  212. sudo -H gpasswd -a "$1" "${REDIS_USER}"
  213. }
  214. redis.rmgrp() {
  215. # usage: redis.rmgrp <user>
  216. [[ -z $1 ]] && die_caller 42 "missing argument <user>"
  217. sudo -H gpasswd -d "$1" "${REDIS_USER}"
  218. }
  219. # private redis. functions
  220. # ------------------------
  221. redis._install_bin() {
  222. local src
  223. src="$(redis._get_dist)"
  224. (
  225. set -e
  226. for redis_exe in "${REDIS_INSTALL_EXE[@]}"; do
  227. install -v -o "${REDIS_USER}" -g "${REDIS_USER}" \
  228. "${src}/${redis_exe}" "${REDIS_HOME_BIN}"
  229. done
  230. pushd "${REDIS_HOME_BIN}" &> /dev/null
  231. for redis_exe in "${REDIS_LINK_EXE[@]}"; do
  232. info_msg "link redis-server --> ${redis_exe}"
  233. sudo -H -u "${REDIS_USER}" ln -sf redis-server "${redis_exe}"
  234. done
  235. popd &> /dev/null
  236. )
  237. }
  238. redis._install_conf() {
  239. sudo -H -u "${REDIS_USER}" bash <<EOF
  240. mkdir -p "${REDIS_HOME}/run"
  241. echo '${REDIS_CONF_TEMPLATE}' > "${REDIS_CONF}"
  242. EOF
  243. }
  244. redis._install_service() {
  245. systemd_install_service "${REDIS_SERVICE_NAME}" "${REDIS_SYSTEMD_UNIT}"
  246. }
  247. redis._remove_service() {
  248. systemd_remove_service "${REDIS_SERVICE_NAME}" "${REDIS_SYSTEMD_UNIT}"
  249. }
  250. redis._get_dist() {
  251. if [ -z "${REDIS_DIST}" ]; then
  252. echo "${REPO_ROOT}/dist/redis/${REDIS_GIT_TAG}/$(redis._arch)"
  253. else
  254. echo "${REDIS_DIST}"
  255. fi
  256. }
  257. redis._arch() {
  258. local ARCH
  259. case "$(command uname -m)" in
  260. "x86_64") ARCH=amd64 ;;
  261. "aarch64") ARCH=arm64 ;;
  262. "armv6" | "armv7l") ARCH=armv6l ;;
  263. "armv8") ARCH=arm64 ;;
  264. .*386.*) ARCH=386 ;;
  265. ppc64*) ARCH=ppc64le ;;
  266. *) die 42 "ARCH is unknown: $(command uname -m)" ;;
  267. esac
  268. echo "${ARCH}"
  269. }
  270. # TODO: move this to the right place ..
  271. bash.cmd(){
  272. # print cmd to get a bash in a non-root mode, even if we are in a sudo
  273. # context.
  274. local user="${USER}"
  275. local bash_cmd="bash"
  276. if [ -n "${SUDO_USER}" ] && [ "root" != "${SUDO_USER}" ] ; then
  277. user="${SUDO_USER}"
  278. bash_cmd="sudo -H -u ${SUDO_USER} bash"
  279. fi
  280. printf "%s" "${bash_cmd}"
  281. }