Switch to upstream mysql and galera modules

This change switches out our mysql and galera modules for the
puppetlabs-mysql and michaeltchapman-galera.

This change includes the following updates:
 - mysql module removed
 - galera module removed
 - mysql hacks were removed from openstacklib module
   https://review.fuel-infra.org/#/c/16445/
 - galera::client moved to openstack::galera::client
 - db modulars updated to use openstack::galera::client
 - database task updated to use galera module
 - create cluster::mysql to do pacemaker configuration for mysql
 - remove osnailyfacter::mysql_user
 - additional database noop tests
 - additional unit tests

Change-Id: Idd0957c677b87a2d8794e993417ef9e2f0ddf4a6
Implements-Blueprint: mysql-galera-librarian
Closes-Bug: #1524747
This commit is contained in:
Alex Schultz 2016-01-13 16:46:39 -07:00 committed by Sergii Golovatiuk
parent d943955d06
commit 041aa989a0
122 changed files with 705 additions and 6923 deletions

View File

@ -10,6 +10,7 @@ puppet/concat
puppet/datacat
puppet/filemapper
puppet/firewall
puppet/galera
puppet/glance
puppet/heat
puppet/horizon
@ -21,6 +22,7 @@ puppet/memcached
puppet/mongodb
puppet/monit
puppet/murano
puppet/mysql
puppet/neutron
puppet/nova
puppet/ntp

View File

@ -94,7 +94,7 @@ mod 'postgresql',
# Pull in puppet-openstacklib
mod 'openstacklib',
:git => 'https://github.com/fuel-infra/puppet-openstacklib.git',
:ref => '8.0.0-rc1'
:ref => '8.0.0-rc2'
# Pull in puppet-keystone
mod 'keystone',
@ -196,3 +196,13 @@ mod 'mcollective',
mod 'rabbitmq',
:git => 'https://github.com/fuel-infra/puppetlabs-rabbitmq.git',
:ref => '5.3.1-mos-rc1'
# Pull in puppetlabs-mysql
mod 'mysql',
:git => 'https://github.com/fuel-infra/puppetlabs-mysql.git',
:ref => '3.6.2'
# Pull in michaeltchapman-galera
mod 'galera',
:git => 'https://github.com/fuel-infra/puppet-galera.git',
:ref => '0.0.2'

View File

@ -10,3 +10,4 @@ fixtures:
heat: "#{source_dir}/../heat"
openstacklib: "#{source_dir}/../openstacklib"
inifile: "#{source_dir}/../inifile"
mysql: "#{source_dir}/../mysql"

View File

@ -0,0 +1,117 @@
# == Class: cluster::mysql
#
# Configure OCF service for mysql managed by corosync/pacemaker
#
# === Parameters
#
# [*primary_controller*]
# (required). Boolean. Flag to indicate if this on the primary contoller
#
# [*mysql_user*]
# (required). String. Mysql user to use for connection testing and status
# checks.
#
# [*mysql_password*]
# (requires). String. Password for the mysql user to checks with.
#
# [*mysql_config*]
# (optional). String. Location to the mysql.cnf to use when running the
# service.
# Defaults to '/etc/mysql/my.cnf'
#
# [*mysql_socket*]
# (optional). String. The socket file to use for connection checks.
# Defaults to '/var/run/mysqld/mysqld.sock'
#
class cluster::mysql (
$primary_controller,
$mysql_user,
$mysql_password,
$mysql_config = '/etc/mysql/my.cnf',
$mysql_socket = '/var/run/mysqld/mysqld.sock',
) {
$service_name = 'mysqld'
if $primary_controller {
cs_resource { "p_${service_name}":
ensure => present,
primitive_class => 'ocf',
provided_by => 'fuel',
primitive_type => 'mysql-wss',
complex_type => 'clone',
parameters => {
'config' => $mysql_config,
'test_user' => $mysql_user,
'test_passwd' => $mysql_password,
'socket' => $mysql_socket,
},
operations => {
'monitor' => {
'interval' => '60',
'timeout' => '55'
},
'start' => {
'interval' => '0',
'timeout' => '300'
},
'stop' => {
'interval' => '0',
'timeout' => '120'
},
},
}
Cs_resource["p_${service_name}"] ~>
Service[$service_name]
}
Service <| title == 'mysqld' |> {
name => 'p_mysqld',
provider => 'pacemaker',
}
# NOTE(aschultz): strings must contain single quotes only, see the
# create-init-file exec as to why
$init_file_contents = join([
"set wsrep_on='off';",
"delete from mysql.user where user='';",
"GRANT USAGE ON *.* TO '${mysql_user}'@'%' IDENTIFIED BY '${mysql_password}';",
"GRANT USAGE ON *.* TO '${mysql_user}'@'localhost' IDENTIFIED BY '${mysql_password}';",
"flush privileges;",
], "\n")
$user_password_string = "-u${mysql_user} -p${mysql_password}"
# This file is used to prep the mysql instance with the monitor user so that
# pacemaker can check that the instance is UP.
# NOTE(aschultz): we are using an exec here because we only want to create
# the init file before the mysql service is not running. This is used to
# bootstrap the service so we only do it the first time. For idempotency
# this exec would be skipped when run a second time with mysql running.
exec { 'create-init-file':
path => '/bin:/sbin:/usr/bin:/usr/sbin',
command => "echo \"${init_file_contents}\" > /tmp/wsrep-init-file",
unless => "mysql ${user_password_string} -Nbe \"select 'OK';\" | grep -q OK",
require => Package['mysql-server'],
before => Service[$service_name],
} ~>
exec { 'wait-initial-sync':
path => '/bin:/sbin:/usr/bin:/usr/sbin',
command => "mysql ${user_password_string} -Nbe \"show status like 'wsrep_local_state_comment'\" | grep -q -e Synced -e Initialized && sleep 10",
try_sleep => 10,
tries => 60,
refreshonly => true,
}
exec { 'rm-init-file':
path => '/bin:/sbin:/usr/bin:/usr/sbin',
command => 'rm /tmp/wsrep-init-file',
onlyif => 'test -f /tmp/wsrep-init-file',
}
Exec['create-init-file'] ->
Service['mysqld'] ->
Exec['wait-initial-sync'] ->
Exec['rm-init-file']
}

View File

@ -0,0 +1,69 @@
require 'spec_helper'
describe 'cluster::mysql' do
let(:pre_condition) do
'include ::mysql::server'
end
shared_examples_for 'cluster::mysql configuration' do
context 'with valid params' do
let :params do
{
:primary_controller => true,
:mysql_user => 'username',
:mysql_password => 'password',
}
end
it 'configures a cs_resource' do
should contain_cs_resource('p_mysqld').with(
:ensure => 'present',
:parameters => {
'config' => '/etc/mysql/my.cnf',
'test_user' => 'username',
'test_passwd' => 'password',
'socket' =>'/var/run/mysqld/mysqld.sock'
}
)
should contain_cs_resource('p_mysqld').that_notifies('Service[mysqld]')
end
it 'creates init-file with grants' do
should contain_exec('create-init-file').with_command(
/'username'@'%' IDENTIFIED BY 'password'/
)
should contain_exec('create-init-file').with_command(
/'username'@'localhost' IDENTIFIED BY 'password'/
)
should contain_exec('create-init-file').that_comes_before('Service[mysqld]')
should contain_exec('create-init-file').that_notifies('Exec[wait-initial-sync]')
end
it 'creates exec to remove init-file' do
should contain_exec('rm-init-file')
end
end
end
context 'on Debian platforms' do
let :facts do
{ :osfamily => 'Debian',
:operatingsystem => 'Debian',
:hostname => 'hostname.example.com', }
end
it_configures 'cluster::mysql configuration'
end
context 'on RedHat platforms' do
let :facts do
{ :osfamily => 'RedHat',
:operatingsystem => 'RedHat',
:hostname => 'hostname.example.com', }
end
it_configures 'cluster::mysql configuration'
end
end

View File

@ -1,8 +0,0 @@
fixtures:
symlinks:
galera: "#{source_dir}"
pacemaker: "#{source_dir}/../pacemaker"
tweaks: "#{source_dir}/../tweaks"
openstack: "#{source_dir}/../openstack"
stdlib: "#{source_dir}/../stdlib"
firewall: "#{source_dir}/../firewall"

View File

@ -1,6 +0,0 @@
*.swp
pkg/
.DS_Store
coverage/
fixtures/modules/

View File

@ -1,30 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>galera</name>
<comment></comment>
<projects>
<project>selinux</project>
</projects>
<buildSpec>
<buildCommand>
<name>com.aptana.ide.core.unifiedBuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.cloudsmith.geppetto.pp.dsl.ui.modulefileBuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.xtext.ui.shared.xtextBuilder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>org.cloudsmith.geppetto.pp.dsl.ui.puppetNature</nature>
<nature>com.aptana.ruby.core.rubynature</nature>
<nature>org.eclipse.xtext.ui.shared.xtextNature</nature>
</natures>
</projectDescription>

View File

@ -1,26 +0,0 @@
source ENV['GEM_SOURCE'] || "https://rubygems.org"
group :development, :unit_tests do
gem 'rake', :require => false
gem 'rspec-core', '~>3.3', :require => false
gem 'rspec-puppet', :require => false
gem 'puppetlabs_spec_helper', :require => false
gem 'puppet-lint', :require => false
gem 'simplecov', :require => false
gem 'puppet_facts', :require => false
gem 'json', :require => false
end
if facterversion = ENV['FACTER_GEM_VERSION']
gem 'facter', facterversion, :require => false
else
gem 'facter', :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,13 +0,0 @@
name 'fuel-galera'
version '0.0.1'
source 'none'
author ''
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

