Skip to content

Commit 51950bf

Browse files
committed
Merge pull request #786 from DavidS/fix-576-rebase-of-763
Fixed MySQL 5.7.6++ compatibility
2 parents 60393f7 + bdf4d0f commit 51950bf

File tree

9 files changed

+374
-19
lines changed

9 files changed

+374
-19
lines changed

README.md

+14
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,8 @@ replicate-do-db = base1
8585
replicate-do-db = base2
8686
~~~
8787

88+
To implement version specific parameters you can use [mysqld-5.5] syntax which is only read by MySQL version 5.5. This allows one config for different versions of MySQL.
89+
8890
### Creating a database
8991

9092
To use `mysql::db` to create a database with a user and assign some privileges:
@@ -181,6 +183,7 @@ mysql::db { 'mydb':
181183
#### Private classes
182184

183185
* `mysql::server::install`: Installs packages.
186+
* `mysql::server::installdb`: Implements setup of mysqld data directory (e.g. /var/lib/mysql)
184187
* `mysql::server::config`: Configures MYSQL.
185188
* `mysql::server::service`: Manages service.
186189
* `mysql::server::account_security`: Deletes default MySQL accounts.
@@ -805,6 +808,17 @@ The name of the MySQL plugin to manage.
805808

806809
The library file name.
807810

811+
#### `mysql_datadir`
812+
813+
Initializes the MySQL data directory with version specific code. Pre MySQL 5.7.6
814+
it uses mysql_install_db. After MySQL 5.7.6 it uses mysqld --initialize-insecure.
815+
816+
Insecure initialization is needed, as mysqld version 5.7 introduced "secure by default" mode.
817+
This means MySQL generates a random password and writes it to STDOUT. This means puppet
818+
can never accesss the database server afterwards, as no credencials are available.
819+
820+
This type is an internal type and should not be called directly.
821+
808822
### Facts
809823

810824
#### `mysql_version`

lib/puppet/provider/mysql.rb

+36-1
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ class Puppet::Provider::Mysql < Puppet::Provider
33
# Without initvars commands won't work.
44
initvars
55
commands :mysql => 'mysql'
6+
commands :mysqld => 'mysqld'
67
commands :mysqladmin => 'mysqladmin'
78

89
# Optional defaults file
@@ -13,7 +14,41 @@ def self.defaults_file
1314
nil
1415
end
1516
end
16-
17+
18+
def self.mysqld_type
19+
# find the mysql "dialect" like mariadb / mysql etc.
20+
mysqld_version_string.scan(/\s\(mariadb/i) { return "mariadb" }
21+
mysqld_version_string.scan(/\s\(mysql/i) { return "mysql" }
22+
mysqld_version_string.scan(/\s\(percona/i) { return "percona" }
23+
nil
24+
end
25+
26+
def mysqld_type
27+
self.class.mysqld_type
28+
end
29+
30+
def self.mysqld_version_string
31+
# we cache the result ...
32+
return @mysqld_version_string unless @mysqld_version_string.nil?
33+
@mysqld_version_string = mysqld(['-V'].compact)
34+
return @mysqld_version_string
35+
end
36+
37+
def mysqld_version_string
38+
self.class.mysqld_version_string
39+
end
40+
41+
def self.mysqld_version
42+
# note: be prepared for '5.7.6-rc-log' etc results
43+
# versioncmp detects 5.7.6-log to be newer then 5.7.6
44+
# this is why we need the trimming.
45+
mysqld_version_string.scan(/\d+\.\d+\.\d+/).first unless mysqld_version_string.nil?
46+
end
47+
48+
def mysqld_version
49+
self.class.mysqld_version
50+
end
51+
1752
def defaults_file
1853
self.class.defaults_file
1954
end
+65
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
require File.expand_path(File.join(File.dirname(__FILE__), '..', 'mysql'))
2+
Puppet::Type.type(:mysql_datadir).provide(:mysql, :parent => Puppet::Provider::Mysql) do
3+
4+
desc 'manage data directories for mysql instances'
5+
6+
commands :mysqld => 'mysqld'
7+
commands :mysql_install_db => 'mysql_install_db'
8+
9+
def create
10+
name = @resource[:name]
11+
insecure = @resource.value(:insecure) || true
12+
defaults_extra_file = @resource.value(:defaults_extra_file)
13+
user = @resource.value(:user) || "mysql"
14+
basedir = @resource.value(:basedir) || "/usr"
15+
datadir = @resource.value(:datadir) || @resource[:name]
16+
17+
unless defaults_extra_file.nil?
18+
if File.exist?(defaults_extra_file)
19+
defaults_extra_file="--defaults-extra-file=#{defaults_extra_file}"
20+
else
21+
raise ArgumentError, "Defaults-extra-file #{defaults_extra_file} is missing"
22+
end
23+
end
24+
25+
if insecure == true
26+
initialize="--initialize-insecure"
27+
else
28+
initialize="--initialize"
29+
end
30+
31+
if mysqld_version.nil?
32+
debug("Installing MySQL data directory with mysql_install_db --basedir=#{basedir} #{defaults_extra_file} --datadir=#{datadir} --user=#{user}")
33+
mysql_install_db(["--basedir=#{basedir}",defaults_extra_file, "--datadir=#{datadir}", "--user=#{user}"].compact)
34+
else
35+
if mysqld_type == "mysql" and Puppet::Util::Package.versioncmp(mysqld_version, '5.7.6') >= 0
36+
debug("Initializing MySQL data directory >= 5.7.6 with 'mysqld #{defaults_extra_file} #{initialize} --basedir=#{basedir} --datadir=#{datadir} --user=#{user}'")
37+
mysqld([defaults_extra_file,initialize,"--basedir=#{basedir}","--datadir=#{datadir}", "--user=#{user}", "--log_error=/var/tmp/mysqld_initialize.log"].compact)
38+
else
39+
debug("Installing MySQL data directory with mysql_install_db --basedir=#{basedir} #{defaults_extra_file} --datadir=#{datadir} --user=#{user}")
40+
mysql_install_db(["--basedir=#{basedir}",defaults_extra_file, "--datadir=#{datadir}", "--user=#{user}"].compact)
41+
end
42+
end
43+
44+
exists?
45+
end
46+
47+
def destroy
48+
name = @resource[:name]
49+
raise ArgumentError, "ERROR: Resource can not be removed"
50+
end
51+
52+
def exists?
53+
datadir = @resource[:datadir]
54+
File.directory?("#{datadir}/mysql")
55+
end
56+
57+
##
58+
## MySQL datadir properties
59+
##
60+
61+
# Generates method for all properties of the property_hash
62+
mk_resource_methods
63+
64+
end
65+

lib/puppet/provider/mysql_user/mysql.rb

+33-3
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,16 @@ def self.instances
1212
# To reduce the number of calls to MySQL we collect all the properties in
1313
# one big swoop.
1414
users.collect do |name|
15-
query = "SELECT MAX_USER_CONNECTIONS, MAX_CONNECTIONS, MAX_QUESTIONS, MAX_UPDATES, /*!50706 AUTHENTICATION_STRING AS */ PASSWORD /*!50508 , PLUGIN */ FROM mysql.user WHERE CONCAT(user, '@', host) = '#{name}'"
15+
if mysqld_version.nil?
16+
## Default ...
17+
query = "SELECT MAX_USER_CONNECTIONS, MAX_CONNECTIONS, MAX_QUESTIONS, MAX_UPDATES, PASSWORD /*!50508 , PLUGIN */ FROM mysql.user WHERE CONCAT(user, '@', host) = '#{name}'"
18+
else
19+
if mysqld_type == "mysql" and Puppet::Util::Package.versioncmp(mysqld_version, '5.7.6') >= 0
20+
query = "SELECT MAX_USER_CONNECTIONS, MAX_CONNECTIONS, MAX_QUESTIONS, MAX_UPDATES, AUTHENTICATION_STRING, PLUGIN FROM mysql.user WHERE CONCAT(user, '@', host) = '#{name}'"
21+
else
22+
query = "SELECT MAX_USER_CONNECTIONS, MAX_CONNECTIONS, MAX_QUESTIONS, MAX_UPDATES, PASSWORD /*!50508 , PLUGIN */ FROM mysql.user WHERE CONCAT(user, '@', host) = '#{name}'"
23+
end
24+
end
1625
@max_user_connections, @max_connections_per_hour, @max_queries_per_hour,
1726
@max_updates_per_hour, @password, @plugin = mysql([defaults_file, "-NBe", query].compact).split(/\s/)
1827

@@ -51,7 +60,11 @@ def create
5160
# Use CREATE USER to be compatible with NO_AUTO_CREATE_USER sql_mode
5261
# This is also required if you want to specify a authentication plugin
5362
if !plugin.nil?
54-
mysql([defaults_file, '-e', "CREATE USER '#{merged_name}' IDENTIFIED WITH '#{plugin}'"].compact)
63+
if plugin == 'sha256_password' and !password_hash.nil?
64+
mysql([defaults_file, '-e', "CREATE USER '#{merged_name}' IDENTIFIED WITH '#{plugin}' AS '#{password_hash}'"].compact)
65+
else
66+
mysql([defaults_file, '-e', "CREATE USER '#{merged_name}' IDENTIFIED WITH '#{plugin}'"].compact)
67+
end
5568
@property_hash[:ensure] = :present
5669
@property_hash[:plugin] = plugin
5770
else
@@ -89,7 +102,24 @@ def exists?
89102

90103
def password_hash=(string)
91104
merged_name = self.class.cmd_user(@resource[:name])
92-
mysql([defaults_file, '-e', "SET PASSWORD FOR #{merged_name} = '#{string}'"].compact)
105+
106+
# We have a fact for the mysql version ...
107+
if mysqld_version.nil?
108+
# default ... if mysqld_version does not work
109+
mysql([defaults_file, '-e', "SET PASSWORD FOR #{merged_name} = '#{string}'"].compact)
110+
else
111+
# Version >= 5.7.6 (many password related changes)
112+
if mysqld_type == "mysql" and Puppet::Util::Package.versioncmp(mysqld_version, '5.7.6') >= 0
113+
if string.match(/^\*/)
114+
mysql([defaults_file, '-e', "ALTER USER #{merged_name} IDENTIFIED WITH mysql_native_password AS '#{string}'"].compact)
115+
else
116+
raise ArgumentError, "Only mysql_native_password (*ABCD...XXX) hashes are supported"
117+
end
118+
else
119+
# older versions
120+
mysql([defaults_file, '-e', "SET PASSWORD FOR #{merged_name} = '#{string}'"].compact)
121+
end
122+
end
93123

94124
password_hash == string ? (return true) : (return false)
95125
end

lib/puppet/type/mysql_datadir.rb

+30
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
Puppet::Type.newtype(:mysql_datadir) do
2+
@doc = 'Manage MySQL datadirs with mysql_install_db OR mysqld (5.7.6 and above).'
3+
4+
ensurable
5+
6+
autorequire(:package) { 'mysql-server' }
7+
8+
newparam(:datadir, :namevar => true) do
9+
desc "The datadir name"
10+
end
11+
12+
newparam(:basedir) do
13+
desc 'The basedir name, default /usr.'
14+
newvalues(/^\//)
15+
end
16+
17+
newparam(:user) do
18+
desc 'The user for the directory default mysql (name, not uid).'
19+
end
20+
21+
newparam(:defaults_extra_file) do
22+
desc "MySQL defaults-extra-file with absolute path (*.cnf)."
23+
newvalues(/^\/.*\.cnf$/)
24+
end
25+
26+
newparam(:insecure, :boolean => true) do
27+
desc "Insecure initialization (needed for 5.7.6++)."
28+
end
29+
30+
end

manifests/params.pp

+15-1
Original file line numberDiff line numberDiff line change
@@ -376,6 +376,21 @@
376376
'log-error' => $mysql::params::log_error,
377377
'socket' => $mysql::params::socket,
378378
},
379+
'mysqld-5.0' => {
380+
'myisam-recover' => 'BACKUP',
381+
},
382+
'mysqld-5.1' => {
383+
'myisam-recover' => 'BACKUP',
384+
},
385+
'mysqld-5.5' => {
386+
'myisam-recover' => 'BACKUP',
387+
},
388+
'mysqld-5.6' => {
389+
'myisam-recover-options' => 'BACKUP',
390+
},
391+
'mysqld-5.7' => {
392+
'myisam-recover-options' => 'BACKUP',
393+
},
379394
'mysqld' => {
380395
'basedir' => $mysql::params::basedir,
381396
'bind-address' => '127.0.0.1',
@@ -386,7 +401,6 @@
386401
'max_allowed_packet' => '16M',
387402
'max_binlog_size' => '100M',
388403
'max_connections' => '151',
389-
'myisam_recover' => 'BACKUP',
390404
'pid-file' => $mysql::params::pidfile,
391405
'port' => '3306',
392406
'query_cache_limit' => '1M',

manifests/server/installdb.pp

+9-9
Original file line numberDiff line numberDiff line change
@@ -10,21 +10,21 @@
1010
$config_file = $mysql::server::config_file
1111

1212
if $mysql::server::manage_config_file {
13-
$install_db_args = "--basedir=${basedir} --defaults-extra-file=${config_file} --datadir=${datadir} --user=${mysqluser}"
13+
$_config_file=$config_file
1414
} else {
15-
$install_db_args = "--basedir=${basedir} --datadir=${datadir} --user=${mysqluser}"
15+
$_config_file=undef
1616
}
1717

18-
exec { 'mysql_install_db':
19-
command => "mysql_install_db ${install_db_args}",
20-
creates => "${datadir}/mysql",
21-
logoutput => on_failure,
22-
path => '/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin',
23-
require => Package['mysql-server'],
18+
mysql_datadir { $datadir:
19+
ensure => 'present',
20+
datadir => $datadir,
21+
basedir => $basedir,
22+
user => $mysqluser,
23+
defaults_extra_file => $_config_file,
2424
}
2525

2626
if $mysql::server::restart {
27-
Exec['mysql_install_db'] {
27+
Mysql_datadir[$datadir] {
2828
notify => Class['mysql::server::service'],
2929
}
3030
}

spec/classes/mysql_server_spec.rb

+1-1
Original file line numberDiff line numberDiff line change
@@ -43,7 +43,7 @@
4343
end
4444
context 'with datadir overridden' do
4545
let(:params) {{ :override_options => { 'mysqld' => { 'datadir' => '/tmp' }} }}
46-
it { is_expected.to contain_exec('mysql_install_db') }
46+
it { is_expected.to contain_mysql_datadir('/tmp') }
4747
end
4848
end
4949

0 commit comments

Comments
 (0)