From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from lists.gentoo.org (pigeon.gentoo.org [208.92.234.80]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (2048 bits)) (No client certificate requested) by finch.gentoo.org (Postfix) with ESMTPS id 6BBAF158021 for ; Sat, 5 Nov 2022 14:41:48 +0000 (UTC) Received: from pigeon.gentoo.org (localhost [127.0.0.1]) by pigeon.gentoo.org (Postfix) with SMTP id 6855FE07B2; Sat, 5 Nov 2022 14:41:47 +0000 (UTC) Received: from smtp.gentoo.org (woodpecker.gentoo.org [140.211.166.183]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits) server-digest SHA256) (No client certificate requested) by pigeon.gentoo.org (Postfix) with ESMTPS id 4786DE07B2 for ; Sat, 5 Nov 2022 14:41:47 +0000 (UTC) Received: from oystercatcher.gentoo.org (oystercatcher.gentoo.org [148.251.78.52]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (4096 bits)) (No client certificate requested) by smtp.gentoo.org (Postfix) with ESMTPS id E7ADC341205 for ; Sat, 5 Nov 2022 14:41:45 +0000 (UTC) Received: from localhost.localdomain (localhost [IPv6:::1]) by oystercatcher.gentoo.org (Postfix) with ESMTP id 6D403615 for ; Sat, 5 Nov 2022 14:41:44 +0000 (UTC) From: "Anna Vyalkova" To: gentoo-commits@lists.gentoo.org Content-Transfer-Encoding: 8bit Content-type: text/plain; charset=UTF-8 Reply-To: gentoo-dev@lists.gentoo.org, "Anna Vyalkova" Message-ID: <1667659291.f0252164166f2b5005476664dd8c40f75afd9cba.cybertailor@gentoo> Subject: [gentoo-commits] repo/proj/guru:dev commit in: eclass/ X-VCS-Repository: repo/proj/guru X-VCS-Files: eclass/databases.eclass X-VCS-Directories: eclass/ X-VCS-Committer: cybertailor X-VCS-Committer-Name: Anna Vyalkova X-VCS-Revision: f0252164166f2b5005476664dd8c40f75afd9cba X-VCS-Branch: dev Date: Sat, 5 Nov 2022 14:41:44 +0000 (UTC) Precedence: bulk List-Post: List-Help: List-Unsubscribe: List-Subscribe: List-Id: Gentoo Linux mail X-BeenThere: gentoo-commits@lists.gentoo.org X-Auto-Response-Suppress: DR, RN, NRN, OOF, AutoReply X-Archives-Salt: 229c7dec-877a-4d73-9ac4-b90f159643d7 X-Archives-Hash: 79ff1be92f78ee32dbc285a577f8ffcf commit: f0252164166f2b5005476664dd8c40f75afd9cba Author: Anna (cybertailor) Vyalkova sysrq in> AuthorDate: Fri Nov 4 06:25:56 2022 +0000 Commit: Anna Vyalkova sysrq in> CommitDate: Sat Nov 5 14:41:31 2022 +0000 URL: https://gitweb.gentoo.org/repo/proj/guru.git/commit/?id=f0252164 databases.eclass: new eclass for running databases Signed-off-by: Anna (cybertailor) Vyalkova sysrq.in> eclass/databases.eclass | 480 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 480 insertions(+) diff --git a/eclass/databases.eclass b/eclass/databases.eclass new file mode 100644 index 000000000..fbf653435 --- /dev/null +++ b/eclass/databases.eclass @@ -0,0 +1,480 @@ +# Copyright 2022 Gentoo Authors +# Distributed under the terms of the GNU General Public License v2 + +# @ECLASS: databases.eclass +# @MAINTAINER: +# Anna +# @AUTHOR: +# Anna +# @SUPPORTED_EAPIS: 8 +# @BLURB: eclass to test packages against databases +# @DESCRIPTION: +# A utility eclass providing functions for running databases. +# +# This eclass does not set any metadata variables nor export any phase, so it +# can be inherited safely. +# +# @SUBSECTION Supported databases +# +# - memcached (via "ememcached" helper) +# +# - MongoDB (via "emongod" helper) +# +# - MySQL/MariaDB/ (via "emysql" helper) +# +# - PostgreSQL (via "epostgres" helper) +# +# - Redis (via "eredis" helper) +# +# @SUBSECTION Helper usage +# +# --die [msg...] +# +# Prints the path to the server's log file to the console and aborts the +# current merge process with the given message. +# +# --get-dbpath +# +# Returns the directory where the server stores database files. +# +# --get-depend +# +# Returns a dependency string (to be included in BDEPEND). +# +# --get-logfile +# +# Returns the path to the server's log file. +# +# --get-pidfile +# +# Returns the path to the server's PID file. +# +# --get-sockdir +# +# Returns the directory where the server's sockets are located. +# +# --get-sockfile +# +# Returns the path to the server's socket file. +# +# --start +# +# Starts the server on the default port. +# +# --start +# +# Starts the server on the given port. +# +# --stop +# +# Stops the server. +# +# @EXAMPLE: +# +# @CODE +# EAPI=8 +# +# ... +# +# inherit databases distutils-r1 +# +# ... +# +# BDEPEND="$(eredis --get-depend)" +# +# distutils_enable_tests pytest +# +# src_test() { +# eredis --start 16739 +# distutils-r1_src_test +# eredis --stop +# } +# @CODE + +case ${EAPI} in + 8) ;; + *) die "${ECLASS}: EAPI ${EAPI} unsupported." +esac + +if [[ ! ${_DATABASES_ECLASS} ]]; then +_DATABASES_ECLASS=1 + +# ============================================================================== +# GENERIC FUNCTIONS +# ============================================================================== + +# @FUNCTION: _databases_gen_depend +# @USAGE: +# @INTERNAL +# @DESCRIPTION: +# Get a dependency string for the given helper function. +_databases_gen_depend() { + local srvname=${1:1} + case ${srvname} in + memcached) + echo "net-misc/memcached" + ;; + mongod) + echo "dev-db/mongodb" + ;; + mysql) + echo "virtual/mysql[server]" + ;; + postgres) + echo "dev-db/postgresql[server]" + ;; + redis) + echo "dev-db/redis" + ;; + *) + die "${ECLASS}: unknown database: ${srvname}" + esac +} + +# @FUNCTION: _databases_die +# @USAGE: [msg] +# @INTERNAL +# @DESCRIPTION: +# Print the given message and the path to the server's log file to the console +# and die. +# +# This function supports being called via "nonfatal". +_databases_die() { + local funcname=${1?} + shift + + eerror "See the server log for details:" + eerror " $(${funcname} --get-logfile)" + die -n "${@}" +} + +# @FUNCTION: _databases_stop_service +# @USAGE: +# @INTERNAL +# @DESCRIPTION: +# Default function to stop servers. Reads PID from a file and sends the TERM +# signal. +_databases_stop_service() { + debug-print-function "${FUNCNAME}" "${@}" + + local funcname=${1?} + local srvname=${funcname:1} + local pidfile="$(${funcname} --get-pidfile)" + + ebegin "Stopping ${srvname}" + kill "$(<"${pidfile}")" + eend $? || ${funcname} --die "Stopping ${srvname} failed" +} + +# @FUNCTION: _databases_dispatch +# @USAGE: [args...] +# @INTERNAL +# @DESCRIPTION: +# Process the given command with its options. +# +# If "--start" command is used, `_${funcname}_start` function must be defined. +# Note that directories will be created automatically. +# +# If `_${funcname}_stop` function is not declared, the internal +# `_databases_stop_service` function will be used instead. +# +# No `--get` function can be overloaded. +_databases_dispatch() { + local funcname=${1?} + local cmd=${2?} + shift; shift + + case ${cmd} in + --die) + _databases_die ${funcname} "${@}" + ;; + --get-depend) + _databases_gen_depend ${funcname} + ;; + --get-dbpath) + echo "${T}"/${funcname}/db/ + ;; + --get-logfile) + echo "${T}"/${funcname}/${funcname}.log + ;; + --get-pidfile) + echo "${T}"/${funcname}/${funcname}.pid + ;; + --get-sockdir) + echo "${T}"/${funcname}/ + ;; + --get-sockfile) + echo "${T}"/${funcname}/${funcname}.sock + ;; + --start) + local port=${1} + local start_fn=( _${funcname}_start ${port} ) + if ! declare -f "${start_fn[0]}" >/dev/null; then + die "${ECLASS}: function not declared: ${start_fn[0]}" + fi + + mkdir -p "${T}"/${funcname}/db/ || die "Creating database directory failed" + "${start_fn[@]}" + ;; + --stop) + local stop_fn=( _${funcname}_stop ) + if ! declare -f "${stop_fn[0]}" >/dev/null; then + # fall back to the default implementation + stop_fn=( _databases_stop_service ${funcname} ) + fi + + "${stop_fn[@]}" + ;; + *) die "${funcname}: invalid command: ${cmd}" ;; + esac +} + +# ============================================================================== +# MEMCACHED +# ============================================================================== + +# @FUNCTION: _ememcached_start +# @USAGE: [port] +# @INTERNAL +# @DESCRIPTION: +# Start memcached server. +_ememcached_start() { + debug-print-function "${FUNCNAME}" "${@}" + + local port=${1:-11211} + + local myargs=( + --daemon + --port=${port} + --user=nobody + --listen=127.0.0.1 + --pidfile=$(ememcached --get-pidfile) + ) + + ebegin "Spawning memcached" + memcached "${myargs[@]}" &>> $(ememcached --get-logfile) + eend $? || ememcached --die "Spawning memcached failed" +} + +# @FUNCTION: ememcached +# @USAGE: [args...] +# @DESCRIPTION: +# Manage memcached server on the given port (default: 11211). +ememcached() { + _databases_dispatch "${FUNCNAME}" "${@}" +} + +# ============================================================================== +# MONGODB +# ============================================================================== + +# @FUNCTION: _emongod_start +# @USAGE: [port] +# @INTERNAL +# @DESCRIPTION: +# Start MongoDB server. +_emongod_start() { + debug-print-function "${FUNCNAME}" "${@}" + + local port=${1:-27017} + local logfile=$(emongod --get-logfile) + + local myargs=( + --dbpath="$(emongod --get-dbpath)" + --nojournal + --bind-ip=127.0.0.1 + --port=${port} + --unixSocketPrefix="$(emongod --get-sockdir)" + --logpath="${logfile}" + --fork + ) + + ebegin "Spawning mongodb" + LC_ALL=C mongod "${myargs[@]}" &>> "${logfile}" + eend $? || emongod --die "Spawning mongod failed" +} + +# @FUNCTION: _emongod_stop +# @INTERNAL +# @DESCRIPTION: +# Stop MongoDB server. +_emongod_stop() { + debug-print-function "${FUNCNAME}" "${@}" + + local myargs=( + --dbpath="$(emongod --get-dbpath)" + --shutdown + ) + + ebegin "Stopping mongodb" + mongod "${myargs[@]}" &>> "${logfile}" + eend $? || emongod --die "Stopping mongod failed" +} + +# @FUNCTION: emongod +# @USAGE: [args...] +# @DESCRIPTION: +# Manage MongoDB server on the given port (default: 27017). +emongod() { + _databases_dispatch "${FUNCNAME}" "${@}" +} + +# ============================================================================== +# MYSQL +# ============================================================================== + +# @FUNCTION: _emysql_start +# @USAGE: [port] +# @INTERNAL +# @DESCRIPTION: +# Create a new MySQL database and start MySQL server. +_emysql_start() { + debug-print-function "${FUNCNAME}" "${@}" + + local port=${1:-3306} + local dbpath=$(emysql --get-dbpath) + local logfile=$(emysql --get-logfile) + local sockfile=$(emysql --get-sockfile) + + local myinstallargs=( + --no-defaults + --auth-root-authentication-method=normal + --basedir="${BROOT}/usr" + --datadir="${dbpath}" + ) + + ebegin "Initializing mysql database" + mysql_install_db "${myinstallargs[@]}" &>> "${logfile}" + eend $? || emysql --die "Initializing mysql database failed" + + local myargs=( + --no-defaults + --character-set-server=utf8 + --pid-file="$(emysql --get-pidfile)" + --socket="${sockfile}" + --bind-address=127.0.0.1 + --port=${port} + --datadir="${dbpath}" + --general-log-file="${logfile}" + --log-error="${logfile}" + ) + + einfo "Spawning mysql" + mysqld "${myargs[@]}" &>> "${logfile}" & + + einfo "Waiting for mysqld to accept connections" + local timeout=30 + while ! mysqladmin ping --socket="${sockfile}" --silent; do + sleep 1 + let timeout-=1 + [[ ${timeout} -eq 0 ]] && emysql --die "Timed out" + done +} + +# @FUNCTION: emysql +# @USAGE: [args...] +# @DESCRIPTION: +# Manage MySQL server on the given port (default: 3306). +emysql() { + _databases_dispatch "${FUNCNAME}" "${@}" +} + +# ============================================================================== +# POSTGRESQL +# ============================================================================== + +# @FUNCTION: _epostgres_start +# @USAGE: [port] +# @INTERNAL +# @DESCRIPTION: +# Create a new PostgreSQL database and start PostgreSQL server. +_epostgres_start() { + debug-print-function "${FUNCNAME}" "${@}" + + local port=${1:-5432} + local dbpath=$(epostgres --get-dbpath) + local logfile=$(epostgres --get-logfile) + + local myinstallargs=( + --pgdata="${dbpath}" + --user=postgres + ) + + ebegin "Initializing postgresql database" + initdb "${myinstallargs[@]}" &>> "${logfile}" + eend $? || epostgres --die "Initializing postgresql database failed" + + local myargs=( + --pgdata="${dbpath}" + --log="${logfile}" + --options="-h '127.0.0.1' -p ${port} -k '$(epostgres --get-sockdir)'" + --wait + ) + + ebegin "Spawning postgresql" + pg_ctl "${myargs[@]}" start &>> "${logfile}" + eend $? || epostgres --die "Spawning postgresql failed" +} + +# @FUNCTION: _epostgres_stop +# @INTERNAL +# @DESCRIPTION: +# Stop PosgreSQL server. +_epostgres_stop() { + debug-print-function "${FUNCNAME}" "${@}" + + local myargs=( + --pgdata="$(epostgres --get-dbpath)" + --wait + ) + + ebegin "Stopping postgresql" + pg_ctl "${myargs[@]}" stop &>> "$(epostgres --get-logfile)" + eend $? || epostgres --die "Stopping postgresql failed" +} + +# @FUNCTION: epostgres +# @USAGE: [args...] +# @DESCRIPTION: +# Manage PostgreSQL server on the given port (default: 5432). +epostgres() { + _databases_dispatch "${FUNCNAME}" "${@}" +} + +# ============================================================================== +# REDIS +# ============================================================================== + +# @FUNCTION: _eredis_start +# @USAGE: [args...] +# @INTERNAL +# @DESCRIPTION: +# Start Redis server. +_eredis_start() { + debug-print-function "${FUNCNAME}" "${@}" + + local port=${1:-6379} + local logfile="$(eredis --get-logfile)" + + ebegin "Spawning redis" + redis-server - <<- EOF &>> "${logfile}" + daemonize yes + pidfile "$(eredis --get-pidfile)" + port ${port} + bind 127.0.0.1 + unixsocket "$(eredis --get-sockfile)" + dir "$(eredis --get-dbpath)" + logfile "${logfile}" + EOF + eend $? || eredis --die "Spawning redis failed" +} + +# @FUNCTION: eredis +# @USAGE: [args...] +# @DESCRIPTION: +# Manage Redis server on the given port (default: 6379). +eredis() { + _databases_dispatch "${FUNCNAME}" "${@}" +} + +fi