Refactor Galera module

- Implements clustercheck script
- Switch haproxy to clustercheck
- Refactor Galera module
- Fix linting
- Add Rakefile, Gemfile
- Add more settings to wsrep.conf
- Update Modulefile

Change-Id: I14aaf056ec7a086ae07ab699bcb9b8f1403d8490
Implements: bp/galera-improvements
This commit is contained in:
Sergii Golovatiuk 2014-07-11 19:36:28 +00:00
parent 7d7ec0d76e
commit a81f668672
13 changed files with 422 additions and 238 deletions

View File

@ -0,0 +1,16 @@
source ENV['GEM_SOURCE'] || 'https://rubygems.org'
group :development, :test do
gem 'puppetlabs_spec_helper', :require => false
gem 'puppet-lint', :require => false
gem 'rake', '~> 10.1.1', :require => false
gem 'rspec-puppet', :require => false
end
if puppetversion = ENV['PUPPET_GEM_VERSION']
gem 'puppet', puppetversion, :require => false
else
gem 'puppet', :require => false
end
# vim:ft=ruby

View File

@ -1,5 +1,13 @@
name 'Mirantis-galera'
version ''
name 'mirantis-galera'
version '0.0.1'
source 'none'
author ''
license ''
license 'Apache License, Version 2.0'
summary 'Install/Configure Galera for MySQL Server'
description 'Install/Configure Galera for MySQL Server'
dependency 'puppetlabs/stdlib', '>= 4.0.0'
dependency 'puppetlabs/apt', '>= 1.4.1'
dependency 'puppetlabs/mysql', '>= 0.0.3'
dependency 'puppetlabs/firewall', '>= 1.0.0'
dependency 'puppetlabs/xinetd', '>= 1.2.0'

View File

@ -0,0 +1,17 @@
require 'puppetlabs_spec_helper/rake_tasks'
require 'puppet-lint/tasks/puppet-lint'
PuppetLint.configuration.send('disable_80chars')
PuppetLint.configuration.ignore_paths = ["spec/**/*.pp", "pkg/**/*.pp"]
desc "Run puppet in noop mode and check for syntax errors."
task :validate do
Dir['manifests/**/*.pp'].each do |manifest|
sh "puppet parser validate --noop #{manifest}"
end
Dir['spec/**/*.rb','lib/**/*.rb'].each do |ruby_file|
sh "ruby -c #{ruby_file}" unless ruby_file =~ /spec\/fixtures/
end
Dir['templates/**/*.erb'].each do |template|
sh "erb -P -x -T '-' #{template} | ruby -c"
end
end

View File

