From f316512a7359a2324f75cfad7f7d74fd0ffd1e7e Mon Sep 17 00:00:00 2001 From: Tom Lane Date: Wed, 27 Jul 2011 15:13:15 -0400 Subject: [PATCH] Convert to systemd startup support --- mysql.init | 228 ------------------------------------------ mysql.spec | 67 ++++++++++--- mysqld-nowatch.patch | 51 ++++++++++ mysqld-prepare-db-dir | 54 ++++++++++ mysqld-wait-ready | 56 +++++++++++ mysqld.service | 24 +++++ 6 files changed, 239 insertions(+), 241 deletions(-) delete mode 100644 mysql.init create mode 100644 mysqld-nowatch.patch create mode 100644 mysqld-prepare-db-dir create mode 100644 mysqld-wait-ready create mode 100644 mysqld.service diff --git a/mysql.init b/mysql.init deleted file mode 100644 index d85c12d..0000000 --- a/mysql.init +++ /dev/null @@ -1,228 +0,0 @@ -#!/bin/sh -# -# mysqld This shell script takes care of starting and stopping -# the MySQL subsystem (mysqld). -# -# chkconfig: - 64 36 -# description: MySQL database server. -# processname: mysqld -# config: /etc/my.cnf -# pidfile: /var/run/mysqld/mysqld.pid -### BEGIN INIT INFO -# Provides: mysqld -# Required-Start: $local_fs $remote_fs $network $named $syslog $time -# Required-Stop: $local_fs $remote_fs $network $named $syslog $time -# Short-Description: start and stop MySQL server -# Description: MySQL database server -### END INIT INFO - -# Source function library. -. /etc/rc.d/init.d/functions - -# Source networking configuration. -. /etc/sysconfig/network - - -exec="/usr/bin/mysqld_safe" -prog="mysqld" - -# Set timeouts here so they can be overridden from /etc/sysconfig/mysqld -STARTTIMEOUT=120 -STOPTIMEOUT=60 - -[ -e /etc/sysconfig/$prog ] && . /etc/sysconfig/$prog - -lockfile=/var/lock/subsys/$prog - - -# extract value of a MySQL option from config files -# Usage: get_mysql_option SECTION VARNAME DEFAULT -# result is returned in $result -# We use my_print_defaults which prints all options from multiple files, -# with the more specific ones later; hence take the last match. -get_mysql_option(){ - result=`/usr/bin/my_print_defaults "$1" | sed -n "s/^--$2=//p" | tail -n 1` - if [ -z "$result" ]; then - # not found, use default - result="$3" - fi -} - -get_mysql_option mysqld datadir "/var/lib/mysql" -datadir="$result" -get_mysql_option mysqld socket "$datadir/mysql.sock" -socketfile="$result" -get_mysql_option mysqld_safe log-error "/var/log/mysqld.log" -errlogfile="$result" -get_mysql_option mysqld_safe pid-file "/var/run/mysqld/mysqld.pid" -mypidfile="$result" - - -start(){ - [ -x $exec ] || exit 5 - # check to see if it's already running - RESPONSE=`/usr/bin/mysqladmin --socket="$socketfile" --user=UNKNOWN_MYSQL_USER ping 2>&1` - if [ $? = 0 ]; then - # already running, do nothing - action $"Starting $prog: " /bin/true - ret=0 - elif echo "$RESPONSE" | grep -q "Access denied for user" - then - # already running, do nothing - action $"Starting $prog: " /bin/true - ret=0 - else - # prepare for start - touch "$errlogfile" - chown mysql:mysql "$errlogfile" - chmod 0640 "$errlogfile" - [ -x /sbin/restorecon ] && /sbin/restorecon "$errlogfile" - if [ ! -d "$datadir/mysql" ] ; then - # First, make sure $datadir is there with correct permissions - if [ ! -e "$datadir" -a ! -h "$datadir" ] - then - mkdir -p "$datadir" || exit 1 - fi - chown mysql:mysql "$datadir" - chmod 0755 "$datadir" - [ -x /sbin/restorecon ] && /sbin/restorecon "$datadir" - # Now create the database - action $"Initializing MySQL database: " /usr/bin/mysql_install_db --datadir="$datadir" --user=mysql - ret=$? - chown -R mysql:mysql "$datadir" - if [ $ret -ne 0 ] ; then - return $ret - fi - fi - chown mysql:mysql "$datadir" - chmod 0755 "$datadir" - # Pass all the options determined above, to ensure consistent behavior. - # In many cases mysqld_safe would arrive at the same conclusions anyway - # but we need to be sure. (An exception is that we don't force the - # log-error setting, since this script doesn't really depend on that, - # and some users might prefer to configure logging to syslog.) - # Note: set --basedir to prevent probes that might trigger SELinux - # alarms, per bug #547485 - $exec --datadir="$datadir" --socket="$socketfile" \ - --pid-file="$mypidfile" \ - --basedir=/usr --user=mysql >/dev/null 2>&1 & - safe_pid=$! - # Spin for a maximum of N seconds waiting for the server to come up; - # exit the loop immediately if mysqld_safe process disappears. - # Rather than assuming we know a valid username, accept an "access - # denied" response as meaning the server is functioning. - ret=0 - TIMEOUT="$STARTTIMEOUT" - while [ $TIMEOUT -gt 0 ]; do - RESPONSE=`/usr/bin/mysqladmin --socket="$socketfile" --user=UNKNOWN_MYSQL_USER ping 2>&1` - mret=$? - if [ $mret -eq 0 ]; then - break - fi - # exit codes 1, 11 (EXIT_CANNOT_CONNECT_TO_SERVICE) are expected, - # anything else suggests a configuration error - if [ $mret -ne 1 -a $mret -ne 11 ]; then - echo "$RESPONSE" - echo "Cannot check for MySQL Daemon startup because of mysqladmin failure." - ret=1 - break - fi - echo "$RESPONSE" | grep -q "Access denied for user" && break - if ! /bin/kill -0 $safe_pid 2>/dev/null; then - echo "MySQL Daemon failed to start." - ret=1 - break - fi - sleep 1 - let TIMEOUT=${TIMEOUT}-1 - done - if [ $TIMEOUT -eq 0 ]; then - echo "Timeout error occurred trying to start MySQL Daemon." - ret=1 - fi - if [ $ret -eq 0 ]; then - action $"Starting $prog: " /bin/true - touch $lockfile - else - action $"Starting $prog: " /bin/false - fi - fi - return $ret -} - -stop(){ - if [ ! -f "$mypidfile" ]; then - # not running; per LSB standards this is "ok" - action $"Stopping $prog: " /bin/true - return 0 - fi - MYSQLPID=`cat "$mypidfile"` - if [ -n "$MYSQLPID" ]; then - /bin/kill "$MYSQLPID" >/dev/null 2>&1 - ret=$? - if [ $ret -eq 0 ]; then - TIMEOUT="$STOPTIMEOUT" - while [ $TIMEOUT -gt 0 ]; do - /bin/kill -0 "$MYSQLPID" >/dev/null 2>&1 || break - sleep 1 - let TIMEOUT=${TIMEOUT}-1 - done - if [ $TIMEOUT -eq 0 ]; then - echo "Timeout error occurred trying to stop MySQL Daemon." - ret=1 - action $"Stopping $prog: " /bin/false - else - rm -f $lockfile - rm -f "$socketfile" - action $"Stopping $prog: " /bin/true - fi - else - action $"Stopping $prog: " /bin/false - fi - else - # failed to read pidfile, probably insufficient permissions - action $"Stopping $prog: " /bin/false - ret=4 - fi - return $ret -} - -restart(){ - stop - start -} - -condrestart(){ - [ -e $lockfile ] && restart || : -} - - -# See how we were called. -case "$1" in - start) - start - ;; - stop) - stop - ;; - status) - status $prog - ;; - restart) - restart - ;; - condrestart|try-restart) - condrestart - ;; - reload) - exit 3 - ;; - force-reload) - restart - ;; - *) - echo $"Usage: $0 {start|stop|status|restart|condrestart|try-restart|reload|force-reload}" - exit 2 -esac - -exit $? diff --git a/mysql.spec b/mysql.spec index 0594a36..adfb127 100644 --- a/mysql.spec +++ b/mysql.spec @@ -1,6 +1,9 @@ Name: mysql Version: 5.5.14 -Release: 2%{?dist} +Release: 3%{?dist} +# Update this whenever F15 gets rebased; it must be NVR-greater than F15 pkg: +%global first_systemd_version 5.5.14-3 + Summary: MySQL client programs and shared libraries Group: Applications/Databases URL: http://www.mysql.com @@ -20,7 +23,6 @@ Source0: mysql-%{version}-nodocs.tar.gz # the tarball into the current directory: # ./generate-tarball.sh $VERSION Source1: generate-tarball.sh -Source2: mysql.init Source3: my.cnf Source4: scriptstub.c Source5: my_config.h @@ -29,6 +31,9 @@ Source7: README.mysql-license Source8: libmysql.version Source9: mysql-embedded-check.c Source10: mysql.tmpfiles.d +Source11: mysqld.service +Source12: mysqld-prepare-db-dir +Source13: mysqld-wait-ready # Working around perl dependency checking bug in rpm FTTB. Remove later. Source999: filter-requires-mysql.sh @@ -45,6 +50,7 @@ Patch10: mysql-embedded-crash.patch Patch11: mysql-plugin-bool.patch Patch12: mysql-s390-tsc.patch Patch13: mysql-openssl-test.patch +Patch14: mysqld-nowatch.patch BuildRoot: %{_tmppath}/%{name}-%{version}-%{release}-root BuildRequires: perl, readline-devel, openssl-devel @@ -54,6 +60,7 @@ BuildRequires: systemtap-sdt-devel BuildRequires: time procps # Socket and Time::HiRes are needed to run regression tests BuildRequires: perl(Socket), perl(Time::HiRes) +BuildRequires: systemd-units Requires: grep, fileutils Requires: %{name}-libs%{?_isa} = %{version}-%{release} @@ -96,11 +103,16 @@ Requires: sh-utils Requires(pre): /usr/sbin/useradd Requires(post): chkconfig Requires(preun): chkconfig -# This is for /sbin/service -Requires(preun): initscripts -Requires(postun): initscripts -# This is for /etc/tmpfiles.d +# We require this to be present for /etc/tmpfiles.d Requires: systemd-units +# Make sure it's there when scriptlets run, too +Requires(post): systemd-units +Requires(preun): systemd-units +Requires(postun): systemd-units +# This is actually needed for the %%triggerun script but Requires(triggerun) +# is not valid. We can use %%post because this particular %%triggerun script +# should fire just after this package is installed. +Requires(post): systemd-sysv # mysqlhotcopy needs DBI/DBD support Requires: perl-DBI, perl-DBD-MySQL Conflicts: MySQL-server @@ -189,6 +201,7 @@ the MySQL sources. %patch11 -p1 %patch12 -p1 %patch13 -p1 +%patch14 -p1 # workaround for upstream bug #56342 rm -f mysql-test/t/ssl_8k_key-master.opt @@ -330,12 +343,18 @@ chmod 755 ${RPM_BUILD_ROOT}%{_bindir}/mysql_config mkdir -p $RPM_BUILD_ROOT/var/log touch $RPM_BUILD_ROOT/var/log/mysqld.log -mkdir -p $RPM_BUILD_ROOT/etc/rc.d/init.d mkdir -p $RPM_BUILD_ROOT/var/run/mysqld install -m 0755 -d $RPM_BUILD_ROOT/var/lib/mysql -install -m 0755 %{SOURCE2} $RPM_BUILD_ROOT/etc/rc.d/init.d/mysqld + +mkdir -p $RPM_BUILD_ROOT/etc install -m 0644 %{SOURCE3} $RPM_BUILD_ROOT/etc/my.cnf +# install systemd unit files and scripts for handling server startup +mkdir -p ${RPM_BUILD_ROOT}%{_unitdir} +install -m 644 %{SOURCE11} ${RPM_BUILD_ROOT}%{_unitdir}/ +install -m 755 %{SOURCE12} ${RPM_BUILD_ROOT}%{_libexecdir}/ +install -m 755 %{SOURCE13} ${RPM_BUILD_ROOT}%{_libexecdir}/ + mkdir -p $RPM_BUILD_ROOT/etc/tmpfiles.d install -m 0644 %{SOURCE10} $RPM_BUILD_ROOT/etc/tmpfiles.d/mysql.conf @@ -408,15 +427,28 @@ rm -rf $RPM_BUILD_ROOT %post server if [ $1 = 1 ]; then - /sbin/chkconfig --add mysqld + # Initial installation + /bin/systemctl daemon-reload >/dev/null 2>&1 || : fi /bin/chmod 0755 /var/lib/mysql /bin/touch /var/log/mysqld.log +# Run this when upgrading from SysV initscript to native systemd unit +%triggerun server -- mysql-server < %{first_systemd_version} +# Save the current service runlevel info +# User must manually run systemd-sysv-convert --apply mysqld +# to migrate them to systemd targets +/usr/bin/systemd-sysv-convert --save mysqld >/dev/null 2>&1 || : + +# Run these because the SysV package being removed won't do them +/sbin/chkconfig --del mysqld >/dev/null 2>&1 || : +/bin/systemctl try-restart mysqld.service >/dev/null 2>&1 || : + %preun server if [ $1 = 0 ]; then - /sbin/service mysqld stop >/dev/null 2>&1 - /sbin/chkconfig --del mysqld + # Package removal, not upgrade + /bin/systemctl --no-reload disable mysqld.service >/dev/null 2>&1 || : + /bin/systemctl stop mysqld.service >/dev/null 2>&1 || : fi %postun libs @@ -425,8 +457,10 @@ if [ $1 = 0 ] ; then fi %postun server +/bin/systemctl daemon-reload >/dev/null 2>&1 || : if [ $1 -ge 1 ]; then - /sbin/service mysqld condrestart >/dev/null 2>&1 || : + # Package upgrade, not uninstall + /bin/systemctl try-restart mysqld.service >/dev/null 2>&1 || : fi @@ -572,7 +606,10 @@ fi %{_datadir}/mysql/my-*.cnf %{_datadir}/mysql/config.*.ini -/etc/rc.d/init.d/mysqld +%{_unitdir}/mysqld.service +%{_libexecdir}/mysqld-prepare-db-dir +%{_libexecdir}/mysqld-wait-ready + /etc/tmpfiles.d/mysql.conf %attr(0755,mysql,mysql) %dir /var/run/mysqld %attr(0755,mysql,mysql) %dir /var/lib/mysql @@ -611,6 +648,10 @@ fi %{_mandir}/man1/mysql_client_test.1* %changelog +* Wed Jul 27 2011 Tom Lane 5.5.14-3 +- Convert to systemd startup support (no socket activation, for now anyway) +Related: #714426 + * Tue Jul 12 2011 Tom Lane 5.5.14-2 - Remove make_scrambled_password and make_scrambled_password_323 from mysql.h, since we're not allowing clients to call those functions anyway diff --git a/mysqld-nowatch.patch b/mysqld-nowatch.patch new file mode 100644 index 0000000..9ca2d12 --- /dev/null +++ b/mysqld-nowatch.patch @@ -0,0 +1,51 @@ +Add a --nowatch option to mysqld_safe that causes it to exit after +spawning mysqld. We don't need mysqld_safe to restart mysqld after +a crash, because systemd can do that just fine. + + +diff -Naur mysql-5.5.14.orig/scripts/mysqld_safe.sh mysql-5.5.14/scripts/mysqld_safe.sh +--- mysql-5.5.14.orig/scripts/mysqld_safe.sh 2011-06-21 12:42:40.000000000 -0400 ++++ mysql-5.5.14/scripts/mysqld_safe.sh 2011-07-25 13:52:40.363068060 -0400 +@@ -15,6 +15,7 @@ + KILL_MYSQLD=1; + MYSQLD= + niceness=0 ++nowatch=0 + mysqld_ld_preload= + mysqld_ld_library_path= + +@@ -54,6 +55,7 @@ + --mysqld=FILE Use the specified file as mysqld + --mysqld-version=VERSION Use "mysqld-VERSION" as mysqld + --nice=NICE Set the scheduling priority of mysqld ++ --nowatch Exit after starting mysqld + --plugin-dir=DIR Plugins are under DIR or DIR/VERSION, if + VERSION is given + --skip-kill-mysqld Don't try to kill stray mysqld processes +@@ -140,8 +142,16 @@ + ;; + esac + +- #echo "Running mysqld: [$cmd]" +- eval "$cmd" ++ if test $nowatch -eq 1 ++ then ++ # We'd prefer to exec $cmd here, but SELinux needs to be fixed first ++ #/usr/bin/logger "Running mysqld: $cmd" ++ eval "$cmd &" ++ exit 0 ++ else ++ #echo "Running mysqld: [$cmd]" ++ eval "$cmd" ++ fi + } + + shell_quote_string() { +@@ -198,6 +208,7 @@ + fi + ;; + --nice=*) niceness="$val" ;; ++ --nowatch) nowatch=1 ;; + --open-files-limit=*) open_files="$val" ;; + --open_files_limit=*) open_files="$val" ;; + --skip-kill-mysqld*) KILL_MYSQLD=0 ;; diff --git a/mysqld-prepare-db-dir b/mysqld-prepare-db-dir new file mode 100644 index 0000000..72badd7 --- /dev/null +++ b/mysqld-prepare-db-dir @@ -0,0 +1,54 @@ +#!/bin/sh + +# This script creates the mysql data directory during first service start. +# In subsequent starts, it does nothing much. + +# extract value of a MySQL option from config files +# Usage: get_mysql_option SECTION VARNAME DEFAULT +# result is returned in $result +# We use my_print_defaults which prints all options from multiple files, +# with the more specific ones later; hence take the last match. +get_mysql_option(){ + result=`/usr/bin/my_print_defaults "$1" | sed -n "s/^--$2=//p" | tail -n 1` + if [ -z "$result" ]; then + # not found, use default + result="$3" + fi +} + +# Defaults here had better match what mysqld_safe will default to +get_mysql_option mysqld datadir "/var/lib/mysql" +datadir="$result" +get_mysql_option mysqld_safe log-error "/var/log/mysqld.log" +errlogfile="$result" + + +# Set up the errlogfile with appropriate permissions +touch "$errlogfile" +chown mysql:mysql "$errlogfile" +chmod 0640 "$errlogfile" +[ -x /sbin/restorecon ] && /sbin/restorecon "$errlogfile" + +# Make the data directory +if [ ! -d "$datadir/mysql" ] ; then + # First, make sure $datadir is there with correct permissions + # (note: if it's not, and we're not root, this'll fail ...) + if [ ! -e "$datadir" -a ! -h "$datadir" ] + then + mkdir -p "$datadir" || exit 1 + fi + chown mysql:mysql "$datadir" + chmod 0755 "$datadir" + [ -x /sbin/restorecon ] && /sbin/restorecon "$datadir" + + # Now create the database + echo "Initializing MySQL database" + /usr/bin/mysql_install_db --datadir="$datadir" --user=mysql + ret=$? + chown -R mysql:mysql "$datadir" + if [ $ret -ne 0 ] ; then + exit $ret + fi +fi + +exit 0 diff --git a/mysqld-wait-ready b/mysqld-wait-ready new file mode 100644 index 0000000..10e86fe --- /dev/null +++ b/mysqld-wait-ready @@ -0,0 +1,56 @@ +#!/bin/sh + +# This script waits for mysqld to be ready to accept connections +# (which can be many seconds or even minutes after launch, if there's +# a lot of crash-recovery work to do). +# Running this as ExecStartPost is useful so that services declared as +# "After mysqld" won't be started until the database is really ready. + +# Service file passes us the daemon's PID +daemon_pid="$1" + +# extract value of a MySQL option from config files +# Usage: get_mysql_option SECTION VARNAME DEFAULT +# result is returned in $result +# We use my_print_defaults which prints all options from multiple files, +# with the more specific ones later; hence take the last match. +get_mysql_option(){ + result=`/usr/bin/my_print_defaults "$1" | sed -n "s/^--$2=//p" | tail -n 1` + if [ -z "$result" ]; then + # not found, use default + result="$3" + fi +} + +# Defaults here had better match what mysqld_safe will default to +get_mysql_option mysqld datadir "/var/lib/mysql" +datadir="$result" +get_mysql_option mysqld socket "$datadir/mysql.sock" +socketfile="$result" + +# Wait for the server to come up or for the mysqld process to disappear +ret=0 +while /bin/true; do + RESPONSE=`/usr/bin/mysqladmin --socket="$socketfile" --user=UNKNOWN_MYSQL_USER ping 2>&1` + mret=$? + if [ $mret -eq 0 ]; then + break + fi + # exit codes 1, 11 (EXIT_CANNOT_CONNECT_TO_SERVICE) are expected, + # anything else suggests a configuration error + if [ $mret -ne 1 -a $mret -ne 11 ]; then + ret=1 + break + fi + # "Access denied" also means the server is alive + echo "$RESPONSE" | grep -q "Access denied for user" && break + + # Check process still exists + if ! /bin/kill -0 $daemon_pid 2>/dev/null; then + ret=1 + break + fi + sleep 1 +done + +exit $ret diff --git a/mysqld.service b/mysqld.service new file mode 100644 index 0000000..b3bc486 --- /dev/null +++ b/mysqld.service @@ -0,0 +1,24 @@ +[Unit] +Description=MySQL database server +After=syslog.target +After=network.target + +[Service] +Type=forking +User=mysql +Group=mysql + +ExecStartPre=/usr/libexec/mysqld-prepare-db-dir +# Note: we set --basedir to prevent probes that might trigger SELinux alarms, +# per bug #547485 +ExecStart=/usr/bin/mysqld_safe --nowatch --basedir=/usr +ExecStartPost=/usr/libexec/mysqld-wait-ready $MAINPID + +# Give a reasonable amount of time for the server to start up/shut down +TimeoutSec=300 + +# We rely on systemd, not mysqld_safe, to restart mysqld if it dies +Restart=always + +[Install] +WantedBy=multi-user.target