@ -1,35 +0,0 @@
This is a good start to play around with the galera multi-master mysql synchronous replication (http://www.codership.com/products/mysql_galera)
HOWTO:
* play around (add a database and data, chaos-monkey nodes etc.)
WARNING
Change the mysql root password in production and limit access to galera cluster members!
TODO
* naming: master -> donor
* put a load balancer in front of the cluster
* make cluster "masterless"
nodes.pp
# nodes
$cluster_name = 'wsrep_galera_cluster'
node /mysql-db-01/ {
class { 'galera' :
cluster_name => $cluster_name
}
}
node /mysql-db-0([2-9])/ {
$master_ip = '172.18.67.254'
class { 'galera' :
cluster_name => $cluster_name,
master_ip => $master_ip
}
}

View File

@ -1,10 +0,0 @@
require 'puppetlabs_spec_helper/rake_tasks'
require 'puppet-lint/tasks/puppet-lint'
PuppetLint.configuration.fail_on_warnings
PuppetLint.configuration.send('relative')
PuppetLint.configuration.send('disable_80chars')
PuppetLint.configuration.send('disable_class_inherits_from_params_class')
PuppetLint.configuration.send('disable_documentation')
PuppetLint.configuration.send('disable_single_quote_string_with_variables')
PuppetLint.configuration.ignore_paths = ["spec/**/*.pp", "pkg/**/*.pp"]

View File

@ -1,31 +0,0 @@
# Fact: galera_gcomm_empty
#
# Purpose: Return 'true' if gcomm:// cluster address is empty for Galera MySQL master-master replication engine
#
# Resolution:
# Greps mysql config files for wsrep_cluster_address option
#
# Caveats:
#
## Cfkey.rb
## Facts related to cfengine
##
result = "true"
#FIXME: do not hardcode wsrep config file location. We need to start from
#FIXME: mysql config file and go through all the include directives
if File.exists?("/etc/mysql/conf.d/wsrep.cnf")
if open("/etc/mysql/conf.d/wsrep.cnf").read.split("\n").grep(/^\s*wsrep_cluster_address=[\"\']gcomm:\/\/\s*[\"\']\s*/).any?
result="true"
else
result="false"
end
end
Facter.add("galera_gcomm_empty") do
setcode do
result
end
end

View File

@ -1,15 +0,0 @@
# Fact: mysql_log_file_size_real
#
# Purpose: Return size (M) of ib_logfile0, if exists
#
require 'facter'
Facter.add(:mysql_log_file_size_real) do
setcode do
f = '/var/lib/mysql/ib_logfile0'
if File.exists?(f)
(File.size(f).to_f / 1048576).round.to_s + 'M' rescue '0'
else
'0'
end
end
end

View File

@ -1,332 +0,0 @@
# Copyright 2013 Mirantis, Inc.
#
# 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 required 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.
#
#
# == Define: galera
#
# Class for installation and configuration of galer Master/Master cluster.
#
# === Parameters
#
# [*cluster_name*]
# Cluster name for `wsrep_cluster_name` variable.
#
# [*primary_controller*]
# Set to true if current node is the initial master/primary
# controller.
#
# [*node_address*]
# Which value to use as node address for filtering in gcomm address.
# This is done due to some bugs in galera configuration. Thus we are
# filtering this address from `wsrep_cluster_address` to avoid these
# problems.
#
# [*gcache_factor*]
# The gcache factor is based on cluster node's count.
# Used in config template for `wsrep_provider_option`.
#
# [*setup_multiple_gcomm*]
# Should gcomm address contain multiple nodes or not.
#
# [*skip_name_resolve*]
# By default, MySQL tries to do reverse name mapping IP->hostname. In this
# case MySQL requests can be timed out by clients in case of broken name
# resolving system. If you are not sure that your DNS/NIS/whatever are
# configured correctly, set this value to true.
#
# [*node_addresses*]
# Array with IPs/hostnames of cluster members.
#
# [*wsrep_sst_method*]
# (optional) The method for state snapshot transfer between nodes
# Defaults to xtrabackup-v2
# xtrabackup, xtrabackup-v2, mysqldump are supported
#
# [*use_percona*]
# Boolean. Set this value to true if you want to use percona instead of
# the mysql packages.
#
# [*use_percona_packages*]
# Boolean. Set this value to true to use the Percona distrubuted packages.
# This requires that these packages are available via a repository for the
# system at install time. NOTE: use_percona must be set to true for this to
# be used.
#
# [*binary_logs_enabled*]
# Set this value to true for enabling MySQL binary logging.
# Defaults to false
#
# [*binary_logs_period*]
# (optional) Set binary logrotation period in days.
# Defaults to 1
#
# [*binary_logs_maxsize*]
# (optional) If a write to the binary log causes the current log file
# size to exceed the value of this variable, the server rotates the
# binary logs (closes the current file and opens the next one). The
# minimum value is 4096 bytes. The maximum and default value is 512MB.
class galera (
$cluster_name = 'openstack',
$primary_controller = false,
$node_address = $ipaddress_eth0,
$setup_multiple_gcomm = true,
$skip_name_resolve = false,
$node_addresses = [ $ipaddress_eth0 ],
$gcache_factor = 0,
$use_syslog = false,
$gcomm_port = '4567',
$status_check = true,
$wsrep_sst_method = 'xtrabackup-v2',
$wsrep_sst_password = undef,
$use_percona = false,
$use_percona_packages = false,
$binary_logs_enabled = false,
$binary_logs_period = 1,
$binary_logs_maxsize = '512M',
) {
include galera::params
validate_array($node_addresses)
validate_bool($use_percona)
validate_bool($use_percona_packages)
anchor {'database-cluster': }
$mysql_user = $::galera::params::mysql_user
$mysql_password = $wsrep_sst_password ? {
undef => $::galera::params::mysql_password,
default => $wsrep_sst_password
}
$libgalera_prefix = $::galera::params::libgalera_prefix
$mysql_buffer_pool_size = $::galera::params::mysql_buffer_pool_size
$mysql_log_file_size = $::galera::params::mysql_log_file_size
$max_connections = $::galera::params::max_connections
$table_open_cache = $::galera::params::table_open_cache
$key_buffer_size = $::galera::params::key_buffer_size
$myisam_sort_buffer_size = $::galera::params::myisam_sort_buffer_size
$wait_timeout = $::galera::params::wait_timeout
$open_files_limit = $::galera::params::open_files_limit
$datadir = $::mysql::params::datadir
$service_name = $::galera::params::service_name
$innodb_flush_method = $::galera::params::innodb_flush_method
package { ['wget',
'perl']:
ensure => present,
before => Package['MySQL-server'],
}
file { '/etc/my.cnf':
ensure => present,
content => template('galera/my.cnf.erb'),
}
if ($use_percona and $::operatingsystem == 'Ubuntu') {
#FIXME:
#Remove this after https://bugs.launchpad.net/bugs/1461304 will be fixed
file {'/etc/apt/apt.conf.d/99tmp':
ensure => present,
content => inline_template("Dpkg::Options {\n\t\"--force-overwrite\";\n}"),
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']
}
if !($use_percona) {
package { $::galera::params::libaio_package:
ensure => present,
before => Package['galera', 'MySQL-server']
}
}
package { 'galera':
ensure => present,
name => $::galera::params::libgalera_package,
before => Package['MySQL-server']
}
if $::galera::params::mysql_version {
$wsrep_version = $::galera::params::mysql_version
} else {
$wsrep_version = 'installed'
}
if $wsrep_sst_method in [ 'xtrabackup', 'xtrabackup-v2' ] {
firewall {'101 xtrabackup':
port => 4444,
proto => 'tcp',
action => 'accept',
before => Package['MySQL-server'],
}
package { 'percona-xtrabackup':
ensure => present,
before => Package['MySQL-server'],
}
$wsrep_sst_auth = true
}
elsif $wsrep_sst_method == 'mysqldump' {
$wsrep_sst_auth = true
}
else {
$wsrep_sst_auth = undef
warning("Unrecognized wsrep_sst method: ${wsrep_sst_auth}")
}
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'],
}
if $primary_controller {
$galera_socket = $::galera::params::database_socket
# TODO(bogdando) move to extras as a wrapper class
cs_resource { "p_${service_name}":
ensure => present,
primitive_class => 'ocf',
provided_by => 'fuel',
primitive_type => 'mysql-wss',
complex_type => 'clone',
parameters => {
'test_user' => $mysql_user,
'test_passwd' => $mysql_password,
'socket' => $galera_socket,
},
operations => {
'monitor' => {
'interval' => '60',
'timeout' => '55'
},
'start' => {
'timeout' => '300'
},
'stop' => {
'timeout' => '120'
},
},
}
Anchor['database-cluster'] ->
Cs_resource["p_${service_name}"] ->
Service['mysql'] ->
Exec['wait-for-synced-state']
} else {
Anchor['database-cluster'] ->
Service['mysql']
}
tweaks::ubuntu_service_override { 'mysql':
package_name => 'MySQL-server',
}
service { 'mysql':
ensure => 'running',
name => "p_${service_name}",
enable => true,
provider => 'pacemaker',
}
Service['mysql'] -> Anchor['database-cluster-done']
#FIXME(bogdando): dirtyhack to pervert imperative puppet nature.
if $::mysql_log_file_size_real != $mysql_log_file_size {
if str2bool($::galera_gcomm_empty) {
# delete MySQL ib_logfiles, if log file size does not match the one
# from params
exec { 'delete_logfiles':
command => "rm -f ${datadir}/ib_logfile* || true",
path => [ '/sbin/', '/usr/sbin/', '/usr/bin/' ,'/bin/' ],
before => File['/etc/mysql/conf.d/wsrep.cnf'],
}
}
# use predefined value for log file size
$innodb_log_file_size_real = $mysql_log_file_size
} else {
# evaluate existing log file size and use it as a value
$innodb_log_file_size_real = $::mysql_log_file_size_real
}
file { '/etc/mysql/conf.d/wsrep.cnf':
ensure => present,
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'] ~> Service['mysql']
# This file contains initial sql requests for creating replication users.
file { '/tmp/wsrep-init-file':
ensure => present,
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':
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 => 10,
tries => 60,
refreshonly => true,
}
exec { 'rm-init-file':
command => '/bin/rm /tmp/wsrep-init-file',
}
exec { 'wait-for-synced-state':
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,
}
if ($use_percona and $::operatingsystem == 'Ubuntu') {
#Clean tmp files:
exec {'rm-99tmp':
command => '/bin/rm /etc/apt/apt.conf.d/99tmp',
}
Exec['wait-for-synced-state'] ->
Exec['rm-99tmp']
}
File['/tmp/wsrep-init-file'] ->
Service['mysql'] ->
Exec['wait-initial-sync'] ->
Exec['wait-for-synced-state'] ->
Exec['rm-init-file']
Package['MySQL-server'] ~> Exec['wait-initial-sync']
anchor {'database-cluster-done': }
}

View File

@ -1,98 +0,0 @@
# Copyright 2013 Mirantis, Inc.
#
# 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 required 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.
#
#
# these parameters need to be accessed from several locations and
# should be considered to be constant
class galera::params {
$mysql_user = 'wsrep_sst'
$mysql_password = 'password'
$service_name = 'mysql'
#TODO(bogdando) remove code duplication for galera and mysql manifests to openstack::db in 'I' release
#limit buffer size to 10G
$buffer_size =
inline_template("<%= [(${::memorysize_mb} * 0.2 + 0).floor, 10000].min %>")
$mysql_buffer_pool_size = "${buffer_size}M"
$mysql_log_file_size =
inline_template("<%= [(${buffer_size} * 0.2 + 0).floor, 2047].min %>M")
$wait_timeout = '1800'
$myisam_sort_buffer_size = '64M'
$key_buffer_size = '64'
$table_open_cache = '10000'
$open_files_limit = '102400'
$innodb_flush_method = 'O_DIRECT'
# default buffer's size
$sort_buffer_size_mb = '0.25'
$read_buffer_size_mb = '0.125'
$max_connections = inline_template(
"<%= [[((${::memorysize_mb} * 0.3 - ${key_buffer_size}) /
(${sort_buffer_size_mb} + ${read_buffer_size_mb})).floor, 8192].min, 2048].max %>")
if ($::galera::use_percona) {
case $::osfamily {
'RedHat': {
if ($::galera::use_percona_packages) {
$mysql_server_name = 'Percona-XtraDB-Cluster-server-56'
$mysql_client_name = 'Percona-XtraDB-Cluster-client-56'
$libgalera_package = 'Percona-XtraDB-Cluster-galera-3'
$libgalera_prefix = '/usr/lib64/galera3'
} else {
fail("Unsupported osfamily: ${::osfamily} operatingsystem: ${::operatingsystem}, module ${module_name} only supports Debian when not using the Percona packages")
}
$database_socket = '/var/lib/mysql/mysql.sock'
}
'Debian': {
if ($::galera::use_percona_packages) {
$mysql_server_name = 'percona-xtradb-cluster-server-5.6'
$mysql_client_name = 'percona-xtradb-cluster-client-5.6'
$libgalera_package = 'percona-xtradb-cluster-galera-3.x'
$libgalera_prefix = '/usr/lib/galera3'
} else {
$mysql_server_name = 'percona-xtradb-cluster-server-5.5'
$mysql_client_name = 'percona-xtradb-cluster-client-5.5'
$libgalera_package = 'percona-xtradb-cluster-galera-2.x'
$libgalera_prefix = '/usr/lib'
}
$database_socket = '/var/run/mysqld/mysqld.sock'
}
default: {
fail("Unsupported osfamily: ${::osfamily} operatingsystem: ${::operatingsystem}, module ${module_name} only support osfamily RedHat and Debian")
}
}
} else {
case $::osfamily {
'RedHat': {
$libaio_package = 'libaio'
$mysql_server_name = 'MySQL-server-wsrep'
$mysql_client_name = 'MySQL-client-wsrep'
$libgalera_package = 'galera'
$libgalera_prefix = '/usr/lib64/galera'
$database_socket = '/var/lib/mysql/mysql.sock'
}
'Debian': {
$libaio_package = 'libaio1'
$mysql_server_name = 'mysql-server-wsrep-5.6'
$mysql_client_name = 'mysql-client-5.6'
$libgalera_package = 'galera'
$libgalera_prefix = '/usr/lib/galera'
$database_socket = '/var/run/mysqld/mysqld.sock'
}
default: {
fail("Unsupported osfamily: ${::osfamily} operatingsystem: ${::operatingsystem}, module ${module_name} only support osfamily RedHat and Debian")
}
}
}
}

View File

@ -1,194 +0,0 @@
# this is a basic example that just checks there are no puppet syntax issues or
# compile errors
shared_examples 'compile' do
it {
should compile
}
end
# this example checks all of the expected items for the galera::init class
shared_examples 'galera-init' do |params|
params = {} if params.nil?
it {
should contain_class('galera')
should contain_class('galera::params')
should contain_tweaks__ubuntu_service_override('mysql')
}
it_behaves_like 'compile'
it_behaves_like 'test-packages', params
it_behaves_like 'test-files', params
it_behaves_like 'test-services', params
it_behaves_like 'test-primary-controller', params
it_behaves_like 'test-backup', params
end
# this example checks for the existance of the expected files for the galera
# class
shared_examples 'test-files' do |params|
params = {} if params.nil?
p = {
:use_percona_packages => false
}.merge(params)
let (:params) { p }
it {
should contain_file('/etc/my.cnf')
should contain_file('/etc/mysql')
should contain_file('/etc/mysql/conf.d')
should contain_file('/etc/init.d/mysql')
should contain_file('/etc/mysql/conf.d/wsrep.cnf')
should contain_file('/tmp/wsrep-init-file')
if params[:use_percona_packages] and facts[:operatingsystem] == 'Ubuntu'
should contain_file('/etc/apt/apt.conf.d/99tmp')
end
}
end
# this example checks for the definition of the specific packages expected for
# the galera class
shared_examples 'test-packages' do |params|
params = {} if params.nil?
p = {
:wsrep_sst_method => 'xtrabackup-v2',
:use_percona => false,
:use_percona_packages => false
}.merge(params)
let (:params) { p }
if params[:use_percona]
if params[:use_percona_packages]
it_behaves_like 'percona-packages'
else
it_behaves_like 'percona-distro-packages'
end
else
it_behaves_like 'mysql-packages'
end
end
# this example checks for the percona packages
shared_examples 'percona-packages' do |params|
it {
case facts[:operatingsystem]
when 'Ubuntu'
mysql_server_name = 'percona-xtradb-cluster-server-5.6'
mysql_client_name = 'percona-xtradb-cluster-client-5.6'
libgalera_package = 'percona-xtradb-cluster-galera-3.x'
when 'CentOS'
mysql_server_name = 'Percona-XtraDB-Cluster-server-56'
mysql_client_name = 'Percona-XtraDB-Cluster-client-56'
libgalera_package = 'Percona-XtraDB-Cluster-galera-3'
end
should contain_package('MySQL-server').with_name(mysql_server_name)
should contain_package('mysql-client').with_name(mysql_client_name)
should contain_package('galera').with_name(libgalera_package)
}
end
# this example checks for the percona packages
shared_examples 'percona-distro-packages' do |params|
it {
case facts[:operatingsystem]
when 'Ubuntu'
mysql_server_name = 'percona-xtradb-cluster-server-5.5'
mysql_client_name = 'percona-xtradb-cluster-client-5.5'
libgalera_package = 'percona-xtradb-cluster-galera-2.x'
should contain_package('MySQL-server').with_name(mysql_server_name)
should contain_package('mysql-client').with_name(mysql_client_name)
should contain_package('galera').with_name(libgalera_package)
when 'CentOS'
should raise_error(Puppet::Error, /Unsupported/)
end
}
end
# this example checks for the use of the mysql classes
shared_examples 'mysql-packages' do
it {
case facts[:operatingsystem]
when 'Ubuntu'
mysql_server_name = 'mysql-server-wsrep-5.6'
mysql_client_name = 'mysql-client-5.6'
libgalera_package = 'galera'
libaio_package = 'libaio1'
when 'CentOS'
mysql_server_name = 'MySQL-server-wsrep'
mysql_client_name = 'MySQL-client-wsrep'
libgalera_package = 'galera'
libaio_package = 'libaio'
end
should contain_package('MySQL-server').with_name(mysql_server_name)
should contain_package('mysql-client').with_name(mysql_client_name)
should contain_package('galera').with_name(libgalera_package)
should contain_package(libaio_package)
}
end
# this example checks for the expected services for the galera class
shared_examples 'test-services' do |params|
params = {} if params.nil?
p = {}.merge(params)
let (:params) { p }
it {
should contain_service('mysql').with({
'ensure' => 'running',
'name' => 'p_mysql',
'provider' => 'pacemaker'
})
}
end
# this example checks for the cluster resource definitions for a primary
# controller. This should probably not live in the galera class.
shared_examples 'test-primary-controller' do |params|
params = {} if params.nil?
p = {
:primary_controller => false
}.merge(params)
let (:params) { p }
it {
if params[:primary_controller]
should contain_cs_resource('p_mysql')
else
should_not contain_cs_resource('p_mysql')
end
}
end
# this example checks for the catalog items around the backup option
shared_examples 'test-backup' do |params|
params = {} if params.nil?
p = {
:wsrep_sst_method => 'xtrabackup-v2',
}.merge(params)
let (:params) { p }
if p.has_key?(:wsrep_sst_method) and ['xtrabackup', 'xtrabackup-v2'].include?(p[:wsrep_sst_method])
it {
should contain_firewall('101 xtrabackup').with_port(4444)
should contain_package('percona-xtrabackup')
should contain_file('/etc/mysql/conf.d/wsrep.cnf').with_content(/xtrabackup/)
}
else
it {
should_not contain_firewall('101 xtrabackup').with_port(4444)
should_not contain_package('percona-xtrabackup')
should_not contain_file('/etc/mysql/conf.d/wsrep.cnf').with_content(/xtrabackup/)
}
end
end
# vim: set ts=2 sw=2 et :

View File

@ -1,6 +0,0 @@
--format
s
--colour
--loadby
mtime
--backtrace

View File

@ -1,55 +0,0 @@
require 'rubygems'
require 'puppetlabs_spec_helper/module_spec_helper'
module Facts
def self.fqdn
'server.example.com'
end
def self.hostname
self.fqdn.split('.').first
end
def self.ipaddress
'10.0.0.1'
end
def self.ubuntu_facts
{
:fqdn => fqdn,
:hostname => hostname,
:processorcount => '4',
:memorysize_mb => '32138.66',
:memorysize => '31.39 GB',
:kernel => 'Linux',
:osfamily => 'Debian',
:operatingsystem => 'Ubuntu',
:operatingsystemrelease => '14.04',
:lsbdistid => 'Ubuntu',
:concat_basedir => '/tmp/',
:ipaddress_eth0 => ipaddress
}
end
def self.centos_facts
{
:fqdn => fqdn,
:hostname => hostname,
:processorcount => '4',
:memorysize_mb => '32138.66',
:memorysize => '31.39 GB',
:kernel => 'Linux',
:osfamily => 'RedHat',
:operatingsystem => 'CentOS',
:operatingsystemrelease => '6.5',
:lsbdistid => 'CentOS',
:concat_basedir => '/tmp/',
:ipaddress_eth0 => ipaddress
}
end
end
# Generage coverage report at the end of a run
at_exit { RSpec::Puppet::Coverage.report! }
# vim: set ts=2 sw=2 et :

View File

@ -1,87 +0,0 @@
require 'spec_helper.rb'
require 'shared-examples'
describe 'galera', :type => :class do
context 'Defaults on CentOS' do
let(:facts) { Facts.centos_facts }
it_behaves_like 'galera-init'
end
context 'Defaults on Ubuntu' do
let(:facts) { Facts.ubuntu_facts }
it_behaves_like 'galera-init'
end
context 'Percona on CentOS' do
let(:facts) { Facts.centos_facts }
p = {
:use_percona => true,
:use_percona_packages => false
}
# we only test compile and packages because this configuration should
# result in a puppet error indicating no support
it_behaves_like 'compile', p
it_behaves_like 'test-packages', p
end
context 'Percona on Ubuntu' do
let(:facts) { Facts.ubuntu_facts }
p = {
:use_percona => true,
:use_percona_packages => false
}
it_behaves_like 'galera-init', p
# these are extra things that should be expected on Ubuntu to work around
# the package installation on Ubuntu
let(:params) { p }
it {
should contain_exec('rm-99tmp')
}
end
context 'Percona Packages on CentOS' do
let(:facts) { Facts.centos_facts }
p = {
:use_percona => true,
:use_percona_packages => true
}
it_behaves_like 'galera-init', p
end
context 'Percona Packages on Ubuntu' do
let(:facts) { Facts.ubuntu_facts }
p = {
:use_percona => true,
:use_percona_packages => true
}
it_behaves_like 'galera-init', p
# these are extra things that should be expected on Ubuntu to work around
# the package installation on Ubuntu
let(:params) { p }
it {
should contain_exec('rm-99tmp')
}
end
context 'Primary Controller on CentOS' do
let(:facts) { Facts.centos_facts }
p = { :primary_controller => true }
it_behaves_like 'galera-init', p
end
context 'Primary Controller on Ubuntu' do
let(:facts) { Facts.ubuntu_facts }
p = { :primary_controller => true }
it_behaves_like 'galera-init', p
end
context 'wsrep_sst_method mysqldump on CentOS' do
let(:facts) { Facts.centos_facts }
p = { :wsrep_sst_method => 'undef' }
it_behaves_like 'galera-init', p
end
context 'wsrep_sst_method mysqldump on Ubuntu' do
let(:facts) { Facts.ubuntu_facts }
p = { :wsrep_sst_method => 'mysqldump' }
it_behaves_like 'galera-init', p
end
end
# vim: set ts=2 sw=2 et :

View File

@ -1,17 +0,0 @@
# #[mysqld]
# #datadir=/var/lib/mysql
# #socket=/var/lib/mysql/mysql.sock
# #user=mysql
# # Disabling symbolic-links is recommended to prevent assorted security risks
# #symbolic-links=0
[mysqld_safe]
<% if @use_syslog -%>
syslog
<% else -%>
log-error=/var/log/mysqld.log
<% end -%>
# pid-file=/var/run/mysqld.pid
!includedir /etc/mysql/conf.d/

View File

@ -1,6 +0,0 @@
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 %>';
flush privileges;

View File

@ -1,77 +0,0 @@
[mysqld]
datadir=<%= @datadir %>
bind-address=<%= @node_address %>
port=3307
max_connections=<%= @max_connections %>
default-storage-engine=innodb
binlog_format=ROW
collation-server=utf8_general_ci
init-connect='SET NAMES utf8'
character-set-server=utf8
default-storage-engine=innodb
<% if @binary_logs_enabled -%>
log_bin=mysql-bin
expire_logs_days=<%= @binary_logs_period %>
max_binlog_size=<%= @binary_logs_maxsize %>
<% end -%>
skip-external-locking
<% if @skip_name_resolve -%>
skip-name-resolve
<% end -%>
<% if scope.lookupvar('memorysize_mb').to_i < 4000 -%>
performance_schema=off
<% 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 %>M
max_allowed_packet=256M
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_flush_method=<%= @innodb_flush_method %>
innodb_doublewrite=0
innodb_autoinc_lock_mode=2
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 -%>
wsrep_cluster_address="gcomm://<%= @node_addresses.first %>:<%= @gcomm_port.to_s %>?pc.wait_prim=no"
<% end -%>
wsrep_provider=<%= @libgalera_prefix %>/libgalera_smm.so
wsrep_cluster_name="<%= @cluster_name -%>"
wsrep_slave_threads=<%= [[@processorcount.to_i*2, 4].max, 12].min %>
wsrep_sst_method=<%= @wsrep_sst_method %>
<% if @wsrep_sst_auth -%>
wsrep_sst_auth=<%= @mysql_user %>:<%= @mysql_password %>
<% end -%>
wsrep_node_address=<%= @node_address %>
wsrep_provider_options="gcache.size = <%= [256, @gcache_factor.to_i*64, 2048].sort[1] %>M"
wsrep_provider_options="gmcast.listen_addr = tcp://<%= @node_address %>:<%= @gcomm_port.to_s %>"
<% if @wsrep_sst_method =~ /xtrabackup/ -%>
[xtrabackup]
parallel=<%= [[@processorcount.to_i, 2].max, 6].min %>
[sst]
streamfmt=xbstream
transferfmt=socat
sockopt=,nodelay,sndbuf=1048576,rcvbuf=1048576
<% end -%>

View File

@ -1,3 +0,0 @@
fixtures:
symlinks:
mysql: "#{source_dir}"

View File

@ -1,5 +0,0 @@
source :rubygems
puppetversion = ENV.key?('PUPPET_VERSION') ? "= #{ENV['PUPPET_VERSION']}" : ['>= 2.7']
gem 'puppet', puppetversion
gem 'puppetlabs_spec_helper', '>= 0.1.0'

View File

@ -1,5 +0,0 @@
*.swp
pkg/
.DS_Store
metadata.json
coverage/

View File

@ -1,24 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>mysql</name>
<comment></comment>
<projects>
<project>galera</project>
</projects>
<buildSpec>
<buildCommand>
<name>org.cloudsmith.geppetto.pp.dsl.ui.modulefileBuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>org.eclipse.xtext.ui.shared.xtextBuilder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>org.cloudsmith.geppetto.pp.dsl.ui.puppetNature</nature>
<nature>org.eclipse.xtext.ui.shared.xtextNature</nature>
</natures>
</projectDescription>

View File

@ -1,3 +0,0 @@
--format doc
--colour
--backtrace

View File

@ -1,17 +0,0 @@
language: ruby
rvm:
- 1.8.7
before_script:
- "[ '2.6.9' = $PUPPET_VERSION ] && git clone git://github.com/puppetlabs/puppetlabs-create_resources.git spec/fixtures/modules/create_resources || true"
after_script:
script: "rake spec"
branches:
only:
- master
env:
- PUPPET_VERSION=2.7.13
- PUPPET_VERSION=2.7.6
- PUPPET_VERSION=2.6.9
notifications:
email: false
gemfile: .gemfile

View File

@ -1,112 +0,0 @@
2012-05-03 - Version 0.3.0
* #14218 Query the database for available privileges
* Add mysql::java class for java connector installation
* Use correct error log location on different distros
* Fix set_mysql_rootpw to properly depend on my.cnf
2012-04-11 - Version 0.2.0
2012-03-19 - William Van Hevelingen <blkperl@cat.pdx.edu>
* (#13203) Add ssl support (f7e0ea5)
2012-03-18 - Nan Liu <nan@puppetlabs.com>
* Travis ci before script needs success exit code. (0ea463b)
2012-03-18 - Nan Liu <nan@puppetlabs.com>
* Fix Puppet 2.6 compilation issues. (9ebbbc4)
2012-03-16 - Nan Liu <nan@puppetlabs.com>
* Add travis.ci for testing multiple puppet versions. (33c72ef)
2012-03-15 - William Van Hevelingen <blkperl@cat.pdx.edu>
* (#13163) Datadir should be configurable (f353fc6)
2012-03-16 - Nan Liu <nan@puppetlabs.com>
* Document create_resources dependency. (558a59c)
2012-03-16 - Nan Liu <nan@puppetlabs.com>
* Fix spec test issues related to error message. (eff79b5)
2012-03-16 - Nan Liu <nan@puppetlabs.com>
* Fix mysql service on Ubuntu. (72da2c5)
2012-03-16 - Dan Bode <dan@puppetlabs.com>
* Add more spec test coverage (55e399d)
2012-03-16 - Nan Liu <nan@puppetlabs.com>
* (#11963) Fix spec test due to path changes. (1700349)
2012-03-07 - François Charlier <fcharlier@ploup.net>
* Add a test to check path for 'mysqld-restart' (b14c7d1)
2012-03-07 - François Charlier <fcharlier@ploup.net>
* Fix path for 'mysqld-restart' (1a9ae6b)
2012-03-15 - Dan Bode <dan@puppetlabs.com>
* Add rspec-puppet tests for mysql::config (907331a)
2012-03-15 - Dan Bode <dan@puppetlabs.com>
* Moved class dependency between sever and config to server (da62ad6)
2012-03-14 - Dan Bode <dan@puppetlabs.com>
* Notify mysql restart from set_mysql_rootpw exec (0832a2c)
2012-03-15 - Nan Liu <nan@puppetlabs.com>
* Add documentation related to osfamily fact. (8265d28)
2012-03-14 - Dan Bode <dan@puppetlabs.com>
* Mention osfamily value in failure message (e472d3b)
2012-03-14 - Dan Bode <dan@puppetlabs.com>
* Fix bug when querying for all database users (015490c)
2012-02-09 - Nan Liu <nan@puppetlabs.com>
* Major refactor of mysql module. (b1f90fd)
2012-01-11 - Justin Ellison <justin.ellison@buckle.com>
* Ruby and Python's MySQL libraries are named differently on different distros. (1e926b4)
2012-01-11 - Justin Ellison <justin.ellison@buckle.com>
* Per @ghoneycutt, we should fail explicitly and explain why. (09af083)
2012-01-11 - Justin Ellison <justin.ellison@buckle.com>
* Removing duplicate declaration (7513d03)
2012-01-10 - Justin Ellison <justin.ellison@buckle.com>
* Use socket value from params class instead of hardcoding. (663e97c)
2012-01-10 - Justin Ellison <justin.ellison@buckle.com>
* Instead of hardcoding the config file target, pull it from mysql::params (031a47d)
2012-01-10 - Justin Ellison <justin.ellison@buckle.com>
* Moved $socket to within the case to toggle between distros. Added a $config_file variable to allow per-distro config file destinations. (360eacd)
2012-01-10 - Justin Ellison <justin.ellison@buckle.com>
* Pretty sure this is a bug, 99% of Linux distros out there won't ever hit the default. (3462e6b)
2012-02-09 - William Van Hevelingen <blkperl@cat.pdx.edu>
* Changed the README to use markdown (3b7dfeb)
2012-02-04 - Daniel Black <grooverdan@users.sourceforge.net>
* (#12412) mysqltuner.pl update (b809e6f)
2011-11-17 - Matthias Pigulla <mp@webfactory.de>
* (#11363) Add two missing privileges to grant: event_priv, trigger_priv (d15c9d1)
2011-12-20 - Jeff McCune <jeff@puppetlabs.com>
* (minor) Fixup typos in Modulefile metadata (a0ed6a1)
2011-12-19 - Carl Caum <carl@carlcaum.com>
* Only notify Exec to import sql if sql is given (0783c74)
2011-12-19 - Carl Caum <carl@carlcaum.com>
* (#11508) Only load sql_scripts on DB creation (e3b9fd9)
2011-12-13 - Justin Ellison <justin.ellison@buckle.com>
* Require not needed due to implicit dependencies (3058feb)
2011-12-13 - Justin Ellison <justin.ellison@buckle.com>
* Bug #11375: puppetlabs-mysql fails on CentOS/RHEL (a557b8d)
2011-06-03 - Dan Bode <dan@puppetlabs.com> - 0.0.1
* initial commit

View File

@ -1,201 +0,0 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
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 required 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.

View File

@ -1,8 +0,0 @@
name 'puppetlabs-mysql'
version '0.3.0'
source 'git://github.com/puppetlabs/puppetlabs-mysql.git'
author 'Puppet Labs'
license 'Apache 2.0'
summary 'Mysql module'
description 'Mysql module'
project_page 'http://github.com/puppetlabs/puppetlabs-mysql'

View File

@ -1,124 +0,0 @@
# Mysql module for Puppet
This module manages mysql on Linux (RedHat/Debian) distros. A native mysql provider implements database resource type to handle database, database user, and database permission.
## Description
This module uses the fact osfamily which is supported by Facter 1.6.1+. If you do not have facter 1.6.1 in your environment, the following manifests will provide the same functionality in site.pp (before declaring any node):
if ! $::osfamily {
case $::operatingsystem {
'RedHat', 'Fedora', 'CentOS', 'Scientific', 'SLC', 'Ascendos', 'CloudLinux', 'PSBM', 'OracleLinux', 'OVS', 'OEL': {
$osfamily = 'RedHat'
}
'ubuntu', 'debian': {
$osfamily = 'Debian'
}
'SLES', 'SLED', 'OpenSuSE', 'SuSE': {
$osfamily = 'Suse'
}
'Solaris', 'Nexenta': {
$osfamily = 'Solaris'
}
default: {
$osfamily = $::operatingsystem
}
}
}
This module depends on creates_resources function which is introduced in Puppet 2.7. Users on puppet 2.6 can use the following module which provides this functionality:
[http://github.com/puppetlabs/puppetlabs-create_resources](http://github.com/puppetlabs/puppetlabs-create_resources)
This module is based on work by David Schmitt. The following contributor have contributed patches to this module (beyond Puppet Labs):
* Christian G. Warden
* Daniel Black
* Justin Ellison
* Lowe Schmidt
* Matthias Pigulla
* William Van Hevelingen
* Michael Arnold
## Usage
### mysql
Installs the mysql-client package.
class { 'mysql': }
### mysql::java
Installs mysql bindings for java.
class { 'mysql::java': }
### mysql::python
Installs mysql bindings for python.
class { 'mysql::python': }
### mysql::ruby
Installs mysql bindings for ruby.
class { 'mysql::ruby': }
### mysql::server
Installs mysql-server packages, configures my.cnf and starts mysqld service:
class { 'mysql::server':
config_hash => { 'root_password' => 'foo' }
}
Database login information stored in `/root/.my.cnf`.
### mysql::db
Creates a database with a user and assign some privileges.
mysql::db { 'mydb':
user => 'myuser',
password => 'mypass',
host => 'localhost',
grant => ['all'],
}
### mysql::backup
Installs a mysql backup script, cronjob, and priviledged backup user.
class { 'mysql::backup':
backupuser => 'myuser',
backuppassword => 'mypassword',
backupdir => '/tmp/backups',
}
### Providers for database types:
MySQL provider supports puppet resources command:
$ puppet resource database
database { 'information_schema':
ensure => 'present',
charset => 'utf8',
}
database { 'mysql':
ensure => 'present',
charset => 'latin1',
}
The custom resources can be used in any other manifests:
database { 'mydb':
charset => 'latin1',
}
database_user { 'bob@localhost':
password_hash => mysql_password('foo')
}
database_grant { 'user@localhost/database':
privileges => ['all'] ,
}
A resource default can be specified to handle dependency:
Database {
require => Class['mysql::server'],
}

View File

@ -1 +0,0 @@
require 'puppetlabs_spec_helper/rake_tasks'

View File

@ -1,8 +0,0 @@
The best that I can tell is that this code traces back to David Schmitt. It has been forked many times since then :)
1. you cannot add databases to an instance that has a root password
2. you have to specify username as USER@BLAH or it cannot be found
3. mysql_grant does not complain if user does not exist
4. Needs support for pre-seeding on debian
5. the types may need to take user/password
6. rather or not to configure /etc/.my.cnf should be configurable

View File

@ -1,25 +0,0 @@
$master_hostname = 'fuel-controller-01'
$primary_controller = $::hostname ? {
$master_hostname => true,
default => false,
}
$galera_node_addresses = ['fuel-controller-01', 'fuel-controller-02']
$galera_cluster_name = 'openstack'
$galera_master_ip = 'master_ip'
$custom_mysql_setup_class = 'galera'
$mysql_root_password = 'nova'
$enabled = true
node /fuel-controller-[\d+]/ {
class { 'mysql::server':
config_hash => {
'bind_address' => '0.0.0.0'
}
,
galera_cluster_name => $galera_cluster_name,
primary_controller => $primary_controller,
galera_node_address => $::hostname,
enabled => $enabled,
custom_setup_class => $custom_mysql_setup_class,
}
}

View File

@ -1,25 +0,0 @@
# Class: mysql::config
#
# Parameters:
#
# [*root_password*] - root user password.
# [*old_root_password*] - previous root user password,
# [*bind_address*] - address to bind service.
# [*port*] - port to bind service.
# [*etc_root_password*] - whether to save /etc/.my.cnf.
# [*service_name*] - mysql service name.
# [*config_file*] - my.cnf configuration file path.
# [*socket*] - mysql socket.
# [*datadir*] - path to datadir.
# [*ssl] - enable ssl
# [*ssl_ca] - path to ssl-ca
# [*ssl_cert] - path to ssl-cert
# [*ssl_key] - path to ssl-key
#
class {'mysql::server':
config_hash =>{
'root_password' => 'r00tme',
'bind_address' => '0.0.0.0'
},
}

View File

@ -1,251 +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
MYSQLDRUNNING=0
if [ -f "$mypidfile" ]; then
MYSQLPID=`cat "$mypidfile" 2>/dev/null`
if [ -n "$MYSQLPID" ] && [ -d "/proc/$MYSQLPID" ] ; then
MYSQLDRUNNING=1
fi
fi
RESPONSE=`/usr/bin/mysqladmin --socket="$socketfile" --user=UNKNOWN_MYSQL_USER ping 2>&1`
if [ $MYSQLDRUNNING = 1 ] && [ $? = 0 ]; then
# already running, do nothing
action $"Starting $prog: " /bin/true
ret=0
elif [ $MYSQLDRUNNING = 1 ] && 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" 2>/dev/null
if [ $? -ne 0 ]; then
# failed to touch log file, probably insufficient permissions
action $"Starting $prog: " /bin/false
return 4
fi
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 0750 "$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 0750 "$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
if [ -S "$socketfile" ] ; then
if pgrep mysqld_safe &> /dev/null; then
echo "Another MySQL daemon already running with the same unix socket."
action $"Starting $prog: " /bin/false
return 1
else
#MySQL isn't running. Kill the socket file
rm -f "$socketfile"
fi
fi
$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
chmod o+r $mypidfile >/dev/null 2>&1
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" 2>/dev/null`
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 -p "$mypidfile" $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 $?

View File

@ -1,966 +0,0 @@
#!/usr/bin/perl -w
# mysqltuner.pl - Version 1.2.0
# High Performance MySQL Tuning Script
# Copyright (C) 2006-2011 Major Hayden - major@mhtx.net
#
# For the latest updates, please visit http://mysqltuner.com/
# Git repository available at http://github.com/rackerhacker/MySQLTuner-perl
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
# This project would not be possible without help from:
# Matthew Montgomery Paul Kehrer Dave Burgess
# Jonathan Hinds Mike Jackson Nils Breunese
# Shawn Ashlee Luuk Vosslamber Ville Skytta
# Trent Hornibrook Jason Gill Mark Imbriaco
# Greg Eden Aubin Galinotti Giovanni Bechis
# Bill Bradford Ryan Novosielski Michael Scheidell
# Blair Christensen Hans du Plooy Victor Trac
# Everett Barnes Tom Krouper Gary Barrueto
# Simon Greenaway Adam Stein Isart Montane
# Baptiste M.
#
# Inspired by Matthew Montgomery's tuning-primer.sh script:
# http://forge.mysql.com/projects/view.php?id=44
#
use strict;
use warnings;
use diagnostics;
use File::Spec;
use Getopt::Long;
# Set up a few variables for use in the script
my $tunerversion = "1.2.0";
my (@adjvars, @generalrec);
# Set defaults
my %opt = (
"nobad" => 0,
"nogood" => 0,
"noinfo" => 0,
"nocolor" => 0,
"forcemem" => 0,
"forceswap" => 0,
"host" => 0,
"socket" => 0,
"port" => 0,
"user" => 0,
"pass" => 0,
"skipsize" => 0,
"checkversion" => 0,
);
# Gather the options from the command line
GetOptions(\%opt,
'nobad',
'nogood',
'noinfo',
'nocolor',
'forcemem=i',
'forceswap=i',
'host=s',
'socket=s',
'port=i',
'user=s',
'pass=s',
'skipsize',
'checkversion',
'help',
);
if (defined $opt{'help'} && $opt{'help'} == 1) { usage(); }
sub usage {
# Shown with --help option passed
print "\n".
" MySQLTuner $tunerversion - MySQL High Performance Tuning Script\n".
" Bug reports, feature requests, and downloads at http://mysqltuner.com/\n".
" Maintained by Major Hayden (major\@mhtx.net) - Licensed under GPL\n".
"\n".
" Important Usage Guidelines:\n".
" To run the script with the default options, run the script without arguments\n".
" Allow MySQL server to run for at least 24-48 hours before trusting suggestions\n".
" Some routines may require root level privileges (script will provide warnings)\n".
" You must provide the remote server's total memory when connecting to other servers\n".
"\n".
" Connection and Authentication\n".
" --host <hostname> Connect to a remote host to perform tests (default: localhost)\n".
" --socket <socket> Use a different socket for a local connection\n".
" --port <port> Port to use for connection (default: 3306)\n".
" --user <username> Username to use for authentication\n".
" --pass <password> Password to use for authentication\n".
"\n".
" Performance and Reporting Options\n".
" --skipsize Don't enumerate tables and their types/sizes (default: on)\n".
" (Recommended for servers with many tables)\n".
" --checkversion Check for updates to MySQLTuner (default: don't check)\n".
" --forcemem <size> Amount of RAM installed in megabytes\n".
" --forceswap <size> Amount of swap memory configured in megabytes\n".
"\n".
" Output Options:\n".
" --nogood Remove OK responses\n".
" --nobad Remove negative/suggestion responses\n".
" --noinfo Remove informational responses\n".
" --nocolor Don't print output in color\n".
"\n";
exit;
}
my $devnull = File::Spec->devnull();
# Setting up the colors for the print styles
my $good = ($opt{nocolor} == 0)? "[\e[0;32mOK\e[0m]" : "[OK]" ;
my $bad = ($opt{nocolor} == 0)? "[\e[0;31m!!\e[0m]" : "[!!]" ;
my $info = ($opt{nocolor} == 0)? "[\e[0;34m--\e[0m]" : "[--]" ;
# Functions that handle the print styles
sub goodprint { print $good." ".$_[0] unless ($opt{nogood} == 1); }
sub infoprint { print $info." ".$_[0] unless ($opt{noinfo} == 1); }
sub badprint { print $bad." ".$_[0] unless ($opt{nobad} == 1); }
sub redwrap { return ($opt{nocolor} == 0)? "\e[0;31m".$_[0]."\e[0m" : $_[0] ; }
sub greenwrap { return ($opt{nocolor} == 0)? "\e[0;32m".$_[0]."\e[0m" : $_[0] ; }
# Calculates the parameter passed in bytes, and then rounds it to one decimal place
sub hr_bytes {
my $num = shift;
if ($num >= (1024**3)) { #GB
return sprintf("%.1f",($num/(1024**3)))."G";
} elsif ($num >= (1024**2)) { #MB
return sprintf("%.1f",($num/(1024**2)))."M";
} elsif ($num >= 1024) { #KB
return sprintf("%.1f",($num/1024))."K";
} else {
return $num."B";
}
}
# Calculates the parameter passed in bytes, and then rounds it to the nearest integer
sub hr_bytes_rnd {
my $num = shift;
if ($num >= (1024**3)) { #GB
return int(($num/(1024**3)))."G";
} elsif ($num >= (1024**2)) { #MB
return int(($num/(1024**2)))."M";
} elsif ($num >= 1024) { #KB
return int(($num/1024))."K";
} else {
return $num."B";
}
}
# Calculates the parameter passed to the nearest power of 1000, then rounds it to the nearest integer
sub hr_num {
my $num = shift;
if ($num >= (1000**3)) { # Billions
return int(($num/(1000**3)))."B";
} elsif ($num >= (1000**2)) { # Millions
return int(($num/(1000**2)))."M";
} elsif ($num >= 1000) { # Thousands
return int(($num/1000))."K";
} else {
return $num;
}
}
# Calculates uptime to display in a more attractive form
sub pretty_uptime {
my $uptime = shift;
my $seconds = $uptime % 60;
my $minutes = int(($uptime % 3600) / 60);
my $hours = int(($uptime % 86400) / (3600));
my $days = int($uptime / (86400));
my $uptimestring;
if ($days > 0) {
$uptimestring = "${days}d ${hours}h ${minutes}m ${seconds}s";
} elsif ($hours > 0) {
$uptimestring = "${hours}h ${minutes}m ${seconds}s";
} elsif ($minutes > 0) {
$uptimestring = "${minutes}m ${seconds}s";
} else {
$uptimestring = "${seconds}s";
}
return $uptimestring;
}
# Retrieves the memory installed on this machine
my ($physical_memory,$swap_memory,$duflags);
sub os_setup {
sub memerror {
badprint "Unable to determine total memory/swap; use '--forcemem' and '--forceswap'\n";
exit;
}
my $os = `uname`;
$duflags = ($os =~ /Linux/) ? '-b' : '';
if ($opt{'forcemem'} > 0) {
$physical_memory = $opt{'forcemem'} * 1048576;
infoprint "Assuming $opt{'forcemem'} MB of physical memory\n";
if ($opt{'forceswap'} > 0) {
$swap_memory = $opt{'forceswap'} * 1048576;
infoprint "Assuming $opt{'forceswap'} MB of swap space\n";
} else {
$swap_memory = 0;
badprint "Assuming 0 MB of swap space (use --forceswap to specify)\n";
}
} else {
if ($os =~ /Linux/) {
$physical_memory = `free -b | grep Mem | awk '{print \$2}'` or memerror;
$swap_memory = `free -b | grep Swap | awk '{print \$2}'` or memerror;
} elsif ($os =~ /Darwin/) {
$physical_memory = `sysctl -n hw.memsize` or memerror;
$swap_memory = `sysctl -n vm.swapusage | awk '{print \$3}' | sed 's/\..*\$//'` or memerror;
} elsif ($os =~ /NetBSD|OpenBSD/) {
$physical_memory = `sysctl -n hw.physmem` or memerror;
if ($physical_memory < 0) {
$physical_memory = `sysctl -n hw.physmem64` or memerror;
}
$swap_memory = `swapctl -l | grep '^/' | awk '{ s+= \$2 } END { print s }'` or memerror;
} elsif ($os =~ /BSD/) {
$physical_memory = `sysctl -n hw.realmem`;
$swap_memory = `swapinfo | grep '^/' | awk '{ s+= \$2 } END { print s }'`;
} elsif ($os =~ /SunOS/) {
$physical_memory = `/usr/sbin/prtconf | grep Memory | cut -f 3 -d ' '` or memerror;
chomp($physical_memory);
$physical_memory = $physical_memory*1024*1024;
} elsif ($os =~ /AIX/) {
$physical_memory = `lsattr -El sys0 | grep realmem | awk '{print \$2}'` or memerror;
chomp($physical_memory);
$physical_memory = $physical_memory*1024;
$swap_memory = `lsps -as | awk -F"(MB| +)" '/MB /{print \$2}'` or memerror;
chomp($swap_memory);
$swap_memory = $swap_memory*1024*1024;
}
}
chomp($physical_memory);
}
# Checks to see if a MySQL login is possible
my ($mysqllogin,$doremote,$remotestring);
sub mysql_setup {
$doremote = 0;
$remotestring = '';
my $command = `which mysqladmin`;
chomp($command);
if (! -e $command) {
badprint "Unable to find mysqladmin in your \$PATH. Is MySQL installed?\n";
exit;
}
# Are we being asked to connect via a socket?
if ($opt{socket} ne 0) {
$remotestring = " -S $opt{socket}";
}
# Are we being asked to connect to a remote server?
if ($opt{host} ne 0) {
chomp($opt{host});
$opt{port} = ($opt{port} eq 0)? 3306 : $opt{port} ;
# If we're doing a remote connection, but forcemem wasn't specified, we need to exit
if ($opt{'forcemem'} eq 0) {
badprint "The --forcemem option is required for remote connections\n";
exit;
}
infoprint "Performing tests on $opt{host}:$opt{port}\n";
$remotestring = " -h $opt{host} -P $opt{port}";
$doremote = 1;
}
# Did we already get a username and password passed on the command line?
if ($opt{user} ne 0 and $opt{pass} ne 0) {
$mysqllogin = "-u $opt{user} -p'$opt{pass}'".$remotestring;
my $loginstatus = `mysqladmin ping $mysqllogin 2>&1`;
if ($loginstatus =~ /mysqld is alive/) {
goodprint "Logged in using credentials passed on the command line\n";
return 1;
} else {
badprint "Attempted to use login credentials, but they were invalid\n";
exit 0;
}
}
if ( -r "/etc/psa/.psa.shadow" and $doremote == 0 ) {
# It's a Plesk box, use the available credentials
$mysqllogin = "-u admin -p`cat /etc/psa/.psa.shadow`";
my $loginstatus = `mysqladmin ping $mysqllogin 2>&1`;
unless ($loginstatus =~ /mysqld is alive/) {
badprint "Attempted to use login credentials from Plesk, but they failed.\n";
exit 0;
}
} elsif ( -r "/etc/mysql/debian.cnf" and $doremote == 0 ){
# We have a debian maintenance account, use it
$mysqllogin = "--defaults-file=/etc/mysql/debian.cnf";
my $loginstatus = `mysqladmin $mysqllogin ping 2>&1`;
if ($loginstatus =~ /mysqld is alive/) {
goodprint "Logged in using credentials from debian maintenance account.\n";
return 1;
} else {
badprint "Attempted to use login credentials from debian maintenance account, but they failed.\n";
exit 0;
}
} else {
# It's not Plesk or debian, we should try a login
my $loginstatus = `mysqladmin $remotestring ping 2>&1`;
if ($loginstatus =~ /mysqld is alive/) {
# Login went just fine
$mysqllogin = " $remotestring ";
# Did this go well because of a .my.cnf file or is there no password set?
my $userpath = `printenv HOME`;
if (length($userpath) > 0) {
chomp($userpath);
}
unless ( -e "${userpath}/.my.cnf" ) {
badprint "Successfully authenticated with no password - SECURITY RISK!\n";
}
return 1;
} else {
print STDERR "Please enter your MySQL administrative login: ";
my $name = <>;
print STDERR "Please enter your MySQL administrative password: ";
system("stty -echo >$devnull 2>&1");
my $password = <>;
system("stty echo >$devnull 2>&1");
chomp($password);
chomp($name);
$mysqllogin = "-u $name";
if (length($password) > 0) {
$mysqllogin .= " -p'$password'";
}
$mysqllogin .= $remotestring;
my $loginstatus = `mysqladmin ping $mysqllogin 2>&1`;
if ($loginstatus =~ /mysqld is alive/) {
print STDERR "\n";
if (! length($password)) {
# Did this go well because of a .my.cnf file or is there no password set?
my $userpath = `ls -d ~`;
chomp($userpath);
unless ( -e "$userpath/.my.cnf" ) {
badprint "Successfully authenticated with no password - SECURITY RISK!\n";
}
}
return 1;
} else {
print "\n".$bad." Attempted to use login credentials, but they were invalid.\n";
exit 0;
}
exit 0;
}
}
}
# Populates all of the variable and status hashes
my (%mystat,%myvar,$dummyselect);
sub get_all_vars {
# We need to initiate at least one query so that our data is useable
$dummyselect = `mysql $mysqllogin -Bse "SELECT VERSION();"`;
my @mysqlvarlist = `mysql $mysqllogin -Bse "SHOW /*!50000 GLOBAL */ VARIABLES;"`;
foreach my $line (@mysqlvarlist) {
$line =~ /([a-zA-Z_]*)\s*(.*)/;
$myvar{$1} = $2;
}
my @mysqlstatlist = `mysql $mysqllogin -Bse "SHOW /*!50000 GLOBAL */ STATUS;"`;
foreach my $line (@mysqlstatlist) {
$line =~ /([a-zA-Z_]*)\s*(.*)/;
$mystat{$1} = $2;
}
# Workaround for MySQL bug #59393 wrt. ignore-builtin-innodb
if (($myvar{'ignore_builtin_innodb'} || "") eq "ON") {
$myvar{'have_innodb'} = "NO";
}
# have_* for engines is deprecated and will be removed in MySQL 5.6;
# check SHOW ENGINES and set corresponding old style variables.
# Also works around MySQL bug #59393 wrt. skip-innodb
my @mysqlenginelist = `mysql $mysqllogin -Bse "SHOW ENGINES;" 2>$devnull`;
foreach my $line (@mysqlenginelist) {
if ($line =~ /^([a-zA-Z_]+)\s+(\S+)/) {
my $engine = lc($1);
if ($engine eq "federated" || $engine eq "blackhole") {
$engine .= "_engine";
} elsif ($engine eq "berkeleydb") {
$engine = "bdb";
}
my $val = ($2 eq "DEFAULT") ? "YES" : $2;
$myvar{"have_$engine"} = $val;
}
}
}
sub security_recommendations {
print "\n-------- Security Recommendations -------------------------------------------\n";
my @mysqlstatlist = `mysql $mysqllogin -Bse "SELECT CONCAT(user, '\@', host) FROM mysql.user WHERE password = '' OR password IS NULL;"`;
if (@mysqlstatlist) {
foreach my $line (sort @mysqlstatlist) {
chomp($line);
badprint "User '".$line."' has no password set.\n";
}
} else {
goodprint "All database users have passwords assigned\n";
}
}
sub get_replication_status {
my $slave_status = `mysql $mysqllogin -Bse "show slave status\\G"`;
my ($io_running) = ($slave_status =~ /slave_io_running\S*\s+(\S+)/i);
my ($sql_running) = ($slave_status =~ /slave_sql_running\S*\s+(\S+)/i);
if ($io_running eq 'Yes' && $sql_running eq 'Yes') {
if ($myvar{'read_only'} eq 'OFF') {
badprint "This replication slave is running with the read_only option disabled.";
} else {
goodprint "This replication slave is running with the read_only option enabled.";
}
}
}
# Checks for updates to MySQLTuner
sub validate_tuner_version {
print "\n-------- General Statistics --------------------------------------------------\n";
if ($opt{checkversion} eq 0) {
infoprint "Skipped version check for MySQLTuner script\n";
return;
}
my $update;
my $url = "http://mysqltuner.com/versioncheck.php?v=$tunerversion";
if (-e "/usr/bin/curl") {
$update = `/usr/bin/curl --connect-timeout 5 '$url' 2>$devnull`;
chomp($update);
} elsif (-e "/usr/bin/wget") {
$update = `/usr/bin/wget -e timestamping=off -T 5 -O - '$url' 2>$devnull`;
chomp($update);
}
if ($update eq 1) {
badprint "There is a new version of MySQLTuner available\n";
} elsif ($update eq 0) {
goodprint "You have the latest version of MySQLTuner\n";
} else {
infoprint "Unable to check for the latest MySQLTuner version\n";
}
}
# Checks for supported or EOL'ed MySQL versions
my ($mysqlvermajor,$mysqlverminor);
sub validate_mysql_version {
($mysqlvermajor,$mysqlverminor) = $myvar{'version'} =~ /(\d)\.(\d)/;
if (!mysql_version_ge(5)) {
badprint "Your MySQL version ".$myvar{'version'}." is EOL software! Upgrade soon!\n";
} elsif (mysql_version_ge(6)) {
badprint "Currently running unsupported MySQL version ".$myvar{'version'}."\n";
} else {
goodprint "Currently running supported MySQL version ".$myvar{'version'}."\n";
}
}
# Checks if MySQL version is greater than equal to (major, minor)
sub mysql_version_ge {
my ($maj, $min) = @_;
return $mysqlvermajor > $maj || ($mysqlvermajor == $maj && $mysqlverminor >= ($min || 0));
}
# Checks for 32-bit boxes with more than 2GB of RAM
my ($arch);
sub check_architecture {
if ($doremote eq 1) { return; }
if (`uname` =~ /SunOS/ && `isainfo -b` =~ /64/) {
$arch = 64;
goodprint "Operating on 64-bit architecture\n";
} elsif (`uname` !~ /SunOS/ && `uname -m` =~ /64/) {
$arch = 64;
goodprint "Operating on 64-bit architecture\n";
} elsif (`uname` =~ /AIX/ && `bootinfo -K` =~ /64/) {
$arch = 64;
goodprint "Operating on 64-bit architecture\n";
} else {
$arch = 32;
if ($physical_memory > 2147483648) {
badprint "Switch to 64-bit OS - MySQL cannot currently use all of your RAM\n";
} else {
goodprint "Operating on 32-bit architecture with less than 2GB RAM\n";
}
}
}
# Start up a ton of storage engine counts/statistics
my (%enginestats,%enginecount,$fragtables);
sub check_storage_engines {
if ($opt{skipsize} eq 1) {
print "\n-------- Storage Engine Statistics -------------------------------------------\n";
infoprint "Skipped due to --skipsize option\n";
return;
}
print "\n-------- Storage Engine Statistics -------------------------------------------\n";
infoprint "Status: ";
my $engines;
$engines .= (defined $myvar{'have_archive'} && $myvar{'have_archive'} eq "YES")? greenwrap "+Archive " : redwrap "-Archive " ;
$engines .= (defined $myvar{'have_bdb'} && $myvar{'have_bdb'} eq "YES")? greenwrap "+BDB " : redwrap "-BDB " ;
$engines .= (defined $myvar{'have_federated_engine'} && $myvar{'have_federated_engine'} eq "YES")? greenwrap "+Federated " : redwrap "-Federated " ;
$engines .= (defined $myvar{'have_innodb'} && $myvar{'have_innodb'} eq "YES")? greenwrap "+InnoDB " : redwrap "-InnoDB " ;
$engines .= (defined $myvar{'have_isam'} && $myvar{'have_isam'} eq "YES")? greenwrap "+ISAM " : redwrap "-ISAM " ;
$engines .= (defined $myvar{'have_ndbcluster'} && $myvar{'have_ndbcluster'} eq "YES")? greenwrap "+NDBCluster " : redwrap "-NDBCluster " ;
print "$engines\n";
if (mysql_version_ge(5)) {
# MySQL 5 servers can have table sizes calculated quickly from information schema
my @templist = `mysql $mysqllogin -Bse "SELECT ENGINE,SUM(DATA_LENGTH),COUNT(ENGINE) FROM information_schema.TABLES WHERE TABLE_SCHEMA NOT IN ('information_schema','mysql') AND ENGINE IS NOT NULL GROUP BY ENGINE ORDER BY ENGINE ASC;"`;
foreach my $line (@templist) {
my ($engine,$size,$count);
($engine,$size,$count) = $line =~ /([a-zA-Z_]*)\s+(\d+)\s+(\d+)/;
if (!defined($size)) { next; }
$enginestats{$engine} = $size;
$enginecount{$engine} = $count;
}
$fragtables = `mysql $mysqllogin -Bse "SELECT COUNT(TABLE_NAME) FROM information_schema.TABLES WHERE TABLE_SCHEMA NOT IN ('information_schema','mysql') AND Data_free > 0 AND NOT ENGINE='MEMORY';"`;
chomp($fragtables);
} else {
# MySQL < 5 servers take a lot of work to get table sizes
my @tblist;
# Now we build a database list, and loop through it to get storage engine stats for tables
my @dblist = `mysql $mysqllogin -Bse "SHOW DATABASES"`;
foreach my $db (@dblist) {
chomp($db);
if ($db eq "information_schema") { next; }
my @ixs = (1, 6, 9);
if (!mysql_version_ge(4, 1)) {
# MySQL 3.23/4.0 keeps Data_Length in the 5th (0-based) column
@ixs = (1, 5, 8);
}
push(@tblist, map { [ (split)[@ixs] ] } `mysql $mysqllogin -Bse "SHOW TABLE STATUS FROM \\\`$db\\\`"`);
}
# Parse through the table list to generate storage engine counts/statistics
$fragtables = 0;
foreach my $tbl (@tblist) {
my ($engine, $size, $datafree) = @$tbl;
if (defined $enginestats{$engine}) {
$enginestats{$engine} += $size;
$enginecount{$engine} += 1;
} else {
$enginestats{$engine} = $size;
$enginecount{$engine} = 1;
}
if ($datafree > 0) {
$fragtables++;
}
}
}
while (my ($engine,$size) = each(%enginestats)) {
infoprint "Data in $engine tables: ".hr_bytes_rnd($size)." (Tables: ".$enginecount{$engine}.")"."\n";
}
# If the storage engine isn't being used, recommend it to be disabled
if (!defined $enginestats{'InnoDB'} && defined $myvar{'have_innodb'} && $myvar{'have_innodb'} eq "YES") {
badprint "InnoDB is enabled but isn't being used\n";
push(@generalrec,"Add skip-innodb to MySQL configuration to disable InnoDB");
}
if (!defined $enginestats{'BerkeleyDB'} && defined $myvar{'have_bdb'} && $myvar{'have_bdb'} eq "YES") {
badprint "BDB is enabled but isn't being used\n";
push(@generalrec,"Add skip-bdb to MySQL configuration to disable BDB");
}
if (!defined $enginestats{'ISAM'} && defined $myvar{'have_isam'} && $myvar{'have_isam'} eq "YES") {
badprint "ISAM is enabled but isn't being used\n";
push(@generalrec,"Add skip-isam to MySQL configuration to disable ISAM (MySQL > 4.1.0)");
}
# Fragmented tables
if ($fragtables > 0) {
badprint "Total fragmented tables: $fragtables\n";
push(@generalrec,"Run OPTIMIZE TABLE to defragment tables for better performance");
} else {
goodprint "Total fragmented tables: $fragtables\n";
}
}
my %mycalc;
sub calculations {
if ($mystat{'Questions'} < 1) {
badprint "Your server has not answered any queries - cannot continue...";
exit 0;
}
# Per-thread memory
if (mysql_version_ge(4)) {
$mycalc{'per_thread_buffers'} = $myvar{'read_buffer_size'} + $myvar{'read_rnd_buffer_size'} + $myvar{'sort_buffer_size'} + $myvar{'thread_stack'} + $myvar{'join_buffer_size'};
} else {
$mycalc{'per_thread_buffers'} = $myvar{'record_buffer'} + $myvar{'record_rnd_buffer'} + $myvar{'sort_buffer'} + $myvar{'thread_stack'} + $myvar{'join_buffer_size'};
}
$mycalc{'total_per_thread_buffers'} = $mycalc{'per_thread_buffers'} * $myvar{'max_connections'};
$mycalc{'max_total_per_thread_buffers'} = $mycalc{'per_thread_buffers'} * $mystat{'Max_used_connections'};
# Server-wide memory
$mycalc{'max_tmp_table_size'} = ($myvar{'tmp_table_size'} > $myvar{'max_heap_table_size'}) ? $myvar{'max_heap_table_size'} : $myvar{'tmp_table_size'} ;
$mycalc{'server_buffers'} = $myvar{'key_buffer_size'} + $mycalc{'max_tmp_table_size'};
$mycalc{'server_buffers'} += (defined $myvar{'innodb_buffer_pool_size'}) ? $myvar{'innodb_buffer_pool_size'} : 0 ;
$mycalc{'server_buffers'} += (defined $myvar{'innodb_additional_mem_pool_size'}) ? $myvar{'innodb_additional_mem_pool_size'} : 0 ;
$mycalc{'server_buffers'} += (defined $myvar{'innodb_log_buffer_size'}) ? $myvar{'innodb_log_buffer_size'} : 0 ;
$mycalc{'server_buffers'} += (defined $myvar{'query_cache_size'}) ? $myvar{'query_cache_size'} : 0 ;
# Global memory
$mycalc{'max_used_memory'} = $mycalc{'server_buffers'} + $mycalc{"max_total_per_thread_buffers"};
$mycalc{'total_possible_used_memory'} = $mycalc{'server_buffers'} + $mycalc{'total_per_thread_buffers'};
$mycalc{'pct_physical_memory'} = int(($mycalc{'total_possible_used_memory'} * 100) / $physical_memory);
# Slow queries
$mycalc{'pct_slow_queries'} = int(($mystat{'Slow_queries'}/$mystat{'Questions'}) * 100);
# Connections
$mycalc{'pct_connections_used'} = int(($mystat{'Max_used_connections'}/$myvar{'max_connections'}) * 100);
$mycalc{'pct_connections_used'} = ($mycalc{'pct_connections_used'} > 100) ? 100 : $mycalc{'pct_connections_used'} ;
# Key buffers
if (mysql_version_ge(4, 1)) {
$mycalc{'pct_key_buffer_used'} = sprintf("%.1f",(1 - (($mystat{'Key_blocks_unused'} * $myvar{'key_cache_block_size'}) / $myvar{'key_buffer_size'})) * 100);
}
if ($mystat{'Key_read_requests'} > 0) {
$mycalc{'pct_keys_from_mem'} = sprintf("%.1f",(100 - (($mystat{'Key_reads'} / $mystat{'Key_read_requests'}) * 100)));
} else {
$mycalc{'pct_keys_from_mem'} = 0;
}
if ($doremote eq 0 and !mysql_version_ge(5)) {
my $size = 0;
$size += (split)[0] for `find $myvar{'datadir'} -name "*.MYI" 2>&1 | xargs du -L $duflags 2>&1`;
$mycalc{'total_myisam_indexes'} = $size;
} elsif (mysql_version_ge(5)) {
$mycalc{'total_myisam_indexes'} = `mysql $mysqllogin -Bse "SELECT IFNULL(SUM(INDEX_LENGTH),0) FROM information_schema.TABLES WHERE TABLE_SCHEMA NOT IN ('information_schema') AND ENGINE = 'MyISAM';"`;
}
if (defined $mycalc{'total_myisam_indexes'} and $mycalc{'total_myisam_indexes'} == 0) {
$mycalc{'total_myisam_indexes'} = "fail";
} elsif (defined $mycalc{'total_myisam_indexes'}) {
chomp($mycalc{'total_myisam_indexes'});
}
# Query cache
if (mysql_version_ge(4)) {
$mycalc{'query_cache_efficiency'} = sprintf("%.1f",($mystat{'Qcache_hits'} / ($mystat{'Com_select'} + $mystat{'Qcache_hits'})) * 100);
if ($myvar{'query_cache_size'}) {
$mycalc{'pct_query_cache_used'} = sprintf("%.1f",100 - ($mystat{'Qcache_free_memory'} / $myvar{'query_cache_size'}) * 100);
}
if ($mystat{'Qcache_lowmem_prunes'} == 0) {
$mycalc{'query_cache_prunes_per_day'} = 0;
} else {
$mycalc{'query_cache_prunes_per_day'} = int($mystat{'Qcache_lowmem_prunes'} / ($mystat{'Uptime'}/86400));
}
}
# Sorting
$mycalc{'total_sorts'} = $mystat{'Sort_scan'} + $mystat{'Sort_range'};
if ($mycalc{'total_sorts'} > 0) {
$mycalc{'pct_temp_sort_table'} = int(($mystat{'Sort_merge_passes'} / $mycalc{'total_sorts'}) * 100);
}
# Joins
$mycalc{'joins_without_indexes'} = $mystat{'Select_range_check'} + $mystat{'Select_full_join'};
$mycalc{'joins_without_indexes_per_day'} = int($mycalc{'joins_without_indexes'} / ($mystat{'Uptime'}/86400));
# Temporary tables
if ($mystat{'Created_tmp_tables'} > 0) {
if ($mystat{'Created_tmp_disk_tables'} > 0) {
$mycalc{'pct_temp_disk'} = int(($mystat{'Created_tmp_disk_tables'} / ($mystat{'Created_tmp_tables'} + $mystat{'Created_tmp_disk_tables'})) * 100);
} else {
$mycalc{'pct_temp_disk'} = 0;
}
}
# Table cache
if ($mystat{'Opened_tables'} > 0) {
$mycalc{'table_cache_hit_rate'} = int($mystat{'Open_tables'}*100/$mystat{'Opened_tables'});
} else {
$mycalc{'table_cache_hit_rate'} = 100;
}
# Open files
if ($myvar{'open_files_limit'} > 0) {
$mycalc{'pct_files_open'} = int($mystat{'Open_files'}*100/$myvar{'open_files_limit'});
}
# Table locks
if ($mystat{'Table_locks_immediate'} > 0) {
if ($mystat{'Table_locks_waited'} == 0) {
$mycalc{'pct_table_locks_immediate'} = 100;
} else {
$mycalc{'pct_table_locks_immediate'} = int($mystat{'Table_locks_immediate'}*100/($mystat{'Table_locks_waited'} + $mystat{'Table_locks_immediate'}));
}
}
# Thread cache
$mycalc{'thread_cache_hit_rate'} = int(100 - (($mystat{'Threads_created'} / $mystat{'Connections'}) * 100));
# Other
if ($mystat{'Connections'} > 0) {
$mycalc{'pct_aborted_connections'} = int(($mystat{'Aborted_connects'}/$mystat{'Connections'}) * 100);
}
if ($mystat{'Questions'} > 0) {
$mycalc{'total_reads'} = $mystat{'Com_select'};
$mycalc{'total_writes'} = $mystat{'Com_delete'} + $mystat{'Com_insert'} + $mystat{'Com_update'} + $mystat{'Com_replace'};
if ($mycalc{'total_reads'} == 0) {
$mycalc{'pct_reads'} = 0;
$mycalc{'pct_writes'} = 100;
} else {
$mycalc{'pct_reads'} = int(($mycalc{'total_reads'}/($mycalc{'total_reads'}+$mycalc{'total_writes'})) * 100);
$mycalc{'pct_writes'} = 100-$mycalc{'pct_reads'};
}
}
# InnoDB
if ($myvar{'have_innodb'} eq "YES") {
$mycalc{'innodb_log_size_pct'} = ($myvar{'innodb_log_file_size'} * 100 / $myvar{'innodb_buffer_pool_size'});
}
}
sub mysql_stats {
print "\n-------- Performance Metrics -------------------------------------------------\n";
# Show uptime, queries per second, connections, traffic stats
my $qps;
if ($mystat{'Uptime'} > 0) { $qps = sprintf("%.3f",$mystat{'Questions'}/$mystat{'Uptime'}); }
if ($mystat{'Uptime'} < 86400) { push(@generalrec,"MySQL started within last 24 hours - recommendations may be inaccurate"); }
infoprint "Up for: ".pretty_uptime($mystat{'Uptime'})." (".hr_num($mystat{'Questions'}).
" q [".hr_num($qps)." qps], ".hr_num($mystat{'Connections'})." conn,".
" TX: ".hr_num($mystat{'Bytes_sent'}).", RX: ".hr_num($mystat{'Bytes_received'}).")\n";
infoprint "Reads / Writes: ".$mycalc{'pct_reads'}."% / ".$mycalc{'pct_writes'}."%\n";
# Memory usage
infoprint "Total buffers: ".hr_bytes($mycalc{'server_buffers'})." global + ".hr_bytes($mycalc{'per_thread_buffers'})." per thread ($myvar{'max_connections'} max threads)\n";
if ($mycalc{'total_possible_used_memory'} > 2*1024*1024*1024 && $arch eq 32) {
badprint "Allocating > 2GB RAM on 32-bit systems can cause system instability\n";
badprint "Maximum possible memory usage: ".hr_bytes($mycalc{'total_possible_used_memory'})." ($mycalc{'pct_physical_memory'}% of installed RAM)\n";
} elsif ($mycalc{'pct_physical_memory'} > 85) {
badprint "Maximum possible memory usage: ".hr_bytes($mycalc{'total_possible_used_memory'})." ($mycalc{'pct_physical_memory'}% of installed RAM)\n";
push(@generalrec,"Reduce your overall MySQL memory footprint for system stability");
} else {
goodprint "Maximum possible memory usage: ".hr_bytes($mycalc{'total_possible_used_memory'})." ($mycalc{'pct_physical_memory'}% of installed RAM)\n";
}
# Slow queries
if ($mycalc{'pct_slow_queries'} > 5) {
badprint "Slow queries: $mycalc{'pct_slow_queries'}% (".hr_num($mystat{'Slow_queries'})."/".hr_num($mystat{'Questions'}).")\n";
} else {
goodprint "Slow queries: $mycalc{'pct_slow_queries'}% (".hr_num($mystat{'Slow_queries'})."/".hr_num($mystat{'Questions'}).")\n";
}
if ($myvar{'long_query_time'} > 10) { push(@adjvars,"long_query_time (<= 10)"); }
if (defined($myvar{'log_slow_queries'})) {
if ($myvar{'log_slow_queries'} eq "OFF") { push(@generalrec,"Enable the slow query log to troubleshoot bad queries"); }
}
# Connections
if ($mycalc{'pct_connections_used'} > 85) {
badprint "Highest connection usage: $mycalc{'pct_connections_used'}% ($mystat{'Max_used_connections'}/$myvar{'max_connections'})\n";
push(@adjvars,"max_connections (> ".$myvar{'max_connections'}.")");
push(@adjvars,"wait_timeout (< ".$myvar{'wait_timeout'}.")","interactive_timeout (< ".$myvar{'interactive_timeout'}.")");
push(@generalrec,"Reduce or eliminate persistent connections to reduce connection usage")
} else {
goodprint "Highest usage of available connections: $mycalc{'pct_connections_used'}% ($mystat{'Max_used_connections'}/$myvar{'max_connections'})\n";
}
# Key buffer
if (!defined($mycalc{'total_myisam_indexes'}) and $doremote == 1) {
push(@generalrec,"Unable to calculate MyISAM indexes on remote MySQL server < 5.0.0");
} elsif ($mycalc{'total_myisam_indexes'} =~ /^fail$/) {
badprint "Cannot calculate MyISAM index size - re-run script as root user\n";
} elsif ($mycalc{'total_myisam_indexes'} == "0") {
badprint "None of your MyISAM tables are indexed - add indexes immediately\n";
} else {
if ($myvar{'key_buffer_size'} < $mycalc{'total_myisam_indexes'} && $mycalc{'pct_keys_from_mem'} < 95) {
badprint "Key buffer size / total MyISAM indexes: ".hr_bytes($myvar{'key_buffer_size'})."/".hr_bytes($mycalc{'total_myisam_indexes'})."\n";
push(@adjvars,"key_buffer_size (> ".hr_bytes($mycalc{'total_myisam_indexes'}).")");
} else {
goodprint "Key buffer size / total MyISAM indexes: ".hr_bytes($myvar{'key_buffer_size'})."/".hr_bytes($mycalc{'total_myisam_indexes'})."\n";
}
if ($mystat{'Key_read_requests'} > 0) {
if ($mycalc{'pct_keys_from_mem'} < 95) {
badprint "Key buffer hit rate: $mycalc{'pct_keys_from_mem'}% (".hr_num($mystat{'Key_read_requests'})." cached / ".hr_num($mystat{'Key_reads'})." reads)\n";
} else {
goodprint "Key buffer hit rate: $mycalc{'pct_keys_from_mem'}% (".hr_num($mystat{'Key_read_requests'})." cached / ".hr_num($mystat{'Key_reads'})." reads)\n";
}
} else {
# No queries have run that would use keys
}
}
# Query cache
if (!mysql_version_ge(4)) {
# MySQL versions < 4.01 don't support query caching
push(@generalrec,"Upgrade MySQL to version 4+ to utilize query caching");
} elsif ($myvar{'query_cache_size'} < 1) {
badprint "Query cache is disabled\n";
push(@adjvars,"query_cache_size (>= 8M)");
} elsif ($mystat{'Com_select'} == 0) {
badprint "Query cache cannot be analyzed - no SELECT statements executed\n";
} else {
if ($mycalc{'query_cache_efficiency'} < 20) {
badprint "Query cache efficiency: $mycalc{'query_cache_efficiency'}% (".hr_num($mystat{'Qcache_hits'})." cached / ".hr_num($mystat{'Qcache_hits'}+$mystat{'Com_select'})." selects)\n";
push(@adjvars,"query_cache_limit (> ".hr_bytes_rnd($myvar{'query_cache_limit'}).", or use smaller result sets)");
} else {
goodprint "Query cache efficiency: $mycalc{'query_cache_efficiency'}% (".hr_num($mystat{'Qcache_hits'})." cached / ".hr_num($mystat{'Qcache_hits'}+$mystat{'Com_select'})." selects)\n";
}
if ($mycalc{'query_cache_prunes_per_day'} > 98) {
badprint "Query cache prunes per day: $mycalc{'query_cache_prunes_per_day'}\n";
if ($myvar{'query_cache_size'} > 128*1024*1024) {
push(@generalrec,"Increasing the query_cache size over 128M may reduce performance");
push(@adjvars,"query_cache_size (> ".hr_bytes_rnd($myvar{'query_cache_size'}).") [see warning above]");
} else {
push(@adjvars,"query_cache_size (> ".hr_bytes_rnd($myvar{'query_cache_size'}).")");
}
} else {
goodprint "Query cache prunes per day: $mycalc{'query_cache_prunes_per_day'}\n";
}
}
# Sorting
if ($mycalc{'total_sorts'} == 0) {
# For the sake of space, we will be quiet here
# No sorts have run yet
} elsif ($mycalc{'pct_temp_sort_table'} > 10) {
badprint "Sorts requiring temporary tables: $mycalc{'pct_temp_sort_table'}% (".hr_num($mystat{'Sort_merge_passes'})." temp sorts / ".hr_num($mycalc{'total_sorts'})." sorts)\n";
push(@adjvars,"sort_buffer_size (> ".hr_bytes_rnd($myvar{'sort_buffer_size'}).")");
push(@adjvars,"read_rnd_buffer_size (> ".hr_bytes_rnd($myvar{'read_rnd_buffer_size'}).")");
} else {
goodprint "Sorts requiring temporary tables: $mycalc{'pct_temp_sort_table'}% (".hr_num($mystat{'Sort_merge_passes'})." temp sorts / ".hr_num($mycalc{'total_sorts'})." sorts)\n";
}
# Joins
if ($mycalc{'joins_without_indexes_per_day'} > 250) {
badprint "Joins performed without indexes: $mycalc{'joins_without_indexes'}\n";
push(@adjvars,"join_buffer_size (> ".hr_bytes($myvar{'join_buffer_size'}).", or always use indexes with joins)");
push(@generalrec,"Adjust your join queries to always utilize indexes");
} else {
# For the sake of space, we will be quiet here
# No joins have run without indexes
}
# Temporary tables
if ($mystat{'Created_tmp_tables'} > 0) {
if ($mycalc{'pct_temp_disk'} > 25 && $mycalc{'max_tmp_table_size'} < 256*1024*1024) {
badprint "Temporary tables created on disk: $mycalc{'pct_temp_disk'}% (".hr_num($mystat{'Created_tmp_disk_tables'})." on disk / ".hr_num($mystat{'Created_tmp_disk_tables'} + $mystat{'Created_tmp_tables'})." total)\n";
push(@adjvars,"tmp_table_size (> ".hr_bytes_rnd($myvar{'tmp_table_size'}).")");
push(@adjvars,"max_heap_table_size (> ".hr_bytes_rnd($myvar{'max_heap_table_size'}).")");
push(@generalrec,"When making adjustments, make tmp_table_size/max_heap_table_size equal");
push(@generalrec,"Reduce your SELECT DISTINCT queries without LIMIT clauses");
} elsif ($mycalc{'pct_temp_disk'} > 25 && $mycalc{'max_tmp_table_size'} >= 256) {
badprint "Temporary tables created on disk: $mycalc{'pct_temp_disk'}% (".hr_num($mystat{'Created_tmp_disk_tables'})." on disk / ".hr_num($mystat{'Created_tmp_disk_tables'} + $mystat{'Created_tmp_tables'})." total)\n";
push(@generalrec,"Temporary table size is already large - reduce result set size");
push(@generalrec,"Reduce your SELECT DISTINCT queries without LIMIT clauses");
} else {
goodprint "Temporary tables created on disk: $mycalc{'pct_temp_disk'}% (".hr_num($mystat{'Created_tmp_disk_tables'})." on disk / ".hr_num($mystat{'Created_tmp_disk_tables'} + $mystat{'Created_tmp_tables'})." total)\n";
}
} else {
# For the sake of space, we will be quiet here
# No temporary tables have been created
}
# Thread cache
if ($myvar{'thread_cache_size'} eq 0) {
badprint "Thread cache is disabled\n";
push(@generalrec,"Set thread_cache_size to 4 as a starting value");
push(@adjvars,"thread_cache_size (start at 4)");
} else {
if ($mycalc{'thread_cache_hit_rate'} <= 50) {
badprint "Thread cache hit rate: $mycalc{'thread_cache_hit_rate'}% (".hr_num($mystat{'Threads_created'})." created / ".hr_num($mystat{'Connections'})." connections)\n";
push(@adjvars,"thread_cache_size (> $myvar{'thread_cache_size'})");
} else {
goodprint "Thread cache hit rate: $mycalc{'thread_cache_hit_rate'}% (".hr_num($mystat{'Threads_created'})." created / ".hr_num($mystat{'Connections'})." connections)\n";
}
}
# Table cache
if ($mystat{'Open_tables'} > 0) {
if ($mycalc{'table_cache_hit_rate'} < 20) {
badprint "Table cache hit rate: $mycalc{'table_cache_hit_rate'}% (".hr_num($mystat{'Open_tables'})." open / ".hr_num($mystat{'Opened_tables'})." opened)\n";
if (mysql_version_ge(5, 1)) {
push(@adjvars,"table_cache (> ".$myvar{'table_open_cache'}.")");
} else {
push(@adjvars,"table_cache (> ".$myvar{'table_cache'}.")");
}
push(@generalrec,"Increase table_cache gradually to avoid file descriptor limits");
} else {
goodprint "Table cache hit rate: $mycalc{'table_cache_hit_rate'}% (".hr_num($mystat{'Open_tables'})." open / ".hr_num($mystat{'Opened_tables'})." opened)\n";
}
}
# Open files
if (defined $mycalc{'pct_files_open'}) {
if ($mycalc{'pct_files_open'} > 85) {
badprint "Open file limit used: $mycalc{'pct_files_open'}% (".hr_num($mystat{'Open_files'})."/".hr_num($myvar{'open_files_limit'}).")\n";
push(@adjvars,"open_files_limit (> ".$myvar{'open_files_limit'}.")");
} else {
goodprint "Open file limit used: $mycalc{'pct_files_open'}% (".hr_num($mystat{'Open_files'})."/".hr_num($myvar{'open_files_limit'}).")\n";
}
}
# Table locks
if (defined $mycalc{'pct_table_locks_immediate'}) {
if ($mycalc{'pct_table_locks_immediate'} < 95) {
badprint "Table locks acquired immediately: $mycalc{'pct_table_locks_immediate'}%\n";
push(@generalrec,"Optimize queries and/or use InnoDB to reduce lock wait");
} else {
goodprint "Table locks acquired immediately: $mycalc{'pct_table_locks_immediate'}% (".hr_num($mystat{'Table_locks_immediate'})." immediate / ".hr_num($mystat{'Table_locks_waited'}+$mystat{'Table_locks_immediate'})." locks)\n";
}
}
# Performance options
if (!mysql_version_ge(4, 1)) {
push(@generalrec,"Upgrade to MySQL 4.1+ to use concurrent MyISAM inserts");
} elsif ($myvar{'concurrent_insert'} eq "OFF") {
push(@generalrec,"Enable concurrent_insert by setting it to 'ON'");
} elsif ($myvar{'concurrent_insert'} eq 0) {
push(@generalrec,"Enable concurrent_insert by setting it to 1");
}
if ($mycalc{'pct_aborted_connections'} > 5) {
badprint "Connections aborted: ".$mycalc{'pct_aborted_connections'}."%\n";
push(@generalrec,"Your applications are not closing MySQL connections properly");
}
# InnoDB
if (defined $myvar{'have_innodb'} && $myvar{'have_innodb'} eq "YES" && defined $enginestats{'InnoDB'}) {
if ($myvar{'innodb_buffer_pool_size'} > $enginestats{'InnoDB'}) {
goodprint "InnoDB data size / buffer pool: ".hr_bytes($enginestats{'InnoDB'})."/".hr_bytes($myvar{'innodb_buffer_pool_size'})."\n";
} else {
badprint "InnoDB data size / buffer pool: ".hr_bytes($enginestats{'InnoDB'})."/".hr_bytes($myvar{'innodb_buffer_pool_size'})."\n";
push(@adjvars,"innodb_buffer_pool_size (>= ".hr_bytes_rnd($enginestats{'InnoDB'}).")");
}
}
}
# Take the two recommendation arrays and display them at the end of the output
sub make_recommendations {
print "\n-------- Recommendations -----------------------------------------------------\n";
if (@generalrec > 0) {
print "General recommendations:\n";
foreach (@generalrec) { print " ".$_."\n"; }
}
if (@adjvars > 0) {
print "Variables to adjust:\n";
if ($mycalc{'pct_physical_memory'} > 90) {
print " *** MySQL's maximum memory usage is dangerously high ***\n".
" *** Add RAM before increasing MySQL buffer variables ***\n";
}
foreach (@adjvars) { print " ".$_."\n"; }
}
if (@generalrec == 0 && @adjvars ==0) {
print "No additional performance recommendations are available.\n"
}
print "\n";
}
# ---------------------------------------------------------------------------
# BEGIN 'MAIN'
# ---------------------------------------------------------------------------
print "\n >> MySQLTuner $tunerversion - Major Hayden <major\@mhtx.net>\n".
" >> Bug reports, feature requests, and downloads at http://mysqltuner.com/\n".
" >> Run with '--help' for additional options and output filtering\n";
mysql_setup; # Gotta login first
os_setup; # Set up some OS variables
get_all_vars; # Toss variables/status into hashes
validate_tuner_version; # Check current MySQLTuner version
validate_mysql_version; # Check current MySQL version
check_architecture; # Suggest 64-bit upgrade
check_storage_engines; # Show enabled storage engines
security_recommendations; # Display some security recommendations
calculations; # Calculate everything we need
mysql_stats; # Print the server stats
make_recommendations; # Make recommendations based on stats
# ---------------------------------------------------------------------------
# END 'MAIN'
# ---------------------------------------------------------------------------
# Local variables:
# indent-tabs-mode: t
# cperl-indent-level: 8
# perl-indent-level: 8
# End:

File diff suppressed because it is too large Load Diff

View File

@ -1,15 +0,0 @@
# hash a string as mysql's "PASSWORD()" function would do it
require 'digest/sha1'
module Puppet::Parser::Functions
newfunction(:mysql_password, :type => :rvalue, :doc => <<-EOS
Returns the mysql password hash from the clear text password.
EOS
) do |args|
raise(Puppet::ParseError, "mysql_password(): Wrong number of arguments " +
"given (#{args.size} for 1)") if args.size != 1
'*' + Digest::SHA1.hexdigest(Digest::SHA1.digest(args[0])).upcase
end
end

View File

@ -1,63 +0,0 @@
Puppet::Type.type(:database).provide(:mysql) do
desc "Manages MySQL database."
defaultfor :kernel => 'Linux'
optional_commands :mysql => 'mysql'
optional_commands :mysqladmin => 'mysqladmin'
# Optional defaults file
def self.defaults_file
if File.file?('/root/.my.cnf')
"--defaults-extra-file=#{Facter.value(:root_home)}/.my.cnf"
else
nil
end
end
def defaults_file
self.class.defaults_file
end
def self.instances
mysql(defaults_file, '-NBe', "show databases").split("\n").collect do |name|
new(:name => name)
end
end
def create
tries=10
begin
debug("Trying to create database #{@resource[:name]} ")
mysql(defaults_file, '-NBe', "create database `#{@resource[:name]}` character set #{resource[:charset]}")
rescue
debug("Can't connect to the server: #{tries} tries to reconnect")
sleep 5
retry unless (tries -= 1) <= 0
end
end
def destroy
mysqladmin(defaults_file, '-f', 'drop', @resource[:name])
end
def charset
mysql(defaults_file, '-NBe', "show create database `#{resource[:name]}`").match(/.*?(\S+)\s\*\//)[1]
end
def charset=(value)
mysql(defaults_file, '-NBe', "alter database `#{resource[:name]}` CHARACTER SET #{value}")
end
def exists?
begin
mysql(defaults_file, '-NBe', "show databases").match(/^#{@resource[:name]}$/)
rescue => e
debug(e.message)
return nil
end
end
end

View File

@ -1,189 +0,0 @@
# A grant is either global or per-db. This can be distinguished by the syntax
# of the name:
# user@host => global
# user@host/db => per-db
Puppet::Type.type(:database_grant).provide(:mysql) do
desc "Uses mysql as database."
defaultfor :kernel => 'Linux'
optional_commands :mysql => 'mysql'
optional_commands :mysqladmin => 'mysqladmin'
# Optional defaults file
def self.defaults_file
if File.file?('/root/.my.cnf')
"--defaults-extra-file=#{Facter.value(:root_home)}/.my.cnf"
else
nil
end
end
def defaults_file
self.class.defaults_file
end
def self.prefetch(resources)
@user_privs = nil
@db_privs = nil
end
def self.user_privs
@user_privs || query_user_privs
end
def self.db_privs
@db_privs || query_db_privs
end
def user_privs
self.class.user_privs
end
def db_privs
self.class.db_privs
end
def self.query_user_privs
results = mysql(defaults_file, "mysql", "-Be", "describe user")
column_names = results.split(/\n/).map { |l| l.chomp.split(/\t/)[0] }
@user_privs = column_names.delete_if { |e| !( e =~/_priv$/) }
end
def self.query_db_privs
results = mysql(defaults_file, "mysql", "-Be", "describe db")
column_names = results.split(/\n/).map { |l| l.chomp.split(/\t/)[0] }
@db_privs = column_names.delete_if { |e| !(e =~/_priv$/) }
end
def mysql_flush
mysqladmin defaults_file, "flush-privileges"
end
# this parses the
def split_name(string)
matches = /^([^@]*)@([^\/]*)(\/(.*))?$/.match(string).captures.compact
case matches.length
when 2
{
:type => :user,
:user => matches[0],
:host => matches[1]
}
when 4
{
:type => :db,
:user => matches[0],
:host => matches[1],
:db => matches[3]
}
end
end
def create_row
unless @resource.should(:privileges).empty?
name = split_name(@resource[:name])
case name[:type]
when :user
mysql defaults_file, "mysql", "-e", "INSERT INTO user (host, user) VALUES ('%s', '%s')" % [
name[:host], name[:user],
]
when :db
mysql defaults_file, "mysql", "-e", "INSERT INTO db (host, user, db) VALUES ('%s', '%s', '%s')" % [
name[:host], name[:user], name[:db],
]
end
mysql_flush
end
end
def destroy
mysql defaults_file, "mysql", "-e", "REVOKE ALL ON '%s'.* FROM '%s@%s'" % [ @resource[:privileges], @resource[:database], @resource[:name], @resource[:host] ]
end
def row_exists?
name = split_name(@resource[:name])
fields = [:user, :host]
if name[:type] == :db
fields << :db
end
not mysql(defaults_file, "mysql", "-NBe", 'SELECT "1" FROM %s WHERE %s' % [ name[:type], fields.map do |f| "%s = '%s'" % [f, name[f]] end.join(' AND ')]).empty?
end
def all_privs_set?
all_privs = case split_name(@resource[:name])[:type]
when :user
user_privs
when :db
db_privs
end
all_privs = all_privs.collect do |p| p.downcase end.sort.join("|")
privs = privileges.collect do |p| p.downcase end.sort.join("|")
all_privs == privs
end
def privileges
name = split_name(@resource[:name])
privs = ""
case name[:type]
when :user
privs = mysql defaults_file, "mysql", "-Be", 'select * from user where user="%s" and host="%s"' % [ name[:user], name[:host] ]
when :db
privs = mysql defaults_file, "mysql", "-Be", 'select * from db where user="%s" and host="%s" and db="%s"' % [ name[:user], name[:host], name[:db] ]
end
if privs.match(/^$/)
privs = [] # no result, no privs
else
# returns a line with field names and a line with values, each tab-separated
privs = privs.split(/\n/).map! do |l| l.chomp.split(/\t/) end
# transpose the lines, so we have key/value pairs
privs = privs[0].zip(privs[1])
privs = privs.select do |p| p[0].match(/_priv$/) and p[1] == 'Y' end
end
privs.collect do |p| p[0] end
end
def privileges=(privs)
unless row_exists?
create_row
end
# puts "Setting privs: ", privs.join(", ")
name = split_name(@resource[:name])
stmt = ''
where = ''
all_privs = []
case name[:type]
when :user
stmt = 'update user set '
where = ' where user="%s" and host="%s"' % [ name[:user], name[:host] ]
all_privs = user_privs
when :db
stmt = 'update db set '
where = ' where user="%s" and host="%s" and db="%s"' % [ name[:user], name[:host], name[:db] ]
all_privs = db_privs
end
if privs[0].downcase == 'all'
privs = all_privs
end
# Downcase the requested priviliges for case-insensitive selection
# we don't map! here because the all_privs object has to remain in
# the same case the DB gave it to us in
privs = privs.map { |p| p.downcase }
# puts "stmt:", stmt
set = all_privs.collect do |p| "%s = '%s'" % [p, privs.include?(p.downcase) ? 'Y' : 'N'] end.join(', ')
# puts "set:", set
stmt = stmt << set << where
mysql defaults_file, "mysql", "-Be", stmt
mysql_flush
end
end

View File

@ -1,62 +0,0 @@
Puppet::Type.type(:database_user).provide(:mysql) do
desc "manage users for a mysql database."
defaultfor :kernel => 'Linux'
optional_commands :mysql => 'mysql'
optional_commands :mysqladmin => 'mysqladmin'
# Optional defaults file
def self.defaults_file
if File.file?('/root/.my.cnf')
"--defaults-extra-file=#{Facter.value(:root_home)}/.my.cnf"
else
nil
end
end
def defaults_file
self.class.defaults_file
end
def self.instances
users = mysql(defaults_file, "mysql", '-BNe' "select concat(User, '@',Host) as User from mysql.user").split("\n")
users.select{ |user| user =~ /.+@/ }.collect do |name|
new(:name => name)
end
end
def create
mysql(defaults_file, "mysql", "-e", "create user '%s' identified by PASSWORD '%s'" % [ @resource[:name].sub("@", "'@'"), @resource.value(:password_hash) ])
end
def destroy
mysql(defaults_file, "mysql", "-e", "drop user '%s'" % @resource.value(:name).sub("@", "'@'") )
end
def password_hash
mysql(defaults_file, "mysql", "-NBe", "select password from user where CONCAT(user, '@', host) = '%s'" % @resource.value(:name)).chomp
end
def password_hash=(string)
mysql(defaults_file, "mysql", "-e", "SET PASSWORD FOR '%s' = '%s'" % [ @resource[:name].sub("@", "'@'"), string ] )
end
def exists?
tries=10
begin
not mysql(defaults_file, "mysql", "-NBe", "select '1' from user where CONCAT(user, '@', host) = '%s'" % @resource.value(:name)).empty?
rescue
debug("Can't connect to the mysql server: #{tries} tries to reconnect")
sleep 5
retry unless (tries -= 1) <= 0
end
end
def flush
@property_hash.clear
mysqladmin defaults_file, "flush-privileges"
end
end

View File

@ -1,17 +0,0 @@
# This has to be a separate type to enable collecting
Puppet::Type.newtype(:database) do
@doc = "Manage databases."
ensurable
newparam(:name, :namevar=>true) do
desc "The name of the database."
end
newproperty(:charset) do
desc "The characterset to use for a database"
defaultto :utf8
newvalue(/^\S+$/)
end
end

View File

@ -1,75 +0,0 @@
# This has to be a separate type to enable collecting
Puppet::Type.newtype(:database_grant) do
@doc = "Manage a database user's rights."
#ensurable
autorequire :database do
# puts "Starting db autoreq for %s" % self[:name]
reqs = []
matches = self[:name].match(/^([^@]+)@([^\/]+)\/(.+)$/)
unless matches.nil?
reqs << matches[3]
end
# puts "Autoreq: '%s'" % reqs.join(" ")
reqs
end
autorequire :database_user do
# puts "Starting user autoreq for %s" % self[:name]
reqs = []
matches = self[:name].match(/^([^@]+)@([^\/]+).*$/)
unless matches.nil?
reqs << "%s@%s" % [ matches[1], matches[2] ]
end
# puts "Autoreq: '%s'" % reqs.join(" ")
reqs
end
newparam(:name, :namevar=>true) do
desc "The primary key: either user@host for global privilges or user@host/database for database specific privileges"
end
newproperty(:privileges, :array_matching => :all) do
desc "The privileges the user should have. The possible values are implementation dependent."
def should_to_s(newvalue = @should)
if newvalue
unless newvalue.is_a?(Array)
newvalue = [ newvalue ]
end
newvalue.collect do |v| v.downcase end.sort.join ", "
else
nil
end
end
def is_to_s(currentvalue = @is)
if currentvalue
unless currentvalue.is_a?(Array)
currentvalue = [ currentvalue ]
end
currentvalue.collect do |v| v.downcase end.sort.join ", "
else
nil
end
end
# use the sorted outputs for comparison
def insync?(is)
if defined? @should and @should
case self.should_to_s
when "all"
self.provider.all_privs_set?
when self.is_to_s(is)
true
else
false
end
else
true
end
end
end
end

View File

@ -1,25 +0,0 @@
# This has to be a separate type to enable collecting
Puppet::Type.newtype(:database_user) do
@doc = "Manage a database user. This includes management of users password as well as priveleges"
ensurable
newparam(:name, :namevar=>true) do
desc "The name of the user. This uses the 'username@hostname' or username@hostname."
validate do |value|
# https://dev.mysql.com/doc/refman/5.1/en/account-names.html
# Regex should problably be more like this: /^[`'"]?[^`'"]*[`'"]?@[`'"]?[\w%\.]+[`'"]?$/
raise(ArgumentError, "Invalid database user #{value}") unless value =~ /[\w-]*@[\w%\.]+/
username = value.split('@')[0]
if username.size > 16
raise ArgumentError, "MySQL usernames are limited to a maximum of 16 characters"
end
end
end
newproperty(:password_hash) do
desc "The password hash of the user. Use mysql_password() for creating such a hash."
newvalue(/\w+/)
end
end

View File

@ -1,68 +0,0 @@
# Class: mysql::backup
#
# This module handles ...
#
# Parameters:
# [*backupuser*] - The name of the mysql backup user.
# [*backuppassword*] - The password of the mysql backup user.
# [*backupdir*] - The target directory of the mysqldump.
#
# Actions:
# GRANT SELECT, RELOAD, LOCK TABLES ON *.* TO 'user'@'localhost'
# IDENTIFIED BY 'password';
#
# Requires:
# Class['mysql::config']
#
# Sample Usage:
# class { 'mysql::backup':
# backupuser => 'myuser',
# backuppassword => 'mypassword',
# backupdir => '/tmp/backups',
# }
#
class mysql::backup (
$backupuser,
$backuppassword,
$backupdir,
$ensure = 'present'
) {
database_user { "${backupuser}@localhost":
ensure => $ensure,
password_hash => mysql_password($backuppassword),
provider => 'mysql',
require => Class['mysql::config'],
}
database_grant { "${backupuser}@localhost":
privileges => [ 'Select_priv', 'Reload_priv', 'Lock_tables_priv' ],
require => Database_user["${backupuser}@localhost"],
}
cron { 'mysql-backup':
ensure => $ensure,
command => '/usr/local/sbin/mysqlbackup.sh',
user => 'root',
hour => 23,
minute => 5,
require => File['mysqlbackup.sh'],
}
file { 'mysqlbackup.sh':
ensure => $ensure,
path => '/usr/local/sbin/mysqlbackup.sh',
mode => '0700',
owner => 'root',
group => 'root',
content => template('mysql/mysqlbackup.sh.erb'),
}
file { 'mysqlbackupdir':
ensure => 'directory',
path => $backupdir,
mode => '0700',
owner => 'root',
group => 'root',
}
}

View File

@ -1,2 +0,0 @@
class mysql::bindings {
}

View File

@ -1,14 +0,0 @@
# Class: mysql::bindings::python
#
# This class installs the python libs for mysql.
#
# Actions:
#
# Requires:
#
# Sample Usage:
#
class mysql::bindings::python(
) {
include ::mysql::python
}

View File

@ -1,138 +0,0 @@
# Class: mysql::config
#
# Parameters:
#
# [*root_password*] - root user password.
# [*old_root_password*] - previous root user password,
# [*bind_address*] - address to bind service.
# [*port*] - port to bind service.
# [*etc_root_password*] - whether to save /etc/.my.cnf.
# [*service_name*] - mysql service name.
# [*config_file*] - my.cnf configuration file path.
# [*socket*] - mysql socket.
# [*datadir*] - path to datadir.
# [*ssl*] - enable ssl
# [*ssl_ca*] - path to ssl-ca
# [*ssl_cert*] - path to ssl-cert
# [*ssl_key*] - path to ssl-key
# [*ignore_db_dirs*] - array of directories to ignore in datadir.
#
# Actions:
#
# Requires:
#
# class mysql::server
#
# Usage:
#
# class { 'mysql::config':
# root_password => 'changeme',
# bind_address => $::ipaddress,
# }
#
class mysql::config(
$bind_address = $mysql::params::bind_address,
$port = $mysql::params::port,
$service_name = $mysql::params::service_name,
$config_file = $mysql::params::config_file,
$socket = $mysql::params::socket,
$pidfile = $mysql::params::pidfile,
$datadir = $mysql::params::datadir,
$ssl = $mysql::params::ssl,
$ssl_ca = $mysql::params::ssl_ca,
$ssl_cert = $mysql::params::ssl_cert,
$ssl_key = $mysql::params::ssl_key,
$log_error = $mysql::params::log_error,
$default_engine = 'UNSET',
$root_group = $mysql::params::root_group,
$use_syslog = false,
$custom_setup_class = undef,
$server_id = $mysql::params::server_id,
$debug = $mysql::params::debug,
$wait_timeout = $mysql::params::wait_timeout,
$ignore_db_dirs = $mysql::params::ignore_db_dirs,
) inherits mysql::params {
$mysql_buffer_pool_size = $::mysql::params::mysql_buffer_pool_size
$mysql_log_file_size = $::mysql::params::mysql_log_file_size
$max_connections = $::mysql::params::max_connections
$table_open_cache = $::mysql::params::table_open_cache
$key_buffer_size = $::mysql::params::key_buffer_size
$myisam_sort_buffer_size = $::mysql::params::myisam_sort_buffer_size
$open_files_limit = $::mysql::params::open_files_limit
if ! is_array($ignore_db_dirs) {
fail('The ignore_db_dirs parameter is expected to be an array')
}
if $custom_setup_class != 'pacemaker_mysql' {
File {
owner => 'root',
group => $root_group,
mode => '0400',
notify => Exec['mysqld-restart'],
}
} else {
File {
owner => 'root',
group => $root_group,
mode => '0400',
notify => Service['mysql'],
}
}
if ($custom_setup_class == undef) {
if $ssl and $ssl_ca == undef {
fail('The ssl_ca parameter is required when ssl is true')
}
if $ssl and $ssl_cert == undef {
fail('The ssl_cert parameter is required when ssl is true')
}
if $ssl and $ssl_key == undef {
fail('The ssl_key parameter is required when ssl is true')
}
# This kind of sucks, that I have to specify a difference resource for
# restart. the reason is that I need the service to be started before mods
# to the config file which can cause a refresh
exec { 'mysqld-restart':
command => "service ${service_name} restart",
logoutput => on_failure,
refreshonly => true,
path => '/sbin/:/usr/sbin/:/usr/bin/:/bin/',
}
file { '/etc/mysql':
ensure => directory,
mode => '0755',
}
file { '/etc/mysql/conf.d':
ensure => directory,
mode => '0755',
}
#FIXME(bogdando): dirtyhack to pervert imperative puppet nature.
if $::mysql_log_file_size_real != $mysql_log_file_size {
# delete MySQL ib_logfiles, if log file size does not match the one
# from params
exec { 'delete_logfiles':
command => "rm -f ${datadir}/ib_logfile* || true",
path => [ '/sbin/', '/usr/sbin/', '/usr/bin/' ,'/bin/' ],
before => File[$config_file],
}
# use predefined value for log file size
$innodb_log_file_size_real = $mysql_log_file_size
} else {
# evaluate existing log file size and use it as a value
$innodb_log_file_size_real = $::mysql_log_file_size_real
}
file { $config_file:
content => template('mysql/my.cnf.erb'),
mode => '0644',
}
}
}

View File

@ -1,77 +0,0 @@
# Define: mysql::db
#
# This module creates database instances, a user, and grants that user
# privileges to the database. It can also import SQL from a file in order to,
# for example, initialize a database schema.
#
# Since it requires class mysql::server, we assume to run all commands as the
# root mysql user against the local mysql server.
#
# Parameters:
# [*title*] - mysql database name.
# [*user*] - username to create and grant access.
# [*password*] - user's password.
# [*charset*] - database charset.
# [*host*] - host for assigning privileges to user.
# [*grant*] - array of privileges to grant user.
# [*enforce_sql*] - whether to enforce or conditionally run sql on creation.
# [*sql*] - sql statement to run.
#
# Actions:
#
# Requires:
#
# class mysql::server
#
# Sample Usage:
#
# mysql::db { 'mydb':
# user => 'my_user',
# password => 'password',
# host => $::hostname,
# grant => ['all']
# }
#
define mysql::db (
$user,
$password,
$charset = 'utf8',
$host = 'localhost',
$grant = 'all',
$sql = '',
$enforce_sql = false
) {
database { $name:
ensure => present,
charset => $charset,
provider => 'mysql',
require => Class['mysql::server'],
}
database_user { "${user}@${host}":
ensure => present,
password_hash => mysql_password($password),
provider => 'mysql',
require => Database[$name],
}
database_grant { "${user}@${host}/${name}":
privileges => $grant,
provider => 'mysql',
require => Database_user["${user}@${host}"],
}
$refresh = ! $enforce_sql
if $sql {
exec{ "${name}-import":
command => "/usr/bin/mysql ${name} < ${sql}",
logoutput => true,
refreshonly => $refresh,
require => Database_grant["${user}@${host}/${name}"],
subscribe => Database[$name],
}
}
}

View File

@ -1,24 +0,0 @@
# Class: mysql
#
# This class installs mysql client software.
#
# Parameters:
# [*client_package_name*] - The name of the mysql client package.
#
# Actions:
#
# Requires:
#
# Sample Usage:
#
class mysql (
$package_name = $mysql::params::client_package_name,
$package_ensure = $mysql::params::client_version
) inherits mysql::params {
package { 'mysql-client':
name => $package_name,
#ensure => $package_ensure,
}
}

View File

@ -1,24 +0,0 @@
# Class: mysql::java
#
# This class installs the mysql-java-connector.
#
# Parameters:
# [*java_package_name*] - The name of the mysql java package.
#
# Actions:
#
# Requires:
#
# Sample Usage:
#
class mysql::java (
$package_name = $mysql::params::java_package_name,
$package_ensure = 'present'
) inherits mysql::params {
package { 'mysql-connector-java':
ensure => $package_ensure,
name => $package_name,
}
}

View File

@ -1,124 +0,0 @@
# Class: mysql::params
#
# The mysql configuration settings.
#
# Parameters:
#
# Actions:
#
# Requires:
#
# Sample Usage:
#
class mysql::params {
$bind_address = '127.0.0.1'
$port = 3306
$etc_root_password = false
$ssl = false
$server_id = delete($::hostname, ['controller-', 'fuel-', 'node-'])
$service_provider = undef
#TODO(bogdando) remove code duplication for galera and mysql manifests to openstack::db in 'I' release
#Set buffer pool size to 30% of memory, but not greater than 10G
$buffer_size =
inline_template("<%= [(${::memorysize_mb} * 0.3 + 0).floor, 10000].min %>")
$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'
$myisam_sort_buffer_size = '64M'
$key_buffer_size = '64M'
$table_open_cache = '10000'
$open_files_limit = '102400'
$max_connections = '3000'
$debug = false
$ignore_db_dirs = []
case $::osfamily {
'RedHat': {
$basedir = '/usr'
$datadir = '/var/lib/mysql'
case $::operatingsystem {
'RedHat': {
$service_name = 'mysqld'
$client_package_name = 'mysql'
$client_version = '5.1.69-1'
$server_package_name = 'mysql-server'
$server_version = '5.1.69-1'
$shared_package_name = 'mysql-libs'
$shared_version = '5.1.69-1'
}
default: {
$service_name = 'mysql'
$client_package_name = 'MySQL-client'
$client_version = '5.5.28_wsrep_23.7'
$server_package_nam = 'MySQL-server'
$server_version = '5.5.28_wsrep_23.7'
$shared_package_name = 'MySQL-shared'
$shared_version = '5.5.28_wsrep_23.7'
}
}
$socket = '/var/lib/mysql/mysql.sock'
$pidfile = '/var/run/mysqld/mysqld.pid'
$config_file = '/etc/my.cnf'
$log_error = '/var/log/mysqld.log'
$ruby_package_name = 'ruby-mysql'
$ruby_package_provider = 'gem'
$python_package_name = 'MySQL-python'
$java_package_name = 'mysql-connector-java'
$root_group = 'root'
$ssl_ca = '/etc/mysql/cacert.pem'
$ssl_cert = '/etc/mysql/server-cert.pem'
$ssl_key = '/etc/mysql/server-key.pem'
}
'Debian': {
$basedir = '/usr'
$datadir = '/var/lib/mysql'
$service_name = 'mysql'
$client_package_name = 'mysql-client-5.5'
$server_package_name = 'mysql-server-5.5'
$shared_package_name = 'mysql-common'
$socket = '/var/run/mysqld/mysqld.sock'
$pidfile = '/var/run/mysqld/mysqld.pid'
$config_file = '/etc/mysql/my.cnf'
$log_error = '/var/log/mysql/error.log'
$ruby_package_name = 'libmysql-ruby'
$python_package_name = 'python-mysqldb'
$java_package_name = 'libmysql-java'
$root_group = 'root'
$ssl_ca = '/etc/mysql/cacert.pem'
$ssl_cert = '/etc/mysql/server-cert.pem'
$ssl_key = '/etc/mysql/server-key.pem'
}
'FreeBSD': {
$basedir = '/usr/local'
$datadir = '/var/db/mysql'
$service_name = 'mysql-server'
$client_package_name = 'databases/mysql55-client'
$client_version = 'installed'
$server_package_name = 'databases/mysql55-server'
$server_version = 'installed'
$shared_package_name = 'databases/mysql55-server'
$shared_version = 'installed'
$socket = '/tmp/mysql.sock'
$pidfile = '/var/db/mysql/mysql.pid'
$config_file = '/var/db/mysql/my.cnf'
$log_error = "/var/db/mysql/${::hostname}.err"
$ruby_package_name = 'ruby-mysql'
$ruby_package_provider = 'gem'
$python_package_name = 'databases/py-MySQLdb'
$java_package_name = 'databases/mysql-connector-java'
$root_group = 'wheel'
$ssl_ca = undef
$ssl_cert = undef
$ssl_key = undef
}
default: {
fail("Unsupported osfamily: ${::osfamily} operatingsystem: ${::operatingsystem}, module ${module_name} only support osfamily RedHat Debian and FreeBSD")
}
}
}

View File

@ -1,54 +0,0 @@
class mysql::password (
$root_password = 'UNSET',
$old_root_password = '',
$etc_root_password = false,
$config_file = $mysql::params::config_file,
) inherits mysql::params {
if $root_password != 'UNSET' {
case $old_root_password {
'': { $old_pw='' }
default: { $old_pw="-p${old_root_password}" }
}
exec { 'set_mysql_rootpw':
command => "mysqladmin -u root ${old_pw} password ${root_password}",
logoutput => true,
unless => "mysqladmin -u root -p${root_password} status > /dev/null",
path => '/usr/local/sbin:/usr/bin:/usr/local/bin',
tries => 10,
try_sleep => 3,
}
if $etc_root_password {
$password_file_path = '/etc/mysql/conf.d/password.cnf'
} else {
$password_file_path = '/root/.my.cnf'
}
file { 'mysql_password' :
path => $password_file_path,
content => template('mysql/my.cnf.pass.erb'),
mode => '0640',
owner => 'mysql',
group => 'mysql',
}
Service <| title == 'mysql' |> -> Exec['set_mysql_rootpw']
Service <| title == 'mysql-service' |> -> Exec['set_mysql_rootpw']
Exec['set_mysql_rootpw'] -> File['mysql_password']
File <| title == $config_file |> -> File['mysql_password']
File <| title == '/etc/my.cnf' |> -> File['mysql_password']
File['mysql_password'] -> Database <| provider=='mysql' |>
File['mysql_password'] -> Database_grant <| provider=='mysql' |>
File['mysql_password'] -> Database_user <| provider=='mysql' |>
Anchor <| title == 'database-cluster' |> -> Class['mysql::password'] -> Anchor <| title == 'database-cluster-done' |>
Exec <| title == 'wait-for-synced-state' |> -> Exec['set_mysql_rootpw']
Exec <| title == 'wait-initial-sync' |> -> Exec['set_mysql_rootpw']
}
}

View File

@ -1,26 +0,0 @@
# Class: mysql::python
#
# This class installs the python libs for mysql.
#
# Parameters:
# [*ensure*] - ensure state for package.
# can be specified as version.
# [*package_name*] - name of package
#
# Actions:
#
# Requires:
#
# Sample Usage:
#
class mysql::python(
$package_name = $mysql::params::python_package_name,
$package_ensure = 'present'
) inherits mysql::params {
package { 'python-mysqldb':
ensure => $package_ensure,
name => $package_name,
}
}

View File

@ -1,13 +0,0 @@
#class mysql::replicator (
# Not used because we need to start mysql for the first time
# with corosync with init script to create users
# database_user { "${user}@${name}":
# password_hash => mysql_password($password),
# provider => 'mysql',
# }
# database_grant { "${user}@${name}":
# privileges => ['Super_priv'],
# provider => 'mysql',
# require => Database_user["${user}@${name}"]
# }
#}

View File

@ -1,28 +0,0 @@
# Class: mysql::ruby
#
# installs the ruby bindings for mysql
#
# Parameters:
# [*ensure*] - ensure state for package.
# can be specified as version.
# [*package_name*] - name of package
#
# Actions:
#
# Requires:
#
# Sample Usage:
#
class mysql::ruby (
$package_name = $mysql::params::ruby_package_name,
$package_provider = $mysql::params::ruby_package_provider,
$package_ensure = 'present'
) inherits mysql::params {
package{ 'ruby_mysql':
ensure => $package_ensure,
name => $package_name,
provider => $package_provider,
}
}

View File

@ -1,281 +0,0 @@
# Class: mysql::server
#
# manages the installation of the mysql server. manages the package, service,
# my.cnf
#
# Parameters:
# [*package_name*] - name of package
# [*service_name*] - name of service
# [*config_hash*] - hash of config parameters that need to be set.
#
# Actions:
#
# Requires:
#
# Sample Usage:
#
class mysql::server (
$custom_setup_class = undef,
$client_package_name = $mysql::params::client_package_name,
$package_name = $mysql::params::server_package_name,
$package_ensure = 'present',
$service_name = $mysql::params::service_name,
$service_provider = $mysql::params::service_provider,
$config_hash = {},
$enabled = true,
$galera_cluster_name = undef,
$primary_controller = false,
$galera_node_address = undef,
$galera_nodes = undef,
$galera_gcache_factor = 0,
$mysql_skip_name_resolve = false,
$server_id = $mysql::params::server_id,
$rep_user = 'replicator',
$rep_pass = 'replicant666',
$replication_roles = 'SELECT, PROCESS, FILE, SUPER, REPLICATION CLIENT, REPLICATION SLAVE, RELOAD',
$initscript_file = 'puppet:///modules/mysql/mysql-single.init',
$root_password = 'UNSET',
$old_root_password = '',
$etc_root_password = true,
$bind_address = '0.0.0.0',
$use_syslog = true,
$wait_timeout = $mysql::params::wait_timeout,
$ignore_db_dirs = $mysql::params::ignore_db_dirs,
) inherits mysql::params {
if ($config_hash['config_file']) {
$config_file_real = $config_hash['config_file']
} else {
$config_file_real = $mysql::params::config_file
}
class { '::mysql::password' :
root_password => $root_password,
old_root_password => $old_root_password,
etc_root_password => $etc_root_password,
config_file => $config_file_real,
}
class { '::mysql::config' :
bind_address => $bind_address,
use_syslog => $use_syslog,
custom_setup_class => $custom_setup_class,
config_file => $config_file_real,
wait_timeout => $wait_timeout,
}
Exec {path => '/usr/bin:/bin:/usr/sbin:/sbin'}
if ($custom_setup_class == undef) {
class { '::mysql':
package_name => $client_package_name,
}
Class['mysql::server'] -> Class['mysql::config']
Class['mysql'] -> Class['mysql::server']
if !defined(Package['mysql-client']) {
package { 'mysql-client':
name => $package_name,
}
}
package { 'mysql-server':
name => $package_name,
}
if $::operatingsystem == 'RedHat' {
file { '/etc/init.d/mysqld':
ensure => present,
source => $initscript_file,
mode => '0755',
owner => 'root',
}
File['/etc/init.d/mysqld'] -> Service['mysql']
}
Package['mysql-client'] -> Package['mysql-server']
$service_ensure = $enabled ? {
true => 'running',
default => 'stopped'
}
service { 'mysql':
ensure => $service_ensure,
name => $service_name,
enable => $enabled,
require => Package['mysql-server'],
provider => $service_provider,
}
}
elsif ($custom_setup_class == 'pacemaker_mysql') {
class { '::mysql':
package_name => $client_package_name,
}
Package['mysql-server'] -> Class['mysql::config']
Package['mysql-client'] -> Package['mysql-server']
$mysql_config = merge($config_hash, { custom_setup_class => $custom_setup_class })
$allowed_hosts = '%'
create_resources( 'class', { 'mysql::config' => $mysql_config })
Class['mysql::config'] -> Cs_resource["p_${service_name}"]
if !defined(Package['mysql-client']) {
package { 'mysql-client':
name => $package_name,
}
}
package { 'mysql-server':
name => $package_name,
} ->
exec { 'create-mysql-table-if-missing':
command => "/usr/bin/mysql_install_db --datadir=${mysql::params::datadir} --user=mysql && chown -R mysql:mysql ${mysql::params::datadir}",
path => '/bin:/usr/bin:/sbin:/usr/sbin',
unless => "test -d ${mysql::params::datadir}/mysql",
}
file { '/tmp/repl_create.sql' :
ensure => present,
content => template('mysql/repl_create.sql.erb'),
owner => 'root',
group => 'root',
mode => '0644',
}
### Start hacks
file { '/usr/lib/ocf/resource.d/heartbeat/mysql':
ensure => present,
source => 'puppet:///modules/mysql/ocf/ocf-mysql',
owner => 'root',
group => 'root',
mode => '0755',
require => File['/tmp/repl_create.sql'],
} ->
install_ssh_keys {'root_ssh_key_for_mysql':
ensure => present,
user => 'root',
private_key_path => '/var/lib/astute/mysql/mysql',
public_key_path => '/var/lib/astute/mysql/mysql.pub',
private_key_name => 'id_rsa_mysql',
public_key_name => 'id_rsa_mysql.pub',
authorized_keys => 'authorized_keys',
}
if ( $::hostname == $galera_nodes[2] ) or ( $galera_node_address == $galera_nodes[2] ) {
$existing_slave = $galera_nodes[1]
exec { 'stop_mysql_slave_on_second_controller':
command => "ssh -i /root/.ssh/id_rsa_mysql -o StrictHostKeyChecking=no root@${existing_slave} 'mysql -NBe \"stop slave;\"'",
require => Install_ssh_keys['root_ssh_key_for_mysql'],
unless => "mysql -NBe 'show slave status;' | grep -q ${rep_user}",
} ->
exec { 'copy_mysql_data_dir':
command => "rsync -e 'ssh -i /root/.ssh/id_rsa_mysql -o StrictHostKeyChecking=no' -vaz root@${existing_slave}:/var/lib/mysql/. /var/lib/mysql/.",
unless => "mysql -NBe 'show slave status;' | grep -q ${rep_user}",
} ->
exec { 'start_mysql_slave_on_second_controller':
command => "ssh -i /root/.ssh/id_rsa_mysql -o StrictHostKeyChecking=no root@${existing_slave} 'mysql -NBe \"start slave;\"'",
unless => "mysql -NBe 'show slave status;' | grep -q ${rep_user}",
}
}
### end hacks
cs_resource { "p_${service_name}":
ensure => present,
primitive_class => 'ocf',
provided_by => 'heartbeat',
primitive_type => 'mysql',
cib => 'mysql',
complex_type => 'master',
ms_metadata => {
'notify' => true
},
parameters => {
'binary' => '/usr/bin/mysqld_safe',
'test_table' => 'mysql.user',
'replication_user' => $rep_user,
'replication_passwd' => $rep_pass,
'additional_parameters' => '"--init-file=/tmp/repl_create.sql"',
},
operations => {
'monitor' => {
'interval' => '20',
'timeout' => '30'
},
'start' => {
'timeout' => '360'
},
'stop' => {
'timeout' => '360'
},
'promote' => {
'timeout' => '360'
},
'demote' => {
'timeout' => '360'
},
'notify' => {
'timeout' => '360'
},
}
}->
service { 'mysql':
ensure => 'running',
name => "p_${service_name}",
enable => true,
require => [Package['mysql-server']],
provider => 'pacemaker',
}
#Tie vip__management to p_mysqld
cs_rsc_colocation { 'mysql_to_internal-vip':
primitives => ['vip__management',"master_p_${service_name}:Master"],
score => 'INFINITY',
require => [Cs_resource["p_${service_name}"]],
}
}
elsif ($custom_setup_class == 'galera') {
Class['galera'] -> Class['mysql::server']
class { '::galera':
cluster_name => $galera_cluster_name,
primary_controller => $primary_controller,
node_address => $galera_node_address,
node_addresses => $galera_nodes,
gcache_factor => $galera_gcache_factor,
skip_name_resolve => $mysql_skip_name_resolve,
use_syslog => $use_syslog,
wsrep_sst_password => $root_password,
}
}
elsif ($custom_setup_class == 'percona') {
Class['galera'] -> Class['mysql::server']
class { '::galera':
cluster_name => $galera_cluster_name,
primary_controller => $primary_controller,
node_address => $galera_node_address,
node_addresses => $galera_nodes,
gcache_factor => $galera_gcache_factor,
skip_name_resolve => $mysql_skip_name_resolve,
use_syslog => $use_syslog,
wsrep_sst_password => $root_password,
use_percona => true,
}
} elsif ($custom_setup_class == 'percona_packages') {
Class['galera'] -> Class['mysql::server']
class { '::galera':
cluster_name => $galera_cluster_name,
primary_controller => $primary_controller,
node_address => $galera_node_address,
node_addresses => $galera_nodes,
gcache_factor => $galera_gcache_factor,
skip_name_resolve => $mysql_skip_name_resolve,
use_syslog => $use_syslog,
wsrep_sst_password => $root_password,
use_percona => true,
use_percona_packages => true
}
} else {
require($custom_setup_class)
}
}

View File

@ -1,19 +0,0 @@
class mysql::server::account_security {
# Some installations have some default users which are not required.
# We remove them here. You can subclass this class to overwrite this behavior.
if $::fqdn {
database_user { [ "root@${::fqdn}", "@${::fqdn}" ]:
ensure => 'absent',
require => Class['mysql::config'],
}
}
database_user { [ 'root@127.0.0.1', "root@${::hostname}", "@${::hostname}", '@localhost', '@%' ]:
ensure => 'absent',
require => Class['mysql::config'],
}
database { 'test':
ensure => 'absent',
require => Class['mysql::config'],
}
}

View File

@ -1,19 +0,0 @@
class mysql::server::monitor (
$mysql_monitor_username,
$mysql_monitor_password,
$mysql_monitor_hostname
) {
Class['mysql::server'] -> Class['mysql::server::monitor']
database_user{ "${mysql_monitor_username}@${mysql_monitor_hostname}":
ensure => present,
password_hash => mysql_password($mysql_monitor_password),
}
database_grant { "${mysql_monitor_username}@${mysql_monitor_hostname}":
privileges => [ 'process_priv', 'super_priv' ],
require => Mysql_user["${mysql_monitor_username}@${mysql_monitor_hostname}"],
}
}

View File

@ -1,22 +0,0 @@
# Copyright 2009 Larry Ludwig (larrylud@gmail.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 required 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 mysql::server::mysqltuner {
# mysql performance tester
file { '/usr/bin/mysqltuner':
ensure => present,
mode => '0550',
source => 'puppet:///modules/mysql/mysqltuner.pl',
}
}

View File

@ -1,33 +0,0 @@
require 'spec_helper'
describe 'mysql::backup' do
let(:params) {
{ 'backupuser' => 'testuser',
'backuppassword' => 'testpass',
'backupdir' => '/tmp',
}
}
it { should contain_database_user('testuser@localhost')}
it { should contain_database_grant('testuser@localhost').with(
:privileges => [ 'Select_priv', 'Reload_priv', 'Lock_tables_priv' ]
)}
it { should contain_cron('mysql-backup').with(
:command => '/usr/local/sbin/mysqlbackup.sh',
:ensure => 'present'
)}
it { should contain_file('mysqlbackup.sh').with(
:path => '/usr/local/sbin/mysqlbackup.sh',
:ensure => 'present'
)}
it { should contain_file('mysqlbackupdir').with(
:path => '/tmp',
:ensure => 'directory'
)}
end

View File

@ -1,236 +0,0 @@
require 'spec_helper'
describe 'mysql::config' do
let :constant_parameter_defaults do
{
:root_password => 'UNSET',
:old_root_password => '',
:bind_address => '127.0.0.1',
:port => '3306',
:etc_root_password => false,
:datadir => '/var/lib/mysql',
:default_engine => 'UNSET',
:ssl => false,
}
end
describe 'with osfamily specific defaults' do
{
'Debian' => {
:datadir => '/var/lib/mysql',
:service_name => 'mysql',
:config_file => '/etc/mysql/my.cnf',
:socket => '/var/run/mysqld/mysqld.sock',
:root_group => 'root',
:ssl_ca => '/etc/mysql/cacert.pem',
:ssl_cert => '/etc/mysql/server-cert.pem',
:ssl_key => '/etc/mysql/server-key.pem'
},
'FreeBSD' => {
:datadir => '/var/db/mysql',
:service_name => 'mysql-server',
:config_file => '/var/db/mysql/my.cnf',
:socket => '/tmp/mysql.sock',
:root_group => 'wheel',
},
'Redhat' => {
:datadir => '/var/lib/mysql',
:service_name => 'mysql',
:config_file => '/etc/my.cnf',
:socket => '/var/lib/mysql/mysql.sock',
:root_group => 'root',
:ssl_ca => '/etc/mysql/cacert.pem',
:ssl_cert => '/etc/mysql/server-cert.pem',
:ssl_key => '/etc/mysql/server-key.pem'
}
}.each do |osfamily, osparams|
describe "when osfamily is #{osfamily}" do
let :facts do
{:osfamily => osfamily}
end
describe 'when root password is set' do
let :params do
{:root_password => 'foo'}
end
it { should contain_exec('set_mysql_rootpw').with(
'command' => 'mysqladmin -u root password foo',
'logoutput' => true,
'unless' => "mysqladmin -u root -pfoo status > /dev/null",
'path' => '/usr/local/sbin:/usr/bin:/usr/local/bin'
)}
it { should contain_file('/root/.my.cnf').with(
'content' => "[client]\nuser=root\nhost=localhost\npassword=foo\n",
'require' => 'Exec[set_mysql_rootpw]'
)}
end
describe 'when root password and old password are set' do
let :params do
{:root_password => 'foo', :old_root_password => 'bar'}
end
it { should contain_exec('set_mysql_rootpw').with(
'command' => 'mysqladmin -u root -pbar password foo',
'logoutput' => true,
'unless' => "mysqladmin -u root -pfoo status > /dev/null",
'path' => '/usr/local/sbin:/usr/bin:/usr/local/bin'
)}
end
[
{},
{
:service_name => 'dans_service',
:config_file => '/home/dan/mysql.conf',
:service_name => 'dans_mysql',
:socket => '/home/dan/mysql.sock',
:bind_address => '0.0.0.0',
:port => '3306',
:datadir => '/path/to/datadir',
:default_engine => 'InnoDB',
:ssl => true,
:ssl_ca => '/path/to/cacert.pem',
:ssl_cert => '/path/to/server-cert.pem',
:ssl_key => '/path/to/server-key.pem'
}
].each do |passed_params|
describe "with #{passed_params == {} ? 'default' : 'specified'} parameters" do
let :parameter_defaults do
constant_parameter_defaults.merge(osparams)
end
let :params do
passed_params
end
let :param_values do
parameter_defaults.merge(params)
end
it { should contain_exec('mysqld-restart').with(
:refreshonly => true,
:path => '/sbin/:/usr/sbin/:/usr/bin/:/bin/',
:command => "service #{param_values[:service_name]} restart"
)}
it { should_not contain_exec('set_mysql_rootpw') }
it { should_not contain_file('/root/.my.cnf')}
it { should contain_file('/etc/mysql').with(
'owner' => 'root',
'group' => param_values[:root_group],
'notify' => 'Exec[mysqld-restart]',
'ensure' => 'directory',
'mode' => '0755'
)}
it { should contain_file('/etc/mysql/conf.d').with(
'owner' => 'root',
'group' => param_values[:root_group],
'notify' => 'Exec[mysqld-restart]',
'ensure' => 'directory',
'mode' => '0755'
)}
it { should contain_file(param_values[:config_file]).with(
'owner' => 'root',
'group' => param_values[:root_group],
'notify' => 'Exec[mysqld-restart]',
'mode' => '0644'
)}
it 'should have a template with the correct contents' do
content = param_value(subject, 'file', param_values[:config_file], 'content')
expected_lines = [
"port = #{param_values[:port]}",
"socket = #{param_values[:socket]}",
"datadir = #{param_values[:datadir]}",
"bind-address = #{param_values[:bind_address]}"
]
if param_values[:default_engine] != 'UNSET'
expected_lines = expected_lines | [ "default-storage-engine = #{param_values[:default_engine]}" ]
end
if param_values[:ssl]
expected_lines = expected_lines |
[
"ssl-ca = #{param_values[:ssl_ca]}",
"ssl-cert = #{param_values[:ssl_cert]}",
"ssl-key = #{param_values[:ssl_key]}"
]
end
(content.split("\n") & expected_lines).should == expected_lines
end
end
end
end
end
end
describe 'when etc_root_password is set with password' do
let :facts do
{:osfamily => 'Debian'}
end
let :params do
{:root_password => 'foo', :old_root_password => 'bar', :etc_root_password => true}
end
it { should contain_exec('set_mysql_rootpw').with(
'command' => 'mysqladmin -u root -pbar password foo',
'logoutput' => true,
'unless' => "mysqladmin -u root -pfoo status > /dev/null",
'path' => '/usr/local/sbin:/usr/bin:/usr/local/bin'
)}
it { should contain_file('/root/.my.cnf').with(
'content' => "[client]\nuser=root\nhost=localhost\npassword=foo\n",
'require' => 'Exec[set_mysql_rootpw]'
)}
end
describe 'setting etc_root_password should fail on redhat' do
let :facts do
{:osfamily => 'Redhat'}
end
let :params do
{:root_password => 'foo', :old_root_password => 'bar', :etc_root_password => true}
end
it 'should fail' do
expect do
subject
end.should raise_error(Puppet::Error, /Duplicate (declaration|definition)/)
end
end
describe 'unset ssl params should fail when ssl is true on freebsd' do
let :facts do
{:osfamily => 'FreeBSD'}
end
let :params do
{ :ssl => true }
end
it 'should fail' do
expect do
subject
end.should raise_error(Puppet::Error, /required when ssl is true/)
end
end
end

View File

@ -1,56 +0,0 @@
require 'spec_helper'
describe 'mysql' do
describe 'on a debian based os' do
let :facts do
{ :osfamily => 'Debian'}
end
it { should contain_package('mysql-client').with(
:name => 'mysql-client',
:ensure => 'present'
)}
end
describe 'on a freebsd based os' do
let :facts do
{ :osfamily => 'FreeBSD'}
end
it { should contain_package('mysql-client').with(
:name => 'databases/mysql55-client',
:ensure => 'present'
)}
end
describe 'on a redhat based os' do
let :facts do
{:osfamily => 'Redhat'}
end
it { should contain_package('mysql-client').with(
:name => 'mysql',
:ensure => 'present'
)}
describe 'when parameters are supplied' do
let :params do
{:package_ensure => 'latest', :package_name => 'mysql-client'}
end
it { should contain_package('mysql-client').with(
:name => 'mysql-client',
:ensure => 'latest'
)}
end
end
describe 'on any other os' do
let :facts do
{:osfamily => 'foo'}
end
it 'should fail' do
expect do
subject
end.should raise_error(/Unsupported osfamily: foo/)
end
end
end

View File

@ -1,56 +0,0 @@
require 'spec_helper'
describe 'mysql::java' do
describe 'on a debian based os' do
let :facts do
{ :osfamily => 'Debian'}
end
it { should contain_package('mysql-connector-java').with(
:name => 'libmysql-java',
:ensure => 'present'
)}
end
describe 'on a freebsd based os' do
let :facts do
{ :osfamily => 'FreeBSD'}
end
it { should contain_package('mysql-connector-java').with(
:name => 'databases/mysql-connector-java',
:ensure => 'present'
)}
end
describe 'on a redhat based os' do
let :facts do
{:osfamily => 'Redhat'}
end
it { should contain_package('mysql-connector-java').with(
:name => 'mysql-connector-java',
:ensure => 'present'
)}
describe 'when parameters are supplied' do
let :params do
{:package_ensure => 'latest', :package_name => 'java-mysql'}
end
it { should contain_package('mysql-connector-java').with(
:name => 'java-mysql',
:ensure => 'latest'
)}
end
end
describe 'on any other os' do
let :facts do
{:osfamily => 'foo'}
end
it 'should fail' do
expect do
subject
end.should raise_error(/Unsupported osfamily: foo/)
end
end
end

View File

@ -1,56 +0,0 @@
require 'spec_helper'
describe 'mysql::python' do
describe 'on a debian based os' do
let :facts do
{ :osfamily => 'Debian'}
end
it { should contain_package('python-mysqldb').with(
:name => 'python-mysqldb',
:ensure => 'present'
)}
end
describe 'on a freebsd based os' do
let :facts do
{ :osfamily => 'FreeBSD'}
end
it { should contain_package('python-mysqldb').with(
:name => 'databases/py-MySQLdb',
:ensure => 'present'
)}
end
describe 'on a redhat based os' do
let :facts do
{:osfamily => 'Redhat'}
end
it { should contain_package('python-mysqldb').with(
:name => 'MySQL-python',
:ensure => 'present'
)}
describe 'when parameters are supplied' do
let :params do
{:package_ensure => 'latest', :package_name => 'python-mysql'}
end
it { should contain_package('python-mysqldb').with(
:name => 'python-mysql',
:ensure => 'latest'
)}
end
end
describe 'on any other os' do
let :facts do
{:osfamily => 'foo'}
end
it 'should fail' do
expect do
subject
end.should raise_error(/Unsupported osfamily: foo/)
end
end
end

View File

@ -1,64 +0,0 @@
require 'spec_helper'
describe 'mysql::ruby' do
describe 'on a debian based os' do
let :facts do
{ :osfamily => 'Debian'}
end
it { should contain_package('ruby_mysql').with(
:name => 'libmysql-ruby',
:ensure => 'present',
# TODO is this what we want? does this actually work
# if the provider is blank
:provider => ''
)}
end
describe 'on a freebsd based os' do
let :facts do
{ :osfamily => 'FreeBSD'}
end
it { should contain_package('ruby_mysql').with(
:name => 'ruby-mysql',
:ensure => 'present',
:provider => 'gem'
)}
end
describe 'on a redhat based os' do
let :facts do
{:osfamily => 'Redhat'}
end
it { should contain_package('ruby_mysql').with(
:name => 'ruby-mysql',
:ensure => 'present',
:provider => 'gem'
)}
describe 'when parameters are supplied' do
let :params do
{:package_ensure => 'latest',
:package_provider => 'zypper',
:package_name => 'mysql_ruby'}
end
it { should contain_package('ruby_mysql').with(
:name => 'mysql_ruby',
:ensure => 'latest',
:provider => 'zypper'
)}
end
end
describe 'on any other os' do
let :facts do
{:osfamily => 'foo'}
end
it 'should fail' do
expect do
subject
end.should raise_error(/Unsupported osfamily: foo/)
end
end
end

View File

@ -1,37 +0,0 @@
require 'spec_helper'
describe 'mysql::server::account_security' do
let :facts do {
:fqdn => 'myhost.mydomain',
:hostname => 'myhost'
}
end
it 'should remove Database_User[root@myhost.mydomain]' do
should contain_database_user('root@myhost.mydomain').with_ensure('absent')
end
it 'should remove Database_User[root@myhost]' do
should contain_database_user('root@myhost').with_ensure('absent')
end
it 'should remove Database_User[root@127.0.0.1]' do
should contain_database_user('root@127.0.0.1').with_ensure('absent')
end
it 'should remove Database_User[@myhost.mydomain]' do
should contain_database_user('@myhost.mydomain').with_ensure('absent')
end
it 'should remove Database_User[@myhost]' do
should contain_database_user('@myhost').with_ensure('absent')
end
it 'should remove Database_User[@localhost]' do
should contain_database_user('@localhost').with_ensure('absent')
end
it 'should remove Database_User[@%]' do
should contain_database_user('@%').with_ensure('absent')
end
it 'should remove Database[test]' do
should contain_database('test').with_ensure('absent')
end
end

View File

@ -1,18 +0,0 @@
require 'spec_helper'
describe 'mysql::server::monitor' do
let :facts do
{ :osfamily => 'Debian' }
end
let :pre_condition do
"include 'mysql::server'"
end
let :params do
{
:mysql_monitor_username => 'monitoruser',
:mysql_monitor_password => 'monitorpass',
:mysql_monitor_hostname => 'monitorhost'
}
end
it { should contain_database_user("monitoruser@monitorhost")}
end

View File

@ -1,92 +0,0 @@
require 'spec_helper'
describe 'mysql::server' do
let :constant_parameter_defaults do
{:config_hash => {},
:package_ensure => 'present',
:enabled => true
}
end
describe 'when ubuntu use upstart' do
let :facts do
{ :osfamily => 'Debian',
:operatingsystem => 'Ubuntu',
}
end
it { should contain_service('mysqld').with(
:name => 'mysql',
:ensure => 'running',
:enable => 'true',
:provider => 'upstart',
:require => 'Package["mysql-server"]'
)}
end
describe 'with osfamily specific defaults' do
{
'Debian' => {
:service_name => 'mysql',
:package_name => 'mysql-server'
},
'FreeBSD' => {
:service_name => 'mysql-server',
:package_name => 'databases/mysql55-server'
},
'Redhat' => {
:service_name => 'mysql',
:package_name => 'mysql-server'
}
}.each do |osfamily, osparams|
describe "when osfamily is #{osfamily}" do
let :facts do
{ :osfamily => osfamily }
end
[
{},
{
:package_name => 'dans_package',
:package_ensure => 'latest',
:service_name => 'dans_service',
:config_hash => {'root_password' => 'foo'},
:enabled => false
}
].each do |passed_params|
describe "with #{passed_params == {} ? 'default' : 'specified'} parameters" do
let :parameter_defaults do
constant_parameter_defaults.merge(osparams)
end
let :params do
passed_params
end
let :param_values do
parameter_defaults.merge(params)
end
it { should contain_package('mysql-server').with(
:name => param_values[:package_name],
:ensure => param_values[:package_ensure]
)}
it { should contain_service('mysqld').with(
:name => param_values[:service_name],
:ensure => param_values[:enabled] ? 'running' : 'stopped',
:enable => param_values[:enabled],
:require => 'Package["mysql-server"]'
)}
it { should contain_service('mysqld').without_provider }
end
end
end
end
end
end

View File

@ -1,30 +0,0 @@
require 'spec_helper'
describe 'mysql::db', :type => :define do
let(:title) { 'test_db' }
let(:params) {
{ 'user' => 'testuser',
'password' => 'testpass',
}
}
it 'should not notify the import sql exec if no sql script was provided' do
should contain_database('test_db').without_notify
end
it 'should subscribe to database if sql script is given' do
params.merge!({'sql' => 'test_sql'})
should contain_exec('test_db-import').with_subscribe('Database[test_db]')
end
it 'should only import sql script on creation if not enforcing' do
params.merge!({'sql' => 'test_sql', 'enforce_sql' => false})
should contain_exec('test_db-import').with_refreshonly(true)
end
it 'should import sql script on creation if enforcing' do
params.merge!({'sql' => 'test_sql', 'enforce_sql' => true})
should contain_exec('test_db-import').with_refreshonly(false)
end
end

View File

@ -1,24 +0,0 @@
require File.expand_path('../../spec_helper', __FILE__)
describe command('mysql --user=myuser --password=mypassword --host=localhost -e "show grants"') do
it { should return_exit_status 0 }
it { should return_stdout /GRANT SELECT, RELOAD, LOCK TABLES ON *.* TO 'myuser'@'localhost'/ }
end
describe file('/usr/local/sbin/mysqlbackup.sh') do
it { should be_file }
it { should be_mode 700 }
it { should be_owned_by 'root' }
it { should be_grouped_into 'root' }
end
describe file('/tmp/backups') do
it { should be_directory }
it { should be_mode 700 }
it { should be_owned_by 'root' }
it { should be_grouped_into 'root' }
end
describe cron do
it { should have_entry('5 23 * * * /usr/local/sbin/mysqlbackup.sh').with_user('root') }
end

View File

@ -1,11 +0,0 @@
require File.expand_path('../../spec_helper', __FILE__)
$mysql_client_package = case attr[:osfamily]
when 'Debian' then 'mysql-client'
when 'RedHat' then 'MySQL-client'
else 'mysql-client'
end
describe package($mysql_client_package) do
it { should be_installed }
end

View File

@ -1,11 +0,0 @@
require File.expand_path('../../spec_helper', __FILE__)
$mysql_java_package = case attr[:osfamily]
when 'Debian' then 'libmysql-java'
when 'RedHat' then 'mysql-connector-java'
else 'mysql-connector-java'
end
describe package($mysql_java_package) do
it { should be_installed }
end

View File

@ -1,11 +0,0 @@
require File.expand_path('../../spec_helper', __FILE__)
$mysql_python_package = case attr[:osfamily]
when 'Debian' then 'python-mysqldb'
when 'RedHat' then 'MySQL-python'
else 'mysql-python'
end
describe package($mysql_python_package) do
it { should be_installed }
end

View File

@ -1,5 +0,0 @@
require File.expand_path('../../spec_helper', __FILE__)
describe command('ruby -e "require \'rubygems\'; require \'mysql\';"') do
it { should return_exit_status 0 }
end

View File

@ -1,65 +0,0 @@
require File.expand_path('../../spec_helper', __FILE__)
$mysql_server_package = case attr[:osfamily]
when 'Debian' then 'mysql-server'
when 'RedHat' then 'MySQL-server'
else 'mysql-server'
end
$mysql_server_service = case attr[:osfamily]
when 'Debian' then 'mysql'
when 'RedHat' then 'mysql'
else 'mysql'
end
describe package($mysql_server_package) do
it { should be_installed }
end
describe service($mysql_server_service) do
it { should be_running }
it { should be_enabled }
end
describe file('/root/.my.cnf') do
it { should be_file }
it { should contain '[client]' }
it { should contain 'user=root' }
it { should contain 'host=localhost' }
it { should contain 'password=password' }
end
describe command('mysql -B -e "show create database redmine_db"') do
it { should return_exit_status 0 }
it { should return_stdout /CHARACTER SET utf8/ }
end
describe command('mysql -B -e "show create database other_db"') do
it { should return_exit_status 0 }
it { should return_stdout /CHARACTER SET utf8/ }
end
describe command('mysql -B -e "show create database old_db"') do
it { should return_exit_status 0 }
it { should return_stdout /CHARACTER SET latin1/ }
end
describe command('mysql --user=dan --password=blah --host=localhost -e "show grants"') do
it { should return_exit_status 0 }
it { should return_stdout /GRANT ALL PRIVILEGES ON `other_db`.* TO 'dan'@'localhost' WITH GRANT OPTION/ }
end
describe command('mysql --user=redmine --password=redmine --host=localhost -e "show grants"') do
it { should return_exit_status 0 }
it { should return_stdout /GRANT ALL PRIVILEGES ON `redmine_db`.* TO 'redmine'@'localhost' WITH GRANT OPTION/ }
end
describe command('mysql -B -e "show create database test"') do
it { should_not return_exit_status 0 }
end
describe command('mysql -e "show grants for \'\'@\'localhost\'"') do
it { should_not return_exit_status 0 }
it { should_not return_stdout /GRANT USAGE ON/ }
end

View File

@ -1,34 +0,0 @@
require 'rubygems'
require 'serverspec'
require 'pathname'
require 'facter'
require 'puppet'
include Serverspec::Helper::Exec
include Serverspec::Helper::DetectOS
Puppet.parse_config
if Puppet[:libdir] && !Facter.search_path.include?(Puppet[:libdir])
Facter.search(Puppet[:libdir])
end
facts = {}
Facter.list.each do |fact|
facts[fact] = Facter.value(fact) || ''
end
Facter.list.map { |fact| [fact, Facter.value(fact) || ''].flatten }
RSpec.configure do |c|
if ENV['ASK_SUDO_PASSWORD']
require 'highline/import'
c.sudo_password = ask("Enter sudo password: ") { |q| q.echo = false }
else
c.sudo_password = ENV['SUDO_PASSWORD']
end
attr_set facts
c.before :all do
ENV['LANG'] = 'C'
end
end

View File

@ -1 +0,0 @@
require 'puppetlabs_spec_helper/module_spec_helper'

View File

@ -1,30 +0,0 @@
#!/usr/bin/env rspec
require 'spec_helper'
describe "the mysql_password function" do
before :all do
Puppet::Parser::Functions.autoloader.loadall
end
before :each do
@scope = Puppet::Parser::Scope.new
end
it "should exist" do
Puppet::Parser::Functions.function("mysql_password").should == "function_mysql_password"
end
it "should raise a ParseError if there is less than 1 arguments" do
lambda { @scope.function_mysql_password([]) }.should( raise_error(Puppet::ParseError))
end
it "should raise a ParseError if there is more than 1 arguments" do
lambda { @scope.function_mysql_password(['foo', 'bar']) }.should( raise_error(Puppet::ParseError))
end
it "should convert password into a hash" do
result = @scope.function_mysql_password(["password"])
result.should(eq('*2470C0C06DEE42FD1618BB99005ADCA2EC9D1E19'))
end
end

View File

@ -1,81 +0,0 @@
require 'puppet'
require 'mocha'
RSpec.configure do |config|
config.mock_with :mocha
end
provider_class = Puppet::Type.type(:database_grant).provider(:mysql)
describe provider_class do
before :each do
@resource = Puppet::Type::Database_grant.new(
{ :privileges => 'all', :provider => 'mysql', :name => 'user@host'}
)
@provider = provider_class.new(@resource)
end
it 'should query privilegess from the database' do
provider_class.expects(:mysql) .with('mysql', '-Be', 'describe user').returns <<-EOT
Field Type Null Key Default Extra
Host char(60) NO PRI
User char(16) NO PRI
Password char(41) NO
Select_priv enum('N','Y') NO N
Insert_priv enum('N','Y') NO N
Update_priv enum('N','Y') NO N
EOT
provider_class.expects(:mysql).with('mysql', '-Be', 'describe db').returns <<-EOT
Field Type Null Key Default Extra
Host char(60) NO PRI
Db char(64) NO PRI
User char(16) NO PRI
Select_priv enum('N','Y') NO N
Insert_priv enum('N','Y') NO N
Update_priv enum('N','Y') NO N
EOT
provider_class.user_privs.should == [ 'Select_priv', 'Insert_priv', 'Update_priv' ]
provider_class.db_privs.should == [ 'Select_priv', 'Insert_priv', 'Update_priv' ]
end
it 'should query set priviliges' do
provider_class.expects(:mysql).with('mysql', '-Be', 'select * from user where user="user" and host="host"').returns <<-EOT
Host User Password Select_priv Insert_priv Update_priv
host user Y N Y
EOT
@provider.privileges.should == [ 'Select_priv', 'Update_priv' ]
end
it 'should recognize when all priviliges are set' do
provider_class.expects(:mysql).with('mysql', '-Be', 'select * from user where user="user" and host="host"').returns <<-EOT
Host User Password Select_priv Insert_priv Update_priv
host user Y Y Y
EOT
@provider.all_privs_set?.should == true
end
it 'should recognize when all privileges are not set' do
provider_class.expects(:mysql).with('mysql', '-Be', 'select * from user where user="user" and host="host"').returns <<-EOT
Host User Password Select_priv Insert_priv Update_priv
host user Y N Y
EOT
@provider.all_privs_set?.should == false
end
it 'should be able to set all privileges' do
provider_class.expects(:mysql).with('mysql', '-NBe', 'SELECT "1" FROM user WHERE user = \'user\' AND host = \'host\'').returns "1\n"
provider_class.expects(:mysql).with('mysql', '-Be', "update user set Select_priv = 'Y', Insert_priv = 'Y', Update_priv = 'Y' where user=\"user\" and host=\"host\"")
provider_class.expects(:mysqladmin).with("flush-privileges")
@provider.privileges=(['all'])
end
it 'should be able to set partial privileges' do
provider_class.expects(:mysql).with('mysql', '-NBe', 'SELECT "1" FROM user WHERE user = \'user\' AND host = \'host\'').returns "1\n"
provider_class.expects(:mysql).with('mysql', '-Be', "update user set Select_priv = 'Y', Insert_priv = 'N', Update_priv = 'Y' where user=\"user\" and host=\"host\"")
provider_class.expects(:mysqladmin).with("flush-privileges")
@provider.privileges=(['Select_priv', 'Update_priv'])
end
it 'should be case insensitive' do
provider_class.expects(:mysql).with('mysql', '-NBe', 'SELECT "1" FROM user WHERE user = \'user\' AND host = \'host\'').returns "1\n"
provider_class.expects(:mysql).with('mysql', '-Be', "update user set Select_priv = 'Y', Insert_priv = 'Y', Update_priv = 'Y' where user=\"user\" and host=\"host\"")
provider_class.expects(:mysqladmin).with('flush-privileges')
@provider.privileges=(['SELECT_PRIV', 'insert_priv', 'UpDaTe_pRiV'])
end
end

View File

@ -1,5 +0,0 @@
server-id=<%= server_id %>
log-bin=mysql-bin
relay-log=mysqld-relay-bin
replicate-ignore-db=mysql
slave-skip-errors=1007

View File

@ -1,90 +0,0 @@
[client]
port = <%= @port %>
socket = <%= @socket %>
[mysqld_safe]
socket = <%= @socket %>
nice = 0
<% if @use_syslog -%>
syslog
<% end -%>
[mysqld]
innodb_file_per_table=1
<% if @operatingsystem != 'RedHat' %>
table_open_cache=<%= @table_open_cache %>
innodb_file_format=Barracuda
<% else %>
table_cache=<%= @table_open_cache %>
<% end %>
user = mysql
#pid-file = <%= @pidfile %>
socket = <%= @socket %>
port = <%= @port %>
basedir = <%= @basedir %>
datadir = <%= @datadir %>
tmpdir = /tmp
<% if @ignore_db_dirs and (@ignore_db_dirs.length > 0) %>
<% @ignore_db_dirs.each do |directory| %>
ignore-db-dir = <%= directory %>
<% end %>
<% end %>
skip-external-locking
bind-address = <%= @bind_address %>
max_allowed_packet = 256M
thread_stack = 192K
thread_cache_size = 8
myisam-recover = BACKUP
query_cache_limit = 1M
query_cache_size = 16M
<% if @mysql_buffer_pool_size %>
innodb_buffer_pool_size=<%= @mysql_buffer_pool_size %>
<% if @innodb_log_file_size_real != '0' %>
innodb_log_file_size=<%= @innodb_log_file_size_real %>
<% end %>
<% end %>
innodb_thread_concurrency= 0
innodb_write_io_threads = 2
innodb_read_io_threads = 8
innodb_io_capacity = 500
key_buffer_size = <%= @key_buffer_size %>
myisam_sort_buffer_size = <%= @myisam_sort_buffer_size %>
wait_timeout = <%= @wait_timeout %>
open_files_limit = <%= @open_files_limit %>
<% if @use_syslog -%>
#log_error = syslog:local1
<% else -%>
log_error = <%= @log_error %>
<% end -%>
expire_logs_days = 10
max_binlog_size = 100M
max_connections = <%= @max_connections %>
<% if @default_engine != 'UNSET' %>
default-storage-engine = <%= @default_engine %>
<% end %>
<% if @ssl == true %>
ssl-ca = <%= @ssl_ca %>
ssl-cert = <%= @ssl_cert %>
ssl-key = <%= @ssl_key %>
<% end %>
<% if @debug %>
slow_query_log = 1
long_query_time = 10
log_queries_not_using_indexes = 1
<% end %>
<% if @custom_setup_class == 'pacemaker_mysql' %>
server-id=<%= @server_id %>
log-bin=mysql-bin
relay-log=mysqld-relay-bin
replicate-ignore-db=mysql
<% end %>
collation-server = utf8_general_ci
init-connect='SET NAMES utf8'
character-set-server = utf8
explicit_defaults_for_timestamp = TRUE
[mysqldump]
quick
quote-names
max_allowed_packet = 16M
[mysql]
[isamchk]
key_buffer_size = 16M
!includedir /etc/mysql/conf.d/

View File

@ -1,6 +0,0 @@
[client]
user=root
host=localhost
<% unless @root_password == 'UNSET' -%>
password=<%= @root_password %>
<% end -%>

View File

@ -1,23 +0,0 @@
#!/bin/sh
#
# MySQL Backup Script
# Dumps mysql databases to a file for another backup tool to pick up.
#
# MySQL code:
# GRANT SELECT, RELOAD, LOCK TABLES ON *.* TO 'user'@'localhost'
# IDENTIFIED BY 'password';
# FLUSH PRIVILEGES;
#
##### START CONFIG ###################################################
USER=<%= backupuser %>
PASS=<%= backuppassword %>
DIR=<%= backupdir %>
##### STOP CONFIG ####################################################
PATH=/usr/bin:/usr/sbin:/bin:/sbin
find $DIR -mtime +30 -exec rm -f {} \;
mysqldump -u${USER} -p${PASS} --opt --flush-logs --single-transaction \
--all-databases | bzcat -zc > ${DIR}/mysql_backup_`date +%Y%m%d-%H%M%S`.sql.bz2

View File

@ -1,14 +0,0 @@
USE mysql;
grant <%= replication_roles %> on *.* to '<%= rep_user %>'@'%' IDENTIFIED by '<%= rep_pass %>';
grant <%= replication_roles %> on *.* to '<%= rep_user %>'@'localhost' IDENTIFIED by '<%= rep_pass %>';
<% @galera_nodes.each do |node| -%>
grant <%= replication_roles %> on *.* to '<%= rep_user %>'@'<%= node %>' IDENTIFIED by '<%= rep_pass %>';
<% end -%>
<%- interfaces.split(',').each do |int|
if has_variable?("ipaddress_#{int}") then %>
grant <%= replication_roles %> on *.* to '<%= rep_user %>'@'<%= scope.lookupvar("ipaddress_#{int}") %>' IDENTIFIED by '<%= rep_pass %>';
<%- end
end %>
grant <%= replication_roles %> on *.* to '<%= rep_user %>'@'<%= internal_address %>' IDENTIFIED by '<%= rep_pass %>';
grant <%= replication_roles %> on *.* to '<%= rep_user %>'@'<%= server_id %>' IDENTIFIED by '<%= rep_pass %>';
flush privileges;

View File

@ -1,71 +0,0 @@
require 'find'
TESTS_DIR = File.dirname(File.expand_path(__FILE__))
SPEC_DIR = File.expand_path(TESTS_DIR + '/../spec/integration')
if ENV['puppet_debug']
PUPPET_OPTIONS = "--detailed-exitcodes --verbose --debug --trace --evaltrace"
else
PUPPET_OPTIONS = "--detailed-exitcodes"
end
RSPEC_OPTIONS = "--color -f doc"
def puppet(manifest_file)
fail "No such manifest '#{manifest_file}'!" unless File.exist?(manifest_file)
sh "puppet apply #{PUPPET_OPTIONS} '#{manifest_file}'" do |ok, res|
fail "Apply of manifest '#{manifest_file}' failed with exit code #{res.exitstatus}!" unless [0,2].include?(res.exitstatus)
end
end
def rspec(test_name)
rspec_file = "#{SPEC_DIR}/default/#{test_name}_spec.rb"
rspec_file = "#{SPEC_DIR}/#{test_name}_spec.rb" unless File.exists?(rspec_file)
if File.exists?(rspec_file)
Dir.chdir(SPEC_DIR) || fail("Can't cd to #{SPEC_DIR}!")
sh "rspec #{RSPEC_OPTIONS} '#{rspec_file}'" do |ok, res|
fail("Test #{test_name} failed with exit code #{res.exitstatus}!") unless ok
end
else
puts "Spec file for test '#{test_name}' doesn't exist! Skipping test phase."
end
end
Dir.chdir(TESTS_DIR) || exit(1)
all_tasks = []
Find.find('.') do |path|
next unless File.file?(path)
next unless path.end_with?('.pp')
path.sub!('./','')
test_name = path.chomp('.pp')
namespace test_name do
task :run => [ :apply, :test ] do
puts "#{test_name} run ends"
end
task :apply do
puppet(path)
puts "#{test_name} have been applied!"
end
task :test do
rspec(test_name)
puts "#{test_name} have been tested!"
end
desc "#{test_name} integration test"
end
task test_name do
Rake::Task["#{test_name}:apply"].invoke
Rake::Task["#{test_name}:test"].invoke
end
all_tasks.push(test_name)
end
desc "Run all tests"
task :all do
all_tasks.each do |test_name|
pwd = Dir.pwd
Rake::Task["#{test_name}:apply"].invoke
Rake::Task["#{test_name}:test"].invoke
Dir.chdir(pwd)
end
end
task :default => [:all]

View File

@ -1,8 +0,0 @@
class { 'mysql::server':
config_hash => {'root_password' => 'password'}
}
class { 'mysql::backup':
backupuser => 'myuser',
backuppassword => 'mypassword',
backupdir => '/tmp/backups',
}

View File

@ -1 +0,0 @@
include mysql

View File

@ -1 +0,0 @@
class { 'mysql::java':}

View File

@ -1 +0,0 @@
class { 'mysql::python':}

View File

@ -1 +0,0 @@
include mysql::ruby

View File

@ -1,47 +0,0 @@
class { 'mysql::server':
config_hash => {
'root_password' => 'password',
}
}
class { 'mysql::server::account_security': }
database{ ['redmine_db', 'other_db']:
ensure => present,
charset => 'utf8',
}
database{ 'old_db':
ensure => present,
charset => 'latin1',
}
database_grant{'redmine@localhost/redmine_db':
privileges => ['all'],
}
database_grant{'dan@localhost/other_db':
privileges => ['all'],
}
database_user{ 'redmine@localhost':
ensure => present,
password_hash => mysql_password('redmine'),
require => Class['mysql::server'],
}
database_user{ 'dan@localhost':
ensure => present,
password_hash => mysql_password('blah'),
require => Class['mysql::server'],
}
database_user{ 'dan@%':
ensure => present,
password_hash => mysql_password('blah'),
require => Class['mysql::server'],
}
Class['mysql::server'] -> Database <| |>
Class['mysql::server'] -> Database_grant <| |>
Class['mysql::server'] -> Database_user <| |>

View File

@ -22,7 +22,7 @@
# [*custom_setup_class*]
# Custom mysql and galera setup class.
#
class galera::client (
class openstack::galera::client (
$custom_setup_class = 'galera',
) {
@ -71,7 +71,7 @@ class galera::client (
}
}
package { 'mysql-client':
name => $mysql_client_name,
class { 'mysql::client':
package_name => $mysql_client_name,
}
}

View File

@ -29,10 +29,6 @@
# (optional) Port for cluster check service
# Defaults to 49000
#
# [*mysql_module*]
# (optional) The puppet-mysql module version to work with
# Defaults to 0.9
#
# [*backend_host*]
# (optional) The MySQL backend host for cluster check
# Defaults to 127.0.0.1
@ -53,7 +49,6 @@ class openstack::galera::status (
$status_password = false,
$status_allow = '%',
$port = '49000',
$mysql_module = '0.9',
$backend_host = '127.0.0.1',
$backend_port = '3306',
$backend_timeout = '10',
@ -61,34 +56,26 @@ class openstack::galera::status (
validate_string($status_user, $status_password)
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 => [ 'USAGE' ],
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 => [ 'select_priv' ],
}
mysql_user { "${status_user}@${status_allow}":
ensure => 'present',
password_hash => mysql_password($status_password),
require => [File["${::root_home}/.my.cnf"],Service['mysqld']],
} ->
mysql_grant { "${status_user}@${status_allow}/*.*":
ensure => 'present',
options => [ 'GRANT' ],
privileges => [ 'USAGE' ],
table => '*.*',
user => "${status_user}@${status_allow}",
before => Anchor['mysql::server::end'],
}
file { '/etc/wsrepclustercheckrc':
content => template('openstack/galera_clustercheck.erb'),
mode => '0755',
owner => 'nobody',
group => 'nogroup',
mode => '0400',
before => Anchor['mysql::server::end'],
}
augeas { 'galeracheck':
@ -99,6 +86,7 @@ class openstack::galera::status (
"set /files/etc/services/service-name[port = '${port}']/protocol tcp",
"set /files/etc/services/service-name[port = '${port}']/#comment 'Galera Cluster Check'",
],
before => Anchor['mysql::server::end'],
}
$group = $::osfamily ? {
@ -107,7 +95,7 @@ class openstack::galera::status (
default => 'nobody',
}
include xinetd
include ::xinetd
xinetd::service { 'galeracheck':
bind => $address,
port => $port,
@ -119,5 +107,6 @@ class openstack::galera::status (
group => $group,
flags => 'IPv4',
require => Augeas['galeracheck'],
before => Anchor['mysql::server::end'],
}
}

View File

@ -0,0 +1,101 @@
require 'spec_helper'
describe 'openstack::galera::client' do
shared_examples_for 'openstack::galera::client config' do
context 'default parameters' do
let(:mysql_client_name) do
case facts[:osfamily]
when 'Debian'
'mysql-client-5.6'
when 'RedHat'
'MySQL-client-wsrep'
else
'mysql-client'
end
end
it 'contains galera client' do
should contain_class('mysql::client').with(
:package_name => mysql_client_name
)
end
end
context 'using percona' do
let(:params) do
{ :custom_setup_class => 'percona' }
end
let(:mysql_client_name) do
case facts[:osfamily]
when 'Debian'
'percona-xtradb-cluster-client-5.5'
else
false
end
end
it 'contains galera client' do
if (mysql_client_name)
should contain_class('mysql::client').with(
:package_name => mysql_client_name
)
else
expect { catalogue }.to raise_error(Puppet::Error, /Unsupported osfamily/)
end
end
end
context 'using percona packages' do
let(:params) do
{ :custom_setup_class => 'percona_packages' }
end
let(:mysql_client_name) do
case facts[:osfamily]
when 'Debian'
'percona-xtradb-cluster-client-5.6'
when 'RedHat'
'Percona-XtraDB-Cluster-client-56'
else
false
end
end
it 'contains galera client' do
if (mysql_client_name)
should contain_class('mysql::client').with(
:package_name => mysql_client_name
)
else
expect { catalogue }.to raise_error(Puppet::Error, /Unsupported osfamily/)
end
end
end
end
context 'on Debian platforms' do
let :facts do
{
:osfamily => 'Debian',
:operatingsystem => 'Debian',
}
end
it_configures 'openstack::galera::client config'
end
context 'on RedHat platforms' do
let :facts do
{
:osfamily => 'RedHat',
:operatingsystem => 'RedHat',
}
end
it_configures 'openstack::galera::client config'
end
end

View File

@ -4,18 +4,18 @@ describe 'openstack::galera::status' do
shared_examples_for 'galera configuration' do
context 'with mysql module with version < 2.2' do
context 'with valid parameters' do
let :params do
{
:mysql_module => 2.1,
:status_user => 'user',
:status_password => 'password',
}
end
it 'should create grant with right privileges' do
should contain_database_grant("user@%/*.*").with(
:privileges => [ 'select_priv' ]
should contain_mysql_grant("user@%/*.*").with(
:options => [ 'GRANT' ],
:privileges => [ 'USAGE' ]
)
end
end

Some files were not shown because too many files have changed in this diff Show More