lib_redis.sh 8.7 KB

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