1 |
commit: f0252164166f2b5005476664dd8c40f75afd9cba |
2 |
Author: Anna (cybertailor) Vyalkova <cyber+gentoo <AT> sysrq <DOT> in> |
3 |
AuthorDate: Fri Nov 4 06:25:56 2022 +0000 |
4 |
Commit: Arthur Zamarin <arthurzam <AT> gentoo <DOT> org> |
5 |
CommitDate: Sat Nov 5 14:41:31 2022 +0000 |
6 |
URL: https://gitweb.gentoo.org/repo/proj/guru.git/commit/?id=f0252164 |
7 |
|
8 |
databases.eclass: new eclass for running databases |
9 |
|
10 |
Signed-off-by: Anna (cybertailor) Vyalkova <cyber+gentoo <AT> sysrq.in> |
11 |
|
12 |
eclass/databases.eclass | 480 ++++++++++++++++++++++++++++++++++++++++++++++++ |
13 |
1 file changed, 480 insertions(+) |
14 |
|
15 |
diff --git a/eclass/databases.eclass b/eclass/databases.eclass |
16 |
new file mode 100644 |
17 |
index 000000000..fbf653435 |
18 |
--- /dev/null |
19 |
+++ b/eclass/databases.eclass |
20 |
@@ -0,0 +1,480 @@ |
21 |
+# Copyright 2022 Gentoo Authors |
22 |
+# Distributed under the terms of the GNU General Public License v2 |
23 |
+ |
24 |
+# @ECLASS: databases.eclass |
25 |
+# @MAINTAINER: |
26 |
+# Anna <cyber+gentoo@×××××.in> |
27 |
+# @AUTHOR: |
28 |
+# Anna <cyber+gentoo@×××××.in> |
29 |
+# @SUPPORTED_EAPIS: 8 |
30 |
+# @BLURB: eclass to test packages against databases |
31 |
+# @DESCRIPTION: |
32 |
+# A utility eclass providing functions for running databases. |
33 |
+# |
34 |
+# This eclass does not set any metadata variables nor export any phase, so it |
35 |
+# can be inherited safely. |
36 |
+# |
37 |
+# @SUBSECTION Supported databases |
38 |
+# |
39 |
+# - memcached (via "ememcached" helper) |
40 |
+# |
41 |
+# - MongoDB (via "emongod" helper) |
42 |
+# |
43 |
+# - MySQL/MariaDB/ (via "emysql" helper) |
44 |
+# |
45 |
+# - PostgreSQL (via "epostgres" helper) |
46 |
+# |
47 |
+# - Redis (via "eredis" helper) |
48 |
+# |
49 |
+# @SUBSECTION Helper usage |
50 |
+# |
51 |
+# --die [msg...] |
52 |
+# |
53 |
+# Prints the path to the server's log file to the console and aborts the |
54 |
+# current merge process with the given message. |
55 |
+# |
56 |
+# --get-dbpath |
57 |
+# |
58 |
+# Returns the directory where the server stores database files. |
59 |
+# |
60 |
+# --get-depend |
61 |
+# |
62 |
+# Returns a dependency string (to be included in BDEPEND). |
63 |
+# |
64 |
+# --get-logfile |
65 |
+# |
66 |
+# Returns the path to the server's log file. |
67 |
+# |
68 |
+# --get-pidfile |
69 |
+# |
70 |
+# Returns the path to the server's PID file. |
71 |
+# |
72 |
+# --get-sockdir |
73 |
+# |
74 |
+# Returns the directory where the server's sockets are located. |
75 |
+# |
76 |
+# --get-sockfile |
77 |
+# |
78 |
+# Returns the path to the server's socket file. |
79 |
+# |
80 |
+# --start |
81 |
+# |
82 |
+# Starts the server on the default port. |
83 |
+# |
84 |
+# --start <port> |
85 |
+# |
86 |
+# Starts the server on the given port. |
87 |
+# |
88 |
+# --stop |
89 |
+# |
90 |
+# Stops the server. |
91 |
+# |
92 |
+# @EXAMPLE: |
93 |
+# |
94 |
+# @CODE |
95 |
+# EAPI=8 |
96 |
+# |
97 |
+# ... |
98 |
+# |
99 |
+# inherit databases distutils-r1 |
100 |
+# |
101 |
+# ... |
102 |
+# |
103 |
+# BDEPEND="$(eredis --get-depend)" |
104 |
+# |
105 |
+# distutils_enable_tests pytest |
106 |
+# |
107 |
+# src_test() { |
108 |
+# eredis --start 16739 |
109 |
+# distutils-r1_src_test |
110 |
+# eredis --stop |
111 |
+# } |
112 |
+# @CODE |
113 |
+ |
114 |
+case ${EAPI} in |
115 |
+ 8) ;; |
116 |
+ *) die "${ECLASS}: EAPI ${EAPI} unsupported." |
117 |
+esac |
118 |
+ |
119 |
+if [[ ! ${_DATABASES_ECLASS} ]]; then |
120 |
+_DATABASES_ECLASS=1 |
121 |
+ |
122 |
+# ============================================================================== |
123 |
+# GENERIC FUNCTIONS |
124 |
+# ============================================================================== |
125 |
+ |
126 |
+# @FUNCTION: _databases_gen_depend |
127 |
+# @USAGE: <funcname> |
128 |
+# @INTERNAL |
129 |
+# @DESCRIPTION: |
130 |
+# Get a dependency string for the given helper function. |
131 |
+_databases_gen_depend() { |
132 |
+ local srvname=${1:1} |
133 |
+ case ${srvname} in |
134 |
+ memcached) |
135 |
+ echo "net-misc/memcached" |
136 |
+ ;; |
137 |
+ mongod) |
138 |
+ echo "dev-db/mongodb" |
139 |
+ ;; |
140 |
+ mysql) |
141 |
+ echo "virtual/mysql[server]" |
142 |
+ ;; |
143 |
+ postgres) |
144 |
+ echo "dev-db/postgresql[server]" |
145 |
+ ;; |
146 |
+ redis) |
147 |
+ echo "dev-db/redis" |
148 |
+ ;; |
149 |
+ *) |
150 |
+ die "${ECLASS}: unknown database: ${srvname}" |
151 |
+ esac |
152 |
+} |
153 |
+ |
154 |
+# @FUNCTION: _databases_die |
155 |
+# @USAGE: <funcname> [msg] |
156 |
+# @INTERNAL |
157 |
+# @DESCRIPTION: |
158 |
+# Print the given message and the path to the server's log file to the console |
159 |
+# and die. |
160 |
+# |
161 |
+# This function supports being called via "nonfatal". |
162 |
+_databases_die() { |
163 |
+ local funcname=${1?} |
164 |
+ shift |
165 |
+ |
166 |
+ eerror "See the server log for details:" |
167 |
+ eerror " $(${funcname} --get-logfile)" |
168 |
+ die -n "${@}" |
169 |
+} |
170 |
+ |
171 |
+# @FUNCTION: _databases_stop_service |
172 |
+# @USAGE: <funcname> |
173 |
+# @INTERNAL |
174 |
+# @DESCRIPTION: |
175 |
+# Default function to stop servers. Reads PID from a file and sends the TERM |
176 |
+# signal. |
177 |
+_databases_stop_service() { |
178 |
+ debug-print-function "${FUNCNAME}" "${@}" |
179 |
+ |
180 |
+ local funcname=${1?} |
181 |
+ local srvname=${funcname:1} |
182 |
+ local pidfile="$(${funcname} --get-pidfile)" |
183 |
+ |
184 |
+ ebegin "Stopping ${srvname}" |
185 |
+ kill "$(<"${pidfile}")" |
186 |
+ eend $? || ${funcname} --die "Stopping ${srvname} failed" |
187 |
+} |
188 |
+ |
189 |
+# @FUNCTION: _databases_dispatch |
190 |
+# @USAGE: <funcname> <cmd> [args...] |
191 |
+# @INTERNAL |
192 |
+# @DESCRIPTION: |
193 |
+# Process the given command with its options. |
194 |
+# |
195 |
+# If "--start" command is used, `_${funcname}_start` function must be defined. |
196 |
+# Note that directories will be created automatically. |
197 |
+# |
198 |
+# If `_${funcname}_stop` function is not declared, the internal |
199 |
+# `_databases_stop_service` function will be used instead. |
200 |
+# |
201 |
+# No `--get` function can be overloaded. |
202 |
+_databases_dispatch() { |
203 |
+ local funcname=${1?} |
204 |
+ local cmd=${2?} |
205 |
+ shift; shift |
206 |
+ |
207 |
+ case ${cmd} in |
208 |
+ --die) |
209 |
+ _databases_die ${funcname} "${@}" |
210 |
+ ;; |
211 |
+ --get-depend) |
212 |
+ _databases_gen_depend ${funcname} |
213 |
+ ;; |
214 |
+ --get-dbpath) |
215 |
+ echo "${T}"/${funcname}/db/ |
216 |
+ ;; |
217 |
+ --get-logfile) |
218 |
+ echo "${T}"/${funcname}/${funcname}.log |
219 |
+ ;; |
220 |
+ --get-pidfile) |
221 |
+ echo "${T}"/${funcname}/${funcname}.pid |
222 |
+ ;; |
223 |
+ --get-sockdir) |
224 |
+ echo "${T}"/${funcname}/ |
225 |
+ ;; |
226 |
+ --get-sockfile) |
227 |
+ echo "${T}"/${funcname}/${funcname}.sock |
228 |
+ ;; |
229 |
+ --start) |
230 |
+ local port=${1} |
231 |
+ local start_fn=( _${funcname}_start ${port} ) |
232 |
+ if ! declare -f "${start_fn[0]}" >/dev/null; then |
233 |
+ die "${ECLASS}: function not declared: ${start_fn[0]}" |
234 |
+ fi |
235 |
+ |
236 |
+ mkdir -p "${T}"/${funcname}/db/ || die "Creating database directory failed" |
237 |
+ "${start_fn[@]}" |
238 |
+ ;; |
239 |
+ --stop) |
240 |
+ local stop_fn=( _${funcname}_stop ) |
241 |
+ if ! declare -f "${stop_fn[0]}" >/dev/null; then |
242 |
+ # fall back to the default implementation |
243 |
+ stop_fn=( _databases_stop_service ${funcname} ) |
244 |
+ fi |
245 |
+ |
246 |
+ "${stop_fn[@]}" |
247 |
+ ;; |
248 |
+ *) die "${funcname}: invalid command: ${cmd}" ;; |
249 |
+ esac |
250 |
+} |
251 |
+ |
252 |
+# ============================================================================== |
253 |
+# MEMCACHED |
254 |
+# ============================================================================== |
255 |
+ |
256 |
+# @FUNCTION: _ememcached_start |
257 |
+# @USAGE: [port] |
258 |
+# @INTERNAL |
259 |
+# @DESCRIPTION: |
260 |
+# Start memcached server. |
261 |
+_ememcached_start() { |
262 |
+ debug-print-function "${FUNCNAME}" "${@}" |
263 |
+ |
264 |
+ local port=${1:-11211} |
265 |
+ |
266 |
+ local myargs=( |
267 |
+ --daemon |
268 |
+ --port=${port} |
269 |
+ --user=nobody |
270 |
+ --listen=127.0.0.1 |
271 |
+ --pidfile=$(ememcached --get-pidfile) |
272 |
+ ) |
273 |
+ |
274 |
+ ebegin "Spawning memcached" |
275 |
+ memcached "${myargs[@]}" &>> $(ememcached --get-logfile) |
276 |
+ eend $? || ememcached --die "Spawning memcached failed" |
277 |
+} |
278 |
+ |
279 |
+# @FUNCTION: ememcached |
280 |
+# @USAGE: <cmd> [args...] |
281 |
+# @DESCRIPTION: |
282 |
+# Manage memcached server on the given port (default: 11211). |
283 |
+ememcached() { |
284 |
+ _databases_dispatch "${FUNCNAME}" "${@}" |
285 |
+} |
286 |
+ |
287 |
+# ============================================================================== |
288 |
+# MONGODB |
289 |
+# ============================================================================== |
290 |
+ |
291 |
+# @FUNCTION: _emongod_start |
292 |
+# @USAGE: [port] |
293 |
+# @INTERNAL |
294 |
+# @DESCRIPTION: |
295 |
+# Start MongoDB server. |
296 |
+_emongod_start() { |
297 |
+ debug-print-function "${FUNCNAME}" "${@}" |
298 |
+ |
299 |
+ local port=${1:-27017} |
300 |
+ local logfile=$(emongod --get-logfile) |
301 |
+ |
302 |
+ local myargs=( |
303 |
+ --dbpath="$(emongod --get-dbpath)" |
304 |
+ --nojournal |
305 |
+ --bind-ip=127.0.0.1 |
306 |
+ --port=${port} |
307 |
+ --unixSocketPrefix="$(emongod --get-sockdir)" |
308 |
+ --logpath="${logfile}" |
309 |
+ --fork |
310 |
+ ) |
311 |
+ |
312 |
+ ebegin "Spawning mongodb" |
313 |
+ LC_ALL=C mongod "${myargs[@]}" &>> "${logfile}" |
314 |
+ eend $? || emongod --die "Spawning mongod failed" |
315 |
+} |
316 |
+ |
317 |
+# @FUNCTION: _emongod_stop |
318 |
+# @INTERNAL |
319 |
+# @DESCRIPTION: |
320 |
+# Stop MongoDB server. |
321 |
+_emongod_stop() { |
322 |
+ debug-print-function "${FUNCNAME}" "${@}" |
323 |
+ |
324 |
+ local myargs=( |
325 |
+ --dbpath="$(emongod --get-dbpath)" |
326 |
+ --shutdown |
327 |
+ ) |
328 |
+ |
329 |
+ ebegin "Stopping mongodb" |
330 |
+ mongod "${myargs[@]}" &>> "${logfile}" |
331 |
+ eend $? || emongod --die "Stopping mongod failed" |
332 |
+} |
333 |
+ |
334 |
+# @FUNCTION: emongod |
335 |
+# @USAGE: <cmd> [args...] |
336 |
+# @DESCRIPTION: |
337 |
+# Manage MongoDB server on the given port (default: 27017). |
338 |
+emongod() { |
339 |
+ _databases_dispatch "${FUNCNAME}" "${@}" |
340 |
+} |
341 |
+ |
342 |
+# ============================================================================== |
343 |
+# MYSQL |
344 |
+# ============================================================================== |
345 |
+ |
346 |
+# @FUNCTION: _emysql_start |
347 |
+# @USAGE: [port] |
348 |
+# @INTERNAL |
349 |
+# @DESCRIPTION: |
350 |
+# Create a new MySQL database and start MySQL server. |
351 |
+_emysql_start() { |
352 |
+ debug-print-function "${FUNCNAME}" "${@}" |
353 |
+ |
354 |
+ local port=${1:-3306} |
355 |
+ local dbpath=$(emysql --get-dbpath) |
356 |
+ local logfile=$(emysql --get-logfile) |
357 |
+ local sockfile=$(emysql --get-sockfile) |
358 |
+ |
359 |
+ local myinstallargs=( |
360 |
+ --no-defaults |
361 |
+ --auth-root-authentication-method=normal |
362 |
+ --basedir="${BROOT}/usr" |
363 |
+ --datadir="${dbpath}" |
364 |
+ ) |
365 |
+ |
366 |
+ ebegin "Initializing mysql database" |
367 |
+ mysql_install_db "${myinstallargs[@]}" &>> "${logfile}" |
368 |
+ eend $? || emysql --die "Initializing mysql database failed" |
369 |
+ |
370 |
+ local myargs=( |
371 |
+ --no-defaults |
372 |
+ --character-set-server=utf8 |
373 |
+ --pid-file="$(emysql --get-pidfile)" |
374 |
+ --socket="${sockfile}" |
375 |
+ --bind-address=127.0.0.1 |
376 |
+ --port=${port} |
377 |
+ --datadir="${dbpath}" |
378 |
+ --general-log-file="${logfile}" |
379 |
+ --log-error="${logfile}" |
380 |
+ ) |
381 |
+ |
382 |
+ einfo "Spawning mysql" |
383 |
+ mysqld "${myargs[@]}" &>> "${logfile}" & |
384 |
+ |
385 |
+ einfo "Waiting for mysqld to accept connections" |
386 |
+ local timeout=30 |
387 |
+ while ! mysqladmin ping --socket="${sockfile}" --silent; do |
388 |
+ sleep 1 |
389 |
+ let timeout-=1 |
390 |
+ [[ ${timeout} -eq 0 ]] && emysql --die "Timed out" |
391 |
+ done |
392 |
+} |
393 |
+ |
394 |
+# @FUNCTION: emysql |
395 |
+# @USAGE: <cmd> [args...] |
396 |
+# @DESCRIPTION: |
397 |
+# Manage MySQL server on the given port (default: 3306). |
398 |
+emysql() { |
399 |
+ _databases_dispatch "${FUNCNAME}" "${@}" |
400 |
+} |
401 |
+ |
402 |
+# ============================================================================== |
403 |
+# POSTGRESQL |
404 |
+# ============================================================================== |
405 |
+ |
406 |
+# @FUNCTION: _epostgres_start |
407 |
+# @USAGE: [port] |
408 |
+# @INTERNAL |
409 |
+# @DESCRIPTION: |
410 |
+# Create a new PostgreSQL database and start PostgreSQL server. |
411 |
+_epostgres_start() { |
412 |
+ debug-print-function "${FUNCNAME}" "${@}" |
413 |
+ |
414 |
+ local port=${1:-5432} |
415 |
+ local dbpath=$(epostgres --get-dbpath) |
416 |
+ local logfile=$(epostgres --get-logfile) |
417 |
+ |
418 |
+ local myinstallargs=( |
419 |
+ --pgdata="${dbpath}" |
420 |
+ --user=postgres |
421 |
+ ) |
422 |
+ |
423 |
+ ebegin "Initializing postgresql database" |
424 |
+ initdb "${myinstallargs[@]}" &>> "${logfile}" |
425 |
+ eend $? || epostgres --die "Initializing postgresql database failed" |
426 |
+ |
427 |
+ local myargs=( |
428 |
+ --pgdata="${dbpath}" |
429 |
+ --log="${logfile}" |
430 |
+ --options="-h '127.0.0.1' -p ${port} -k '$(epostgres --get-sockdir)'" |
431 |
+ --wait |
432 |
+ ) |
433 |
+ |
434 |
+ ebegin "Spawning postgresql" |
435 |
+ pg_ctl "${myargs[@]}" start &>> "${logfile}" |
436 |
+ eend $? || epostgres --die "Spawning postgresql failed" |
437 |
+} |
438 |
+ |
439 |
+# @FUNCTION: _epostgres_stop |
440 |
+# @INTERNAL |
441 |
+# @DESCRIPTION: |
442 |
+# Stop PosgreSQL server. |
443 |
+_epostgres_stop() { |
444 |
+ debug-print-function "${FUNCNAME}" "${@}" |
445 |
+ |
446 |
+ local myargs=( |
447 |
+ --pgdata="$(epostgres --get-dbpath)" |
448 |
+ --wait |
449 |
+ ) |
450 |
+ |
451 |
+ ebegin "Stopping postgresql" |
452 |
+ pg_ctl "${myargs[@]}" stop &>> "$(epostgres --get-logfile)" |
453 |
+ eend $? || epostgres --die "Stopping postgresql failed" |
454 |
+} |
455 |
+ |
456 |
+# @FUNCTION: epostgres |
457 |
+# @USAGE: <cmd> [args...] |
458 |
+# @DESCRIPTION: |
459 |
+# Manage PostgreSQL server on the given port (default: 5432). |
460 |
+epostgres() { |
461 |
+ _databases_dispatch "${FUNCNAME}" "${@}" |
462 |
+} |
463 |
+ |
464 |
+# ============================================================================== |
465 |
+# REDIS |
466 |
+# ============================================================================== |
467 |
+ |
468 |
+# @FUNCTION: _eredis_start |
469 |
+# @USAGE: [args...] |
470 |
+# @INTERNAL |
471 |
+# @DESCRIPTION: |
472 |
+# Start Redis server. |
473 |
+_eredis_start() { |
474 |
+ debug-print-function "${FUNCNAME}" "${@}" |
475 |
+ |
476 |
+ local port=${1:-6379} |
477 |
+ local logfile="$(eredis --get-logfile)" |
478 |
+ |
479 |
+ ebegin "Spawning redis" |
480 |
+ redis-server - <<- EOF &>> "${logfile}" |
481 |
+ daemonize yes |
482 |
+ pidfile "$(eredis --get-pidfile)" |
483 |
+ port ${port} |
484 |
+ bind 127.0.0.1 |
485 |
+ unixsocket "$(eredis --get-sockfile)" |
486 |
+ dir "$(eredis --get-dbpath)" |
487 |
+ logfile "${logfile}" |
488 |
+ EOF |
489 |
+ eend $? || eredis --die "Spawning redis failed" |
490 |
+} |
491 |
+ |
492 |
+# @FUNCTION: eredis |
493 |
+# @USAGE: <cmd> [args...] |
494 |
+# @DESCRIPTION: |
495 |
+# Manage Redis server on the given port (default: 6379). |
496 |
+eredis() { |
497 |
+ _databases_dispatch "${FUNCNAME}" "${@}" |
498 |
+} |
499 |
+ |
500 |
+fi |