@ -46,22 +46,20 @@
#
class galera (
$cluster_name,
$cluster_name = 'openstack',
$primary_controller = false,
$node_address = $ipaddress_eth0,
$setup_multiple_gcomm = true,
$skip_name_resolve = false,
$node_addresses = [$ipaddress_eth0],
$node_addresses = $ipaddress_eth0,
$use_syslog = false,
$gcomm_port = '4567',
$status_check = true,
) {
include galera::params
anchor {'galera': }
$service_name = "mysql"
$res_name = "p_${service_name}"
$mysql_user = $::galera::params::mysql_user
$mysql_password = $::galera::params::mysql_password
$libgalera_prefix = $::galera::params::libgalera_prefix
@ -73,95 +71,72 @@ class galera (
$myisam_sort_buffer_size = $::galera::params::myisam_sort_buffer_size
$wait_timeout = $::galera::params::wait_timeout
$open_files_limit= $::galera::params::open_files_limit
$innodb_flush_log_at_trx_commit=$::galera::params::innodb_flush_log_at_trx_commit
$datadir=$::mysql::params::datadir
case $::osfamily {
'RedHat' : {
file { '/etc/init.d/mysql':
package { ['wget',
'perl']:
ensure => present,
mode => '0644',
require => Package['MySQL-server'],
before => File['mysql-wss-ocf']
before => Package['MySQL-server'],
}
file { '/etc/my.cnf':
ensure => present,
content => template("galera/my.cnf.erb"),
content => template('galera/my.cnf.erb'),
before => File['mysql-wss-ocf']
}
package { 'wget':
ensure => present,
before => Package['MySQL-server']
}
package { 'bc':
ensure => present,
before => Package['MySQL-server']
}
package { 'perl':
ensure => present,
before => Package['mysql-client']
}
}
'Debian' : {
file { '/etc/init.d/mysql':
ensure => present,
mode => '0644',
source => 'puppet:///modules/galera/mysql.init' ,
require => Package['MySQL-server'],
before => File['mysql-wss-ocf']
}
file { '/etc/my.cnf':
ensure => present,
content => template("galera/my.cnf.erb"),
before => File['mysql-wss-ocf']
}
package { 'wget':
ensure => present,
before => Package['mysql-client']
}
package { 'perl':
ensure => present,
before => Package['mysql-client']
}
package { 'bc':
ensure => present,
before => Package['MySQL-server']
}
package { 'mysql-common':
ensure => present,
before => Package['MySQL-server']
}
}
}
package { 'mysql-client':
ensure => present,
name => $::galera::params::mysql_client_name,
before => Package['MySQL-server']
}
file { ['/etc/mysql',
'/etc/mysql/conf.d']:
ensure => directory,
before => Package['MySQL-server']
}
package { [$::galera::params::libssl_package,
$::galera::params::libaio_package]:
ensure => present,
before => Package['galera', 'MySQL-server']
}
package { 'galera':
ensure => present,
before => Package['MySQL-server']
}
if $::galera::params::mysql_version {
$wsrep_version = $::galera::params::mysql_version
} else {
$wsrep_version = 'installed'
}
package { 'MySQL-server':
ensure => $wsrep_version,
name => $::galera::params::mysql_server_name,
provider => $::galera::params::pkg_provider,
}
file { '/etc/init.d/mysql':
ensure => present,
mode => '0644',
require => Package['MySQL-server'],
before => File['mysql-wss-ocf']
}
if $primary_controller {
$galera_pid = $osfamily ? {
$galera_pid = $::osfamily ? {
'RedHat' => '/var/run/mysql/mysqld.pid',
'Debian' => '/var/run/mysqld/mysqld.pid',
}
$galera_socket = $osfamily ? {
$galera_socket = $::osfamily ? {
'RedHat' => '/var/lib/mysql/mysql.sock',
'Debian' => '/var/run/mysqld/mysqld.sock',
}
cs_resource { "$res_name":
cs_resource { 'p_mysql':
ensure => present,
primitive_class => 'ocf',
provided_by => 'mirantis',
@ -188,73 +163,38 @@ class galera (
},
},
}
Anchor['galera'] -> File['mysql-wss-ocf'] -> Cs_resource[$res_name] -> Service[$service_name]
exec { 'start-new-galera-cluster':
path => "/usr/bin:/usr/sbin:/bin:/sbin",
logoutput => true,
command => 'echo Primary-controller completed',
}
Service["$service_name"] -> Exec['start-new-galera-cluster']
Exec['start-new-galera-cluster'] -> Exec['wait-for-synced-state']
Exec['start-new-galera-cluster'] ~> Exec['raise-first-setup-flag']
notify{'xxx-controller-primary':}
Anchor['galera'] ->
File['mysql-wss-ocf'] ->
Cs_resource['p_mysql'] ->
Service['mysql'] ->
Exec['wait-for-synced-state']
} else {
Anchor['galera'] -> File['mysql-wss-ocf'] -> Service[$service_name]
notify{'xxx-controller-ordinary':}
Anchor['galera'] ->
File['mysql-wss-ocf'] ->
Service['mysql']
}
file {'mysql-wss-ocf':
file { 'mysql-wss-ocf':
path => '/usr/lib/ocf/resource.d/mirantis/mysql-wss',
mode => '0755',
owner => root,
group => root,
source => "puppet:///modules/galera/ocf/mysql-wss",
source => 'puppet:///modules/galera/ocf/mysql-wss',
}
File<| title == 'ocf-mirantis-path' |> -> File['mysql-wss-ocf']
Package['MySQL-server'] -> File['mysql-wss-ocf']
Package['galera'] -> File['mysql-wss-ocf']
service { $service_name:
name => $res_name,
enable => true,
service { 'mysql':
ensure => 'running',
name => 'p_mysql',
enable => true,
provider => 'pacemaker',
}
Service[$service_name] -> Anchor['galera-done']
package { [$::galera::params::libssl_package, $::galera::params::libaio_package]:
ensure => present,
before => Package["galera", "MySQL-server"]
}
if $::galera::params::mysql_version {
$wsrep_version = $::galera::params::mysql_version
} else {
$wsrep_version = 'installed'
}
package { "MySQL-server":
ensure => $wsrep_version,
name => $::galera::params::mysql_server_name,
provider => $::galera::params::pkg_provider,
require => Package['galera']
}
package { "galera":
ensure => present,
}
# Uncomment the following Exec and sequence arrow to obtain full MySQL server installation log
# ->
# exec { "debug -mysql-server-installation" :
# command => "/usr/bin/yum -d 10 -e 10 -y install MySQL-server 2>&1 | tee mysql_install.log",
# before => Package["MySQL-server"],
# logoutput => true,
# }
file { ["/etc/mysql", "/etc/mysql/conf.d"]: ensure => directory, }
Service['mysql'] -> Anchor['galera-done']
if $::galera_gcomm_empty == "true" {
#FIXME(bogdando): dirtyhack to pervert imperative puppet nature.
@ -273,29 +213,25 @@ class galera (
$innodb_log_file_size_real = $::mysql_log_file_size_real
}
file { "/etc/mysql/conf.d/wsrep.cnf":
file { '/etc/mysql/conf.d/wsrep.cnf':
ensure => present,
content => template("galera/wsrep.cnf.erb"),
require => [File["/etc/mysql/conf.d"], File["/etc/mysql"]],
content => template('galera/wsrep.cnf.erb'),
require => [File['/etc/mysql/conf.d'], File['/etc/mysql']],
}
File["/etc/mysql/conf.d/wsrep.cnf"] -> Package['MySQL-server']
File['/etc/mysql/conf.d/wsrep.cnf'] -> Package['MySQL-server']
}
#TODO: find another way of mysql initial replication users creation
# This file contains initial sql requests for creating replication users.
file { "/tmp/wsrep-init-file":
file { '/tmp/wsrep-init-file':
ensure => present,
content => template("galera/wsrep-init-file.erb"),
content => template('galera/wsrep-init-file.erb'),
}
# This exec waits for initial sync of galera cluster after mysql replication user creation.
$user_password_string="-u${mysql_user} -p${mysql_password}"
exec { "wait-initial-sync":
exec { 'wait-initial-sync':
logoutput => true,
command => "/usr/bin/mysql ${user_password_string} -Nbe \"show status like 'wsrep_local_state_comment'\" | /bin/grep -q -e Synced -e Initialized && sleep 10",
try_sleep => 5,
@ -303,30 +239,27 @@ class galera (
refreshonly => true,
}
exec { "rm-init-file":
command => "/bin/rm /tmp/wsrep-init-file",
exec { 'rm-init-file':
command => '/bin/rm /tmp/wsrep-init-file',
}
exec { "wait-for-synced-state":
exec { 'wait-for-synced-state':
logoutput => true,
command => "/usr/bin/mysql ${user_password_string} -Nbe \"show status like 'wsrep_local_state_comment'\" | /bin/grep -q Synced && sleep 10",
try_sleep => 5,
tries => 60,
}
exec { "raise-first-setup-flag" :
path => "/usr/bin:/usr/sbin:/bin:/sbin",
command => "crm_attribute -t crm_config --name mysqlprimaryinit --update done",
refreshonly => true,
}
File['/tmp/wsrep-init-file'] ->
Service[$service_name] ->
Service['mysql'] ->
Exec['wait-initial-sync'] ->
Exec['wait-for-synced-state'] ->
Exec ['rm-init-file']
Package['MySQL-server'] ~> Exec['wait-initial-sync']
if $status_check {
include galera::status
}
anchor {'galera-done': }
}

View File

@ -26,13 +26,12 @@ class galera::params {
$mysql_buffer_pool_size = "${buffer_size}M"
$mysql_log_file_size =
inline_template("<%= [(${buffer_size} * 0.25 + 0).floor, 2047].min %>M")
$wait_timeout = '3600'
$wait_timeout = '1800'
$myisam_sort_buffer_size = '64M'
$key_buffer_size = '64M'
$table_open_cache = '10000'
$open_files_limit = '102400'
$max_connections = '4096'
$innodb_flush_log_at_trx_commit = '2'
case $::osfamily {
'RedHat': {

View File

@ -0,0 +1,94 @@
# == Class: galera::status
#
# Configures a user and script that will check the status
# of galera cluster,
#
# === Parameters:
#
# [*address*]
# (optional) xinet.d bind address for clustercheck
#
# [*status_user*]
# (optiona) The name of user to use for status checks
# Defaults to 'clustercheck'
#
# [*status_password*]
# (optional) The password of the status check user
# Defaults to 'clustercheck!'
#
# [*status_allow*]
# (optional) The subnet to allow status checks from
# Defaults to '%'
#
# [*port*]
# (optional) Port for cluster check service
# Defaults to 9200
#
class galera::status (
$address = '0.0.0.0',
$status_user = 'clustercheck',
$status_password = 'clustercheck!',
$status_allow = '%',
$port = '49000',
$mysql_module = '0.9',
) {
if ($mysql_module >= 2.2) {
mysql_user { "${status_user}@${status_allow}":
ensure => 'present',
password_hash => mysql_password($status_password),
require => Class['mysql::server'],
} ->
mysql_grant { "${status_user}@${status_allow}/*.*":
ensure => 'present',
option => [ 'GRANT' ],
privileges => [ 'STATUS' ],
table => '*.*',
user => "${status_user}@${status_allow}",
}
} else {
database_user { "${status_user}@${status_allow}":
ensure => 'present',
password_hash => mysql_password($status_password),
provider => 'mysql',
require => Class['mysql::server'],
} ->
database_grant { "${status_user}@${status_allow}/*.*":
privileges => [ 'Status_priv' ],
}
}
file { '/usr/local/bin/clustercheck':
content => template('galera/clustercheck.erb'),
mode => '0755',
}
augeas { 'galeracheck':
context => '/files/etc/services',
changes => [
"set /files/etc/services/service-name[port = '${port}']/port ${port}",
"set /files/etc/services/service-name[port = '${port}'] galeracheck",
"set /files/etc/services/service-name[port = '${port}']/protocol tcp",
"set /files/etc/services/service-name[port = '${port}']/#comment 'Galera Cluster Check'",
],
require => File['/usr/local/bin/clustercheck'],
}
$group = $::osfamily ? {
'redhat' => 'nobody',
'debian' => 'nogroup',
default => 'nobody',
}
xinetd::service { 'galeracheck':
bind => $address,
port => $port,
cps => '512 10',
per_source => 'UNLIMITED',
server => '/usr/local/bin/clustercheck',
user => 'nobody',
group => $group,
flags => 'IPv4',
require => File['/usr/local/bin/clustercheck'],
}
}

View File

@ -0,0 +1,5 @@
shared_examples_for "a Puppet::Error" do |description|
it "with message matching #{description.inspect}" do
expect { should have_class_count(1) }.to raise_error(Puppet::Error, description)
end
end

View File

@ -0,0 +1,6 @@
require 'puppetlabs_spec_helper/module_spec_helper'
RSpec.configure do |c|
c.alias_it_should_behave_like_to :it_configures, 'configures'
c.alias_it_should_behave_like_to :it_raises, 'raises'
end

View File

@ -0,0 +1,83 @@
#!/bin/bash
#
# Script to make a proxy (ie HAProxy) capable of monitoring Percona XtraDB Cluster nodes properly
#
# Author: Olaf van Zandwijk <olaf.vanzandwijk@nedap.com>
# Author: Raghavendra Prabhu <raghavendra.prabhu@percona.com>
#
# Documentation and download: https://github.com/olafz/percona-clustercheck
#
# Based on the original script from Unai Rodriguez
#
if [[ $1 == '-h' || $1 == '--help' ]];then
echo "Usage: $0 <user> <pass> <available_when_donor=0|1> <log_file> <available_when_readonly=0|1> <defaults_extra_file>"
exit
fi
MYSQL_USERNAME="<%= @status_user %>"
MYSQL_PASSWORD="<%= @status_password %>"
AVAILABLE_WHEN_DONOR=${3:-0}
ERR_FILE="${4:-/dev/null}"
AVAILABLE_WHEN_READONLY=${5:-1}
DEFAULTS_EXTRA_FILE=${6:-/etc/my.cnf}
#Timeout exists for instances where mysqld may be hung
TIMEOUT=10
if [[ -r $DEFAULTS_EXTRA_FILE ]];then
MYSQL_CMDLINE="mysql --defaults-extra-file=$DEFAULTS_EXTRA_FILE -nNE --connect-timeout=$TIMEOUT \
--user=${MYSQL_USERNAME} --password=${MYSQL_PASSWORD}"
else
MYSQL_CMDLINE="mysql -nNE --connect-timeout=$TIMEOUT --user=${MYSQL_USERNAME} --password=${MYSQL_PASSWORD}"
fi
#
# Perform the query to check the wsrep_local_state
#
WSREP_STATUS=$($MYSQL_CMDLINE -e "SHOW STATUS LIKE 'wsrep_local_state';" \
2>${ERR_FILE} | tail -1 2>>${ERR_FILE})
if [[ "${WSREP_STATUS}" == "4" ]] || [[ "${WSREP_STATUS}" == "2" && ${AVAILABLE_WHEN_DONOR} == 1 ]]
then
# Check only when set to 0 to avoid latency in response.
if [[ $AVAILABLE_WHEN_READONLY -eq 0 ]];then
READ_ONLY=$($MYSQL_CMDLINE -e "SHOW GLOBAL VARIABLES LIKE 'read_only';" \
2>${ERR_FILE} | tail -1 2>>${ERR_FILE})
if [[ "${READ_ONLY}" == "ON" ]];then
# Percona XtraDB Cluster node local state is 'Synced', but it is in
# read-only mode. The variable AVAILABLE_WHEN_READONLY is set to 0.
# => return HTTP 503
# Shell return-code is 1
echo -en "HTTP/1.1 503 Service Unavailable\r\n"
echo -en "Content-Type: text/plain\r\n"
echo -en "Connection: close\r\n"
echo -en "Content-Length: 43\r\n"
echo -en "\r\n"
echo -en "Percona XtraDB Cluster Node is read-only.\r\n"
sleep 0.1
exit 1
fi
fi
# Percona XtraDB Cluster node local state is 'Synced' => return HTTP 200
# Shell return-code is 0
echo -en "HTTP/1.1 200 OK\r\n"
echo -en "Content-Type: text/plain\r\n"
echo -en "Connection: close\r\n"
echo -en "Content-Length: 40\r\n"
echo -en "\r\n"
echo -en "Percona XtraDB Cluster Node is synced.\r\n"
sleep 0.1
exit 0
else
# Percona XtraDB Cluster node local state is not 'Synced' => return HTTP 503
# Shell return-code is 1
echo -en "HTTP/1.1 503 Service Unavailable\r\n"
echo -en "Content-Type: text/plain\r\n"
echo -en "Connection: close\r\n"
echo -en "Content-Length: 44\r\n"
echo -en "\r\n"
echo -en "Percona XtraDB Cluster Node is not synced.\r\n"
sleep 0.1
exit 1
fi

View File

@ -2,6 +2,5 @@ set wsrep_on='off';
delete from mysql.user where user='';
grant all on *.* to '<%= @mysql_user %>'@'%' identified by '<%= @mysql_password %>';
grant all on *.* to '<%= @mysql_user %>'@'localhost' identified by '<%= @mysql_password %>';
grant usage on *.* to 'cluster_watcher'@'%';
flush privileges;

View File

@ -1,15 +1,44 @@
[mysqld]
bind-address=<%= @node_address %>
port=3307
max_connections=<%= @max_connections %>
default-storage-engine=innodb
binlog_format=ROW
log_bin=mysql-bin
collation-server=utf8_general_ci
init-connect='SET NAMES utf8'
character-set-server=utf8
default-storage-engine=innodb
skip-external-locking
<% if @skip_name_resolve -%>
skip-name-resolve
<% end -%>
myisam_sort_buffer_size=<%= @myisam_sort_buffer_size %>
wait_timeout=<%= @wait_timeout %>
open_files_limit=<%= @open_files_limit %>
table_open_cache=<%= @table_open_cache %>
key_buffer_size=<%= @key_buffer_size %>
query_cache_size=0
query_cache_type=0
innodb_file_format=Barracuda
innodb_file_per_table=1
<% if @mysql_buffer_pool_size -%>
innodb_buffer_pool_size=<%= @mysql_buffer_pool_size %>
<% end -%>
<% if @innodb_log_file_size_real != '0' -%>
innodb_log_file_size=<%= @innodb_log_file_size_real %>
<% end -%>
innodb_read_io_threads=8
innodb_write_io_threads=8
innodb_io_capacity=500
innodb_flush_log_at_trx_commit=2
innodb_doublewrite=0
innodb_autoinc_lock_mode=2
binlog_format=ROW
log_bin=mysql-bin
innodb_locks_unsafe_for_binlog=1
<% if @setup_multiple_gcomm -%>
wsrep_cluster_address="gcomm://<%= @node_addresses.collect {|ip| ip + ':' + @gcomm_port.to_s }.join ',' %>?pc.wait_prim=no"
<% else -%>
@ -18,12 +47,6 @@ wsrep_cluster_address="gcomm://<%= @node_addresses.first %>:<%= @gcomm_port.to_s
wsrep_provider=<%= @libgalera_prefix %>/galera/libgalera_smm.so
wsrep_cluster_name="<%= @cluster_name -%>"
wsrep_certify_nonPK=1
wsrep_convert_LOCK_to_trx=0
wsrep_auto_increment_control=1
wsrep_drupal_282555_workaround=0
wsrep_causal_reads=0
wsrep_slave_threads=2
wsrep_sst_method=mysqldump
wsrep_sst_auth=<%= @mysql_user %>:<%= @mysql_password %>

View File

@ -7,6 +7,7 @@ class openstack::firewall (
$mysql_backend_port = 3307,
$mysql_gcomm_port = 4567,
$galera_ist_port = 4568,
$galera_clustercheck_port = 49000,
$keystone_public_port = 5000,
$swift_proxy_port = 8080,
$swift_object_port = 6000,
@ -90,7 +91,7 @@ class openstack::firewall (
}
firewall {'101 mysql':
port => [$mysql_port, $mysql_backend_port, $mysql_gcomm_port, $galera_ist_port],
port => [$mysql_port, $mysql_backend_port, $mysql_gcomm_port, $galera_ist_port, $galera_clustercheck_port],
proto => 'tcp',
action => 'accept',
}

View File

@ -12,14 +12,14 @@ class openstack::ha::mysqld (
before_start => $before_start,
haproxy_config_options => {
'option' => ['mysql-check user cluster_watcher', 'tcplog','clitcpka','srvtcpka'],
'balance' => 'roundrobin',
'option' => ['httpchk', 'tcplog','clitcpka','srvtcpka'],
'balance' => 'leastconn',
'mode' => 'tcp',
'timeout server' => '28801s',
'timeout client' => '28801s'
},
balancermember_options => 'check inter 15s fastinter 2s downinter 1s rise 5 fall 3',
balancermember_options => 'check port 49000 inter 15s fastinter 2s downinter 1s rise 3 fall 3',
}
package { 'socat': ensure => present }