--- /dev/null
+#
+# Copyright (C) 2015 eNovance SAS <licensing@enovance.com>
+#
+# Licensed under the Apache License, Version 2.0 (the "License"); you may
+# not use this file except in compliance with the License. You may obtain
+# a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless optional by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
+# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
+# License for the specific language governing permissions and limitations
+# under the License.
+#
+# == Class: tripleo::database::mysql
+#
+# Configure a MySQL for TripleO with or without HA.
+#
+# === Parameters
+#
+# [*bind_address*]
+# (optional) IP to bind MySQL daemon.
+# Defaults to undef
+#
+# [*mysql_root_password*]
+# (optional) MySQL root password.
+# Defaults to 'secrete'
+#
+# [*mysql_sys_maint_password*]
+# (optional) The MySQL debian-sys-maint password.
+# Debian only parameter.
+# Defaults to 'sys-maint'
+#
+# [*galera_clustercheck_dbpassword*]
+# (optional) The MySQL password for Galera cluster check
+# Defaults to 'password'
+#
+# [*galera_clustercheck_dbuser*]
+# (optional) The MySQL username for Galera cluster check (using monitoring database)
+# Defaults to 'clustercheck'
+#
+# [*galera_clustercheck_ipaddress*]
+# (optional) The name or ip address of host running monitoring database (clustercheck)
+# Defaults to undef
+#
+# [*galera_gcache*]
+# (optional) Size of the Galera gcache
+# wsrep_provider_options, for master/slave mode
+# Defaults to '1G'
+#
+# [*galera_master*]
+# (optional) Hostname or IP of the Galera master node, databases and users
+# resources are created on this node and propagated on the cluster.
+# Defining to false means we disable MySQL HA and run a single node setup.
+# Defaults to false
+#
+# [*controller_host*]
+# (optional) Array of internal ip of the controller nodes.
+# They need access to all OpenStack databases.
+# Defaults to false
+#
+# [*database_host*]
+# (optional) Array of internal ip of the database nodes.
+# Used to boostrap Galera cluster.
+# Defaults to false
+#
+# [*ceilometer_database_connection*]
+# (optional) URL to connect at Ceilometer database.
+# Example: 'mysql://user:password@host/database'
+# Defaults to undef
+#
+# [*cinder_database_connection*]
+# (optional) URL to connect at Cinder database.
+# Example: 'mysql://user:password@host/database'
+# Defaults to undef
+#
+# [*glance_database_connection*]
+# (optional) URL to connect at Glance database.
+# Example: 'mysql://user:password@host/database'
+# Defaults to undef
+#
+# [*heat_database_connection*]
+# (optional) URL to connect at Heat database.
+# Example: 'mysql://user:password@host/database'
+# Defaults to undef
+#
+# [*keystone_database_connection*]
+# (optional) URL to connect at Keystone database.
+# Example: 'mysql://user:password@host/database'
+# Defaults to undef
+#
+# [*neutron_database_connection*]
+# (optional) URL to connect at Neutron database.
+# Example: 'mysql://user:password@host/database'
+# Defaults to undef
+#
+# [*nova_database_connection*]
+# (optional) URL to connect at Nova database.
+# Example: 'mysql://user:password@host/database'
+# Defaults to undef
+#
+class tripleo::database::mysql (
+ $bind_address = undef,
+ $mysql_root_password = 'secrete',
+ $mysql_sys_maint_password = 'sys-maint',
+ $galera_clustercheck_dbpassword = 'secrete',
+ $galera_clustercheck_dbuser = 'clustercheck',
+ $galera_clustercheck_ipaddress = undef,
+ $galera_gcache = '1G',
+ $galera_master = false,
+ $controller_host = false,
+ $database_host = false,
+ $ceilometer_database_connection = undef,
+ $cinder_database_connection = undef,
+ $glance_database_connection = undef,
+ $heat_database_connection = undef,
+ $keystone_database_connection = undef,
+ $neutron_database_connection = undef,
+ $nova_database_connection = undef,
+) {
+
+ include ::xinetd
+
+ $gcomm_definition = inline_template('<%= @database_host.join(",") + "?pc.wait_prim=no" -%>')
+
+ # If HA enabled
+ if $galera_master {
+ # Specific to Galera master node
+ if $::hostname == $galera_master {
+ mysql_database { 'monitoring':
+ ensure => 'present',
+ charset => 'utf8',
+ collate => 'utf8_unicode_ci',
+ require => File['/root/.my.cnf']
+ }
+ mysql_user { "${galera_clustercheck_dbuser}@localhost":
+ ensure => 'present',
+ password_hash => mysql_password($galera_clustercheck_dbpassword),
+ require => File['/root/.my.cnf']
+ }
+ mysql_grant { "${galera_clustercheck_dbuser}@localhost/monitoring":
+ ensure => 'present',
+ options => ['GRANT'],
+ privileges => ['ALL'],
+ table => 'monitoring.*',
+ user => "${galera_clustercheck_dbuser}@localhost",
+ }
+ Database_user<<| |>>
+ } else {
+ # NOTE(sileht): Only the master must create the password
+ # into the database, slave nodes must just use the password.
+ # The one in the database have been retrieved via galera.
+ file { "${::root_home}/.my.cnf":
+ content => "[client]\nuser=root\nhost=localhost\npassword=${mysql_root_password}\n",
+ owner => 'root',
+ mode => '0600',
+ }
+ }
+
+ # Specific to Red Hat or Debian systems
+ case $::osfamily {
+ 'RedHat': {
+ $mysql_server_package_name = 'mariadb-galera-server'
+ $mysql_client_package_name = 'mariadb'
+ $wsrep_provider = '/usr/lib64/galera/libgalera_smm.so'
+ $mysql_server_config_file = '/etc/my.cnf'
+ $mysql_init_file = '/usr/lib/systemd/system/mysql-bootstrap.service'
+
+ if $::hostname == $galera_master {
+ $mysql_service_name = 'mysql-bootstrap'
+ } else {
+ $mysql_service_name = 'mariadb'
+ }
+
+ # In Red Hat, the package does not perform the mysql db installation.
+ # We need to do this manually.
+ # Note: in MariaDB repository, package perform this action in post-install,
+ # but MariaDB is not packaged for Red Hat / CentOS 7 in MariaDB repository.
+ exec { 'bootstrap-mysql':
+ command => '/usr/bin/mysql_install_db --rpm --user=mysql',
+ unless => 'test -d /var/lib/mysql/mysql',
+ before => Service['mysqld'],
+ require => [Package[$mysql_server_package_name], File[$mysql_server_config_file]]
+ }
+
+ }
+ 'Debian': {
+ $mysql_server_package_name = 'mariadb-galera-server'
+ $mysql_client_package_name = 'mariadb-client'
+ $wsrep_provider = '/usr/lib/galera/libgalera_smm.so'
+ $mysql_server_config_file = '/etc/mysql/my.cnf'
+ $mysql_init_file = '/etc/init.d/mysql-bootstrap'
+
+ if $::hostname == $galera_master {
+ $mysql_service_name = 'mysql-bootstrap'
+ } else {
+ $mysql_service_name = 'mysql'
+ }
+
+ mysql_user { 'debian-sys-maint@localhost':
+ ensure => 'present',
+ password_hash => mysql_password($mysql_sys_maint_password),
+ require => File['/root/.my.cnf']
+ }
+
+ file{'/etc/mysql/debian.cnf':
+ ensure => file,
+ content => template('tripleo/database/debian.cnf.erb'),
+ owner => 'root',
+ group => 'root',
+ mode => '0600',
+ require => Exec['clean-mysql-binlog'],
+ }
+ }
+ default: {
+ err "${::osfamily} not supported yet"
+ }
+ }
+
+ file { $mysql_init_file :
+ content => template("tripleo/database/etc_initd_mysql_${::osfamily}"),
+ owner => 'root',
+ mode => '0755',
+ group => 'root',
+ notify => Service['mysqld'],
+ before => Package[$mysql_server_package_name],
+ }
+
+ class { 'mysql::server':
+ manage_config_file => false,
+ config_file => $mysql_server_config_file,
+ package_name => $mysql_server_package_name,
+ service_name => $mysql_service_name,
+ override_options => {
+ 'mysqld' => {
+ 'bind-address' => $bind_address,
+ }
+ },
+ root_password => $mysql_root_password,
+ notify => Service['xinetd'],
+ }
+
+ file { $mysql_server_config_file:
+ content => template('tripleo/database/mysql.conf.erb'),
+ mode => '0644',
+ owner => 'root',
+ group => 'root',
+ notify => [Service['mysqld'],Exec['clean-mysql-binlog']],
+ require => Package[$mysql_server_package_name],
+ }
+
+ class { 'mysql::client':
+ package_name => $mysql_client_package_name,
+ }
+
+ # Haproxy http monitoring
+ augeas { 'mysqlchk':
+ context => '/files/etc/services',
+ changes => [
+ 'ins service-name after service-name[last()]',
+ 'set service-name[last()] "mysqlchk"',
+ 'set service-name[. = "mysqlchk"]/port 9200',
+ 'set service-name[. = "mysqlchk"]/protocol tcp',
+ ],
+ onlyif => 'match service-name[. = "mysqlchk"] size == 0',
+ notify => [ Service['xinetd'], Exec['reload_xinetd'] ]
+ }
+ file {
+ '/etc/xinetd.d/mysqlchk':
+ content => template('tripleo/database/mysqlchk.erb'),
+ owner => 'root',
+ group => 'root',
+ mode => '0755',
+ require => File['/usr/bin/clustercheck'],
+ notify => [ Service['xinetd'], Exec['reload_xinetd'] ];
+ '/usr/bin/clustercheck':
+ ensure => present,
+ content => template('tripleo/database/clustercheck.erb'),
+ mode => '0755',
+ owner => 'root',
+ group => 'root';
+ }
+
+ exec{'clean-mysql-binlog':
+ # first sync take a long time
+ command => "/bin/bash -c '/usr/bin/mysqladmin --defaults-file=/root/.my.cnf shutdown ; /bin/rm ${::mysql::params::datadir}/ib_logfile*'",
+ path => '/usr/bin',
+ notify => Service['mysqld'],
+ refreshonly => true,
+ onlyif => "stat ${::mysql::params::datadir}/ib_logfile0 && test `du -sh ${::mysql::params::datadir}/ib_logfile0 | cut -f1` != '256M'",
+ }
+ } else {
+ # When HA is disabled
+ class { 'mysql::server':
+ override_options => {
+ 'mysqld' => {
+ 'bind-address' => $bind_address,
+ }
+ },
+ root_password => $mysql_root_password,
+ }
+ }
+
+ # On master node (when using Galera) or single node (when no HA)
+ if $galera_master == $::hostname or ! $galera_master {
+ # Create all the database schemas
+ $allowed_hosts = ['%',$controller_host]
+ $keystone_dsn = split($keystone_database_connection, '[@:/?]')
+ class { 'keystone::db::mysql':
+ user => $keystone_dsn[3],
+ password => $keystone_dsn[4],
+ host => $keystone_dsn[5],
+ dbname => $keystone_dsn[6],
+ allowed_hosts => $allowed_hosts,
+ }
+ $glance_dsn = split($glance_database_connection, '[@:/?]')
+ class { 'glance::db::mysql':
+ user => $glance_dsn[3],
+ password => $glance_dsn[4],
+ host => $glance_dsn[5],
+ dbname => $glance_dsn[6],
+ allowed_hosts => $allowed_hosts,
+ }
+ $nova_dsn = split($nova_database_connection, '[@:/?]')
+ class { 'nova::db::mysql':
+ user => $nova_dsn[3],
+ password => $nova_dsn[4],
+ host => $nova_dsn[5],
+ dbname => $nova_dsn[6],
+ allowed_hosts => $allowed_hosts,
+ }
+ $neutron_dsn = split($neutron_database_connection, '[@:/?]')
+ class { 'neutron::db::mysql':
+ user => $neutron_dsn[3],
+ password => $neutron_dsn[4],
+ host => $neutron_dsn[5],
+ dbname => $neutron_dsn[6],
+ allowed_hosts => $allowed_hosts,
+ }
+ $cinder_dsn = split($cinder_database_connection, '[@:/?]')
+ class { 'cinder::db::mysql':
+ user => $cinder_dsn[3],
+ password => $cinder_dsn[4],
+ host => $cinder_dsn[5],
+ dbname => $cinder_dsn[6],
+ allowed_hosts => $allowed_hosts,
+ }
+ $heat_dsn = split($heat_database_connection, '[@:/?]')
+ class { 'heat::db::mysql':
+ user => $heat_dsn[3],
+ password => $heat_dsn[4],
+ host => $heat_dsn[5],
+ dbname => $heat_dsn[6],
+ allowed_hosts => $allowed_hosts,
+ }
+ $ceilometer_dsn = split($ceilometer_database_connection, '[@:/?]')
+ class { 'ceilometer::db::mysql':
+ user => $ceilometer_dsn[3],
+ password => $ceilometer_dsn[4],
+ host => $ceilometer_dsn[5],
+ dbname => $ceilometer_dsn[6],
+ allowed_hosts => $allowed_hosts,
+ }
+ }
+
+}
--- /dev/null
+#!/bin/bash
+#
+### BEGIN INIT INFO
+# Provides: mysql-bootstrap
+# Required-Start: $remote_fs $syslog
+# Required-Stop: $remote_fs $syslog
+# Should-Start: $network $named $time
+# Should-Stop: $network $named $time
+# Default-Start: 2 3 4 5
+# Default-Stop: 0 1 6
+# Short-Description: Start and stop the mysql database server daemon
+# Description: Controls the main MariaDB database server daemon "mysqld"
+# and its wrapper script "mysqld_safe".
+### END INIT INFO
+#
+# Managed by Puppet
+#
+MYSQLD_STARTUP_TIMEOUT=${MYSQLD_STARTUP_TIMEOUT:-60}
+[ -e /etc/mysql/my.cnf ] && \
+ MYSQLD_DATA_DIR=$(awk -F= '/^datadir/{print $2}' /etc/mysql/my.cnf | sed -e 's/^ *//')
+MYSQLD_DATA_DIR=${MYSQLD_DATA_DIR:-<%= scope.lookupvar('::mysql::datadir') %>}
+set -e
+set -u
+${DEBIAN_SCRIPT_DEBUG:+ set -v -x}
+
+test -x /usr/sbin/mysqld || exit 0
+
+. /lib/lsb/init-functions
+
+SELF=$(cd $(dirname $0); pwd -P)/$(basename $0)
+CONF=/etc/mysql/my.cnf
+MYADMIN="/usr/bin/mysqladmin --defaults-file=/etc/mysql/debian.cnf"
+
+# priority can be overriden and "-s" adds output to stderr
+ERR_LOGGER="logger -p daemon.err -t /etc/init.d/mysql -i"
+
+# Safeguard (relative paths, core dumps..)
+cd /
+umask 077
+
+# mysqladmin likes to read /root/.my.cnf. This is usually not what I want
+# as many admins e.g. only store a password without a username there and
+# so break my scripts.
+export HOME=/etc/mysql/
+
+## Fetch a particular option from mysql's invocation.
+#
+# Usage: void mysqld_get_param option
+mysqld_get_param() {
+ /usr/sbin/mysqld --print-defaults \
+ | tr " " "\n" \
+ | grep -- "--$1" \
+ | tail -n 1 \
+ | cut -d= -f2
+}
+
+## Do some sanity checks before even trying to start mysqld.
+sanity_checks() {
+ # check for config file
+ if [ ! -r /etc/mysql/my.cnf ]; then
+ log_warning_msg "$0: WARNING: /etc/mysql/my.cnf cannot be read. See README.Debian.gz"
+ echo "WARNING: /etc/mysql/my.cnf cannot be read. See README.Debian.gz" | $ERR_LOGGER
+ fi
+
+ # check for diskspace shortage
+ datadir=`mysqld_get_param datadir`
+ if LC_ALL=C BLOCKSIZE= df --portability $datadir/. | tail -n 1 | awk '{ exit ($4>4096) }'; then
+ log_failure_msg "$0: ERROR: The partition with $datadir is too full!"
+ echo "ERROR: The partition with $datadir is too full!" | $ERR_LOGGER
+ exit 1
+ fi
+}
+
+## Checks if there is a server running and if so if it is accessible.
+#
+# check_alive insists on a pingable server
+# check_dead also fails if there is a lost mysqld in the process list
+#
+# Usage: boolean mysqld_status [check_alive|check_dead] [warn|nowarn]
+mysqld_status () {
+ ping_output=`$MYADMIN ping 2>&1`; ping_alive=$(( ! $? ))
+
+ ps_alive=0
+ pidfile=`mysqld_get_param pid-file`
+ if [ -f "$pidfile" ] && ps `cat $pidfile` >/dev/null 2>&1; then ps_alive=1; fi
+
+ if [ "$1" = "check_alive" -a $ping_alive = 1 ] ||
+ [ "$1" = "check_dead" -a $ping_alive = 0 -a $ps_alive = 0 ]; then
+ return 0 # EXIT_SUCCESS
+ else
+ if [ "$2" = "warn" ]; then
+ echo -e "$ps_alive processes alive and '$MYADMIN ping' resulted in\n$ping_output\n" | $ERR_LOGGER -p daemon.debug
+ fi
+ return 1 # EXIT_FAILURE
+ fi
+}
+
+#
+# main()
+#
+
+case "${1:-''}" in
+ 'start')
+ sanity_checks;
+ # Start daemon
+ log_daemon_msg "Starting MariaDB database server" "mysqld"
+ if mysqld_status check_alive nowarn; then
+ log_progress_msg "already running"
+ log_end_msg 0
+ else
+ # Could be removed during boot
+ test -e /var/run/mysqld || install -m 755 -o mysql -g root -d /var/run/mysqld
+
+ # Start MariaDB! in a Galera setup we want to use
+ # new-cluster only when the galera cluster hasn't been
+ # bootstraped
+ if [ -e ${MYSQLD_DATA_DIR}/grastate.dat ]; then
+ # normal boot
+ /usr/bin/mysqld_safe "${@:2}" > /dev/null 2>&1 &
+ else
+ # bootstrap boot
+ log_progress_msg " (Galera bootstrap) "
+ /usr/bin/mysqld_safe "${@:2}" --wsrep-new-cluster > /dev/null 2>&1 &
+ fi
+
+ # 6s was reported in #352070 to be too few when using ndbcluster
+ for i in $(seq 1 "${MYSQLD_STARTUP_TIMEOUT:-30}"); do
+ sleep 1
+ if mysqld_status check_alive nowarn ; then break; fi
+ log_progress_msg "."
+ done
+ if mysqld_status check_alive warn; then
+ log_end_msg 0
+ # Now start mysqlcheck or whatever the admin wants.
+ output=$(/etc/mysql/debian-start)
+ [ -n "$output" ] && log_action_msg "$output"
+ else
+ log_end_msg 1
+ log_failure_msg "Please take a look at the syslog"
+ fi
+ fi
+ ;;
+
+ 'stop')
+ # * As a passwordless mysqladmin (e.g. via ~/.my.cnf) must be possible
+ # at least for cron, we can rely on it here, too. (although we have
+ # to specify it explicit as e.g. sudo environments points to the normal
+ # users home and not /root)
+ log_daemon_msg "Stopping MariaDB database server" "mysqld"
+ if ! mysqld_status check_dead nowarn; then
+ set +e
+ shutdown_out=`$MYADMIN shutdown 2>&1`; r=$?
+ set -e
+ if [ "$r" -ne 0 ]; then
+ log_end_msg 1
+ [ "$VERBOSE" != "no" ] && log_failure_msg "Error: $shutdown_out"
+ log_daemon_msg "Killing MariaDB database server by signal" "mysqld"
+ killall -15 mysqld
+ server_down=
+ for i in `seq 1 600`; do
+ sleep 1
+ if mysqld_status check_dead nowarn; then server_down=1; break; fi
+ done
+ if test -z "$server_down"; then killall -9 mysqld; fi
+ fi
+ fi
+
+ if ! mysqld_status check_dead warn; then
+ log_end_msg 1
+ log_failure_msg "Please stop MariaDB manually and read /usr/share/doc/mariadb-server-5.5/README.Debian.gz!"
+ exit -1
+ else
+ log_end_msg 0
+ fi
+ ;;
+
+ 'restart')
+ set +e; $SELF stop; set -e
+ $SELF start
+ ;;
+
+ 'reload'|'force-reload')
+ log_daemon_msg "Reloading MariaDB database server" "mysqld"
+ $MYADMIN reload
+ log_end_msg 0
+ ;;
+
+ 'status')
+ if mysqld_status check_alive nowarn; then
+ log_action_msg "$($MYADMIN version)"
+ else
+ log_action_msg "MariaDB is stopped."
+ exit 3
+ fi
+ ;;
+
+ *)
+ echo "Usage: $SELF start|stop|restart|reload|force-reload|status"
+ exit 1
+ ;;
+esac
+