diff --git a/README.md b/README.md index 9961d6d..e0d7671 100644 --- a/README.md +++ b/README.md @@ -85,6 +85,8 @@ replicate-do-db = base1 replicate-do-db = base2 ~~~ +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. + ### Creating a database To use `mysql::db` to create a database with a user and assign some privileges: @@ -181,6 +183,7 @@ mysql::db { 'mydb': #### Private classes * `mysql::server::install`: Installs packages. +* `mysql::server::installdb`: Implements setup of mysqld data directory (e.g. /var/lib/mysql) * `mysql::server::config`: Configures MYSQL. * `mysql::server::service`: Manages service. * `mysql::server::account_security`: Deletes default MySQL accounts. @@ -805,6 +808,17 @@ The name of the MySQL plugin to manage. The library file name. +#### `mysql_datadir` + +Initializes the MySQL data directory with version specific code. Pre MySQL 5.7.6 +it uses mysql_install_db. After MySQL 5.7.6 it uses mysqld --initialize-insecure. + +Insecure initialization is needed, as mysqld version 5.7 introduced "secure by default" mode. +This means MySQL generates a random password and writes it to STDOUT. This means puppet +can never accesss the database server afterwards, as no credencials are available. + +This type is an internal type and should not be called directly. + ### Facts #### `mysql_version` diff --git a/lib/puppet/provider/mysql.rb b/lib/puppet/provider/mysql.rb index 9b34ca0..5e6dcd5 100644 --- a/lib/puppet/provider/mysql.rb +++ b/lib/puppet/provider/mysql.rb @@ -3,6 +3,7 @@ class Puppet::Provider::Mysql < Puppet::Provider # Without initvars commands won't work. initvars commands :mysql => 'mysql' + commands :mysqld => 'mysqld' commands :mysqladmin => 'mysqladmin' # Optional defaults file @@ -13,7 +14,41 @@ class Puppet::Provider::Mysql < Puppet::Provider nil end end - + + def self.mysqld_type + # find the mysql "dialect" like mariadb / mysql etc. + mysqld_version_string.scan(/\s\(mariadb/i) { return "mariadb" } + mysqld_version_string.scan(/\s\(mysql/i) { return "mysql" } + mysqld_version_string.scan(/\s\(percona/i) { return "percona" } + nil + end + + def mysqld_type + self.class.mysqld_type + end + + def self.mysqld_version_string + # we cache the result ... + return @mysqld_version_string unless @mysqld_version_string.nil? + @mysqld_version_string = mysqld(['-V'].compact) + return @mysqld_version_string + end + + def mysqld_version_string + self.class.mysqld_version_string + end + + def self.mysqld_version + # note: be prepared for '5.7.6-rc-log' etc results + # versioncmp detects 5.7.6-log to be newer then 5.7.6 + # this is why we need the trimming. + mysqld_version_string.scan(/\d+\.\d+\.\d+/).first unless mysqld_version_string.nil? + end + + def mysqld_version + self.class.mysqld_version + end + def defaults_file self.class.defaults_file end diff --git a/lib/puppet/provider/mysql_datadir/mysql.rb b/lib/puppet/provider/mysql_datadir/mysql.rb new file mode 100644 index 0000000..f066e1e --- /dev/null +++ b/lib/puppet/provider/mysql_datadir/mysql.rb @@ -0,0 +1,65 @@ +require File.expand_path(File.join(File.dirname(__FILE__), '..', 'mysql')) +Puppet::Type.type(:mysql_datadir).provide(:mysql, :parent => Puppet::Provider::Mysql) do + + desc 'manage data directories for mysql instances' + + commands :mysqld => 'mysqld' + commands :mysql_install_db => 'mysql_install_db' + + def create + name = @resource[:name] + insecure = @resource.value(:insecure) || true + defaults_extra_file = @resource.value(:defaults_extra_file) + user = @resource.value(:user) || "mysql" + basedir = @resource.value(:basedir) || "/usr" + datadir = @resource.value(:datadir) || @resource[:name] + + unless defaults_extra_file.nil? + if File.exist?(defaults_extra_file) + defaults_extra_file="--defaults-extra-file=#{defaults_extra_file}" + else + raise ArgumentError, "Defaults-extra-file #{defaults_extra_file} is missing" + end + end + + if insecure == true + initialize="--initialize-insecure" + else + initialize="--initialize" + end + + if mysqld_version.nil? + debug("Installing MySQL data directory with mysql_install_db --basedir=#{basedir} #{defaults_extra_file} --datadir=#{datadir} --user=#{user}") + mysql_install_db(["--basedir=#{basedir}",defaults_extra_file, "--datadir=#{datadir}", "--user=#{user}"].compact) + else + if mysqld_type == "mysql" and Puppet::Util::Package.versioncmp(mysqld_version, '5.7.6') >= 0 + debug("Initializing MySQL data directory >= 5.7.6 with 'mysqld #{defaults_extra_file} #{initialize} --basedir=#{basedir} --datadir=#{datadir} --user=#{user}'") + mysqld([defaults_extra_file,initialize,"--basedir=#{basedir}","--datadir=#{datadir}", "--user=#{user}", "--log_error=/var/tmp/mysqld_initialize.log"].compact) + else + debug("Installing MySQL data directory with mysql_install_db --basedir=#{basedir} #{defaults_extra_file} --datadir=#{datadir} --user=#{user}") + mysql_install_db(["--basedir=#{basedir}",defaults_extra_file, "--datadir=#{datadir}", "--user=#{user}"].compact) + end + end + + exists? + end + + def destroy + name = @resource[:name] + raise ArgumentError, "ERROR: Resource can not be removed" + end + + def exists? + datadir = @resource[:datadir] + File.directory?("#{datadir}/mysql") + end + + ## + ## MySQL datadir properties + ## + + # Generates method for all properties of the property_hash + mk_resource_methods + +end + diff --git a/lib/puppet/provider/mysql_user/mysql.rb b/lib/puppet/provider/mysql_user/mysql.rb index 4ba194b..bc4014f 100644 --- a/lib/puppet/provider/mysql_user/mysql.rb +++ b/lib/puppet/provider/mysql_user/mysql.rb @@ -12,7 +12,16 @@ Puppet::Type.type(:mysql_user).provide(:mysql, :parent => Puppet::Provider::Mysq # To reduce the number of calls to MySQL we collect all the properties in # one big swoop. users.collect do |name| - 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}'" + if mysqld_version.nil? + ## Default ... + query = "SELECT MAX_USER_CONNECTIONS, MAX_CONNECTIONS, MAX_QUESTIONS, MAX_UPDATES, PASSWORD /*!50508 , PLUGIN */ FROM mysql.user WHERE CONCAT(user, '@', host) = '#{name}'" + else + if mysqld_type == "mysql" and Puppet::Util::Package.versioncmp(mysqld_version, '5.7.6') >= 0 + query = "SELECT MAX_USER_CONNECTIONS, MAX_CONNECTIONS, MAX_QUESTIONS, MAX_UPDATES, AUTHENTICATION_STRING, PLUGIN FROM mysql.user WHERE CONCAT(user, '@', host) = '#{name}'" + else + query = "SELECT MAX_USER_CONNECTIONS, MAX_CONNECTIONS, MAX_QUESTIONS, MAX_UPDATES, PASSWORD /*!50508 , PLUGIN */ FROM mysql.user WHERE CONCAT(user, '@', host) = '#{name}'" + end + end @max_user_connections, @max_connections_per_hour, @max_queries_per_hour, @max_updates_per_hour, @password, @plugin = mysql([defaults_file, "-NBe", query].compact).split(/\s/) @@ -51,7 +60,11 @@ Puppet::Type.type(:mysql_user).provide(:mysql, :parent => Puppet::Provider::Mysq # Use CREATE USER to be compatible with NO_AUTO_CREATE_USER sql_mode # This is also required if you want to specify a authentication plugin if !plugin.nil? - mysql([defaults_file, '-e', "CREATE USER '#{merged_name}' IDENTIFIED WITH '#{plugin}'"].compact) + if plugin == 'sha256_password' and !password_hash.nil? + mysql([defaults_file, '-e', "CREATE USER '#{merged_name}' IDENTIFIED WITH '#{plugin}' AS '#{password_hash}'"].compact) + else + mysql([defaults_file, '-e', "CREATE USER '#{merged_name}' IDENTIFIED WITH '#{plugin}'"].compact) + end @property_hash[:ensure] = :present @property_hash[:plugin] = plugin else @@ -89,7 +102,24 @@ Puppet::Type.type(:mysql_user).provide(:mysql, :parent => Puppet::Provider::Mysq def password_hash=(string) merged_name = self.class.cmd_user(@resource[:name]) - mysql([defaults_file, '-e', "SET PASSWORD FOR #{merged_name} = '#{string}'"].compact) + + # We have a fact for the mysql version ... + if mysqld_version.nil? + # default ... if mysqld_version does not work + mysql([defaults_file, '-e', "SET PASSWORD FOR #{merged_name} = '#{string}'"].compact) + else + # Version >= 5.7.6 (many password related changes) + if mysqld_type == "mysql" and Puppet::Util::Package.versioncmp(mysqld_version, '5.7.6') >= 0 + if string.match(/^\*/) + mysql([defaults_file, '-e', "ALTER USER #{merged_name} IDENTIFIED WITH mysql_native_password AS '#{string}'"].compact) + else + raise ArgumentError, "Only mysql_native_password (*ABCD...XXX) hashes are supported" + end + else + # older versions + mysql([defaults_file, '-e', "SET PASSWORD FOR #{merged_name} = '#{string}'"].compact) + end + end password_hash == string ? (return true) : (return false) end diff --git a/lib/puppet/type/mysql_datadir.rb b/lib/puppet/type/mysql_datadir.rb new file mode 100644 index 0000000..156b827 --- /dev/null +++ b/lib/puppet/type/mysql_datadir.rb @@ -0,0 +1,30 @@ +Puppet::Type.newtype(:mysql_datadir) do + @doc = 'Manage MySQL datadirs with mysql_install_db OR mysqld (5.7.6 and above).' + + ensurable + + autorequire(:package) { 'mysql-server' } + + newparam(:datadir, :namevar => true) do + desc "The datadir name" + end + + newparam(:basedir) do + desc 'The basedir name, default /usr.' + newvalues(/^\//) + end + + newparam(:user) do + desc 'The user for the directory default mysql (name, not uid).' + end + + newparam(:defaults_extra_file) do + desc "MySQL defaults-extra-file with absolute path (*.cnf)." + newvalues(/^\/.*\.cnf$/) + end + + newparam(:insecure, :boolean => true) do + desc "Insecure initialization (needed for 5.7.6++)." + end + +end diff --git a/manifests/params.pp b/manifests/params.pp index a81aa52..363bda9 100644 --- a/manifests/params.pp +++ b/manifests/params.pp @@ -376,6 +376,21 @@ class mysql::params { 'log-error' => $mysql::params::log_error, 'socket' => $mysql::params::socket, }, + 'mysqld-5.0' => { + 'myisam-recover' => 'BACKUP', + }, + 'mysqld-5.1' => { + 'myisam-recover' => 'BACKUP', + }, + 'mysqld-5.5' => { + 'myisam-recover' => 'BACKUP', + }, + 'mysqld-5.6' => { + 'myisam-recover-options' => 'BACKUP', + }, + 'mysqld-5.7' => { + 'myisam-recover-options' => 'BACKUP', + }, 'mysqld' => { 'basedir' => $mysql::params::basedir, 'bind-address' => '127.0.0.1', @@ -386,7 +401,6 @@ class mysql::params { 'max_allowed_packet' => '16M', 'max_binlog_size' => '100M', 'max_connections' => '151', - 'myisam_recover' => 'BACKUP', 'pid-file' => $mysql::params::pidfile, 'port' => '3306', 'query_cache_limit' => '1M', diff --git a/manifests/server/installdb.pp b/manifests/server/installdb.pp index de4772e..78e08f5 100644 --- a/manifests/server/installdb.pp +++ b/manifests/server/installdb.pp @@ -10,21 +10,21 @@ class mysql::server::installdb { $config_file = $mysql::server::config_file if $mysql::server::manage_config_file { - $install_db_args = "--basedir=${basedir} --defaults-extra-file=${config_file} --datadir=${datadir} --user=${mysqluser}" + $_config_file=$config_file } else { - $install_db_args = "--basedir=${basedir} --datadir=${datadir} --user=${mysqluser}" + $_config_file=undef } - exec { 'mysql_install_db': - command => "mysql_install_db ${install_db_args}", - creates => "${datadir}/mysql", - logoutput => on_failure, - path => '/bin:/sbin:/usr/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin', - require => Package['mysql-server'], + mysql_datadir { $datadir: + ensure => 'present', + datadir => $datadir, + basedir => $basedir, + user => $mysqluser, + defaults_extra_file => $_config_file, } if $mysql::server::restart { - Exec['mysql_install_db'] { + Mysql_datadir[$datadir] { notify => Class['mysql::server::service'], } } diff --git a/spec/classes/mysql_server_spec.rb b/spec/classes/mysql_server_spec.rb index 0625895..edcdb49 100644 --- a/spec/classes/mysql_server_spec.rb +++ b/spec/classes/mysql_server_spec.rb @@ -43,7 +43,7 @@ describe 'mysql::server' do end context 'with datadir overridden' do let(:params) {{ :override_options => { 'mysqld' => { 'datadir' => '/tmp' }} }} - it { is_expected.to contain_exec('mysql_install_db') } + it { is_expected.to contain_mysql_datadir('/tmp') } end end diff --git a/spec/unit/puppet/provider/mysql_user/mysql_spec.rb b/spec/unit/puppet/provider/mysql_user/mysql_spec.rb index aec7593..7eff67f 100644 --- a/spec/unit/puppet/provider/mysql_user/mysql_spec.rb +++ b/spec/unit/puppet/provider/mysql_user/mysql_spec.rb @@ -1,6 +1,47 @@ require 'spec_helper' describe Puppet::Type.type(:mysql_user).provider(:mysql) do + + # Output of mysqld -V + mysql_version_string_hash = { + 'mysql-5.5' => + { + :version => '5.5.46', + :string => '/usr/sbin/mysqld Ver 5.5.46-log for Linux on x86_64 (MySQL Community Server (GPL))', + :mysql_type => 'mysql', + }, + 'mysql-5.6' => + { + :version => '5.6.27', + :string => '/usr/sbin/mysqld Ver 5.6.27 for Linux on x86_64 (MySQL Community Server (GPL))', + :mysql_type => 'mysql', + }, + 'mysql-5.7.1' => + { + :version => '5.7.1', + :string => '/usr/sbin/mysqld Ver 5.7.1 for Linux on x86_64 (MySQL Community Server (GPL))', + :mysql_type => 'mysql', + }, + 'mysql-5.7.6' => + { + :version => '5.7.8', + :string => '/usr/sbin/mysqld Ver 5.7.8-rc for Linux on x86_64 (MySQL Community Server (GPL))', + :mysql_type => 'mysql', + }, + 'mariadb-10.0' => + { + :version => '10.0.21', + :string => '/usr/sbin/mysqld Ver 10.0.21-MariaDB for Linux on x86_64 (MariaDB Server)', + :mysql_type => 'mariadb', + }, + 'percona-5.5' => + { + :version => '5.5.39', + :string => 'mysqld Ver 5.5.39-36.0-55 for Linux on x86_64 (Percona XtraDB Cluster (GPL), Release rel36.0, Revision 824, WSREP version 25.11, wsrep_25.11.r4023)', + :mysql_type => 'percona', + }, + } + let(:defaults_file) { '--defaults-extra-file=/root/.my.cnf' } let(:newhash) { '*6C8989366EAF75BB670AD8EA7A7FC1176A95CEF5' } @@ -35,24 +76,90 @@ usvn_user@localhost # Set up the stubs for an instances call. Facter.stubs(:value).with(:root_home).returns('/root') Facter.stubs(:value).with(:mysql_version).returns('5.6.24') + provider.class.instance_variable_set(:@mysqld_version_string, '5.6.24') Puppet::Util.stubs(:which).with('mysql').returns('/usr/bin/mysql') + Puppet::Util.stubs(:which).with('mysqld').returns('/usr/sbin/mysqld') File.stubs(:file?).with('/root/.my.cnf').returns(true) provider.class.stubs(:mysql).with([defaults_file, '-NBe', "SELECT CONCAT(User, '@',Host) AS User FROM mysql.user"]).returns('joe@localhost') - provider.class.stubs(:mysql).with([defaults_file, '-NBe', "SELECT MAX_USER_CONNECTIONS, MAX_CONNECTIONS, MAX_QUESTIONS, MAX_UPDATES, /*!50706 AUTHENTICATION_STRING AS */ PASSWORD /*!50508 , PLUGIN */ FROM mysql.user WHERE CONCAT(user, '@', host) = 'joe@localhost'"]).returns('10 10 10 10 *6C8989366EAF75BB670AD8EA7A7FC1176A95CEF4') + provider.class.stubs(:mysql).with([defaults_file, '-NBe', "SELECT MAX_USER_CONNECTIONS, MAX_CONNECTIONS, MAX_QUESTIONS, MAX_UPDATES, PASSWORD /*!50508 , PLUGIN */ FROM mysql.user WHERE CONCAT(user, '@', host) = 'joe@localhost'"]).returns('10 10 10 10 *6C8989366EAF75BB670AD8EA7A7FC1176A95CEF4') end let(:instance) { provider.class.instances.first } describe 'self.instances' do - it 'returns an array of users' do + it 'returns an array of users MySQL 5.5' do + provider.class.instance_variable_set(:@mysqld_version_string, mysql_version_string_hash['mysql-5.5'][:string]) provider.class.stubs(:mysql).with([defaults_file, '-NBe', "SELECT CONCAT(User, '@',Host) AS User FROM mysql.user"]).returns(raw_users) parsed_users.each do |user| - provider.class.stubs(:mysql).with([defaults_file, '-NBe', "SELECT MAX_USER_CONNECTIONS, MAX_CONNECTIONS, MAX_QUESTIONS, MAX_UPDATES, /*!50706 AUTHENTICATION_STRING AS */ PASSWORD /*!50508 , PLUGIN */ FROM mysql.user WHERE CONCAT(user, '@', host) = '#{user}'"]).returns('10 10 10 10 ') + provider.class.stubs(:mysql).with([defaults_file, '-NBe', "SELECT MAX_USER_CONNECTIONS, MAX_CONNECTIONS, MAX_QUESTIONS, MAX_UPDATES, PASSWORD /*!50508 , PLUGIN */ FROM mysql.user WHERE CONCAT(user, '@', host) = '#{user}'"]).returns('10 10 10 10 ') end usernames = provider.class.instances.collect {|x| x.name } expect(parsed_users).to match_array(usernames) end + it 'returns an array of users MySQL 5.6' do + provider.class.instance_variable_set(:@mysqld_version_string, mysql_version_string_hash['mysql-5.6'][:string]) + provider.class.stubs(:mysql).with([defaults_file, '-NBe', "SELECT CONCAT(User, '@',Host) AS User FROM mysql.user"]).returns(raw_users) + parsed_users.each do |user| + provider.class.stubs(:mysql).with([defaults_file, '-NBe', "SELECT MAX_USER_CONNECTIONS, MAX_CONNECTIONS, MAX_QUESTIONS, MAX_UPDATES, PASSWORD /*!50508 , PLUGIN */ FROM mysql.user WHERE CONCAT(user, '@', host) = '#{user}'"]).returns('10 10 10 10 ') + end + + usernames = provider.class.instances.collect {|x| x.name } + expect(parsed_users).to match_array(usernames) + end + it 'returns an array of users MySQL >= 5.7.0 < 5.7.6' do + provider.class.instance_variable_set(:@mysqld_version_string, mysql_version_string_hash['mysql-5.7.1'][:string]) + provider.class.stubs(:mysql).with([defaults_file, '-NBe', "SELECT CONCAT(User, '@',Host) AS User FROM mysql.user"]).returns(raw_users) + parsed_users.each do |user| + provider.class.stubs(:mysql).with([defaults_file, '-NBe', "SELECT MAX_USER_CONNECTIONS, MAX_CONNECTIONS, MAX_QUESTIONS, MAX_UPDATES, PASSWORD /*!50508 , PLUGIN */ FROM mysql.user WHERE CONCAT(user, '@', host) = '#{user}'"]).returns('10 10 10 10 ') + end + + usernames = provider.class.instances.collect {|x| x.name } + expect(parsed_users).to match_array(usernames) + end + it 'returns an array of users MySQL >= 5.7.6' do + provider.class.instance_variable_set(:@mysqld_version_string, mysql_version_string_hash['mysql-5.7.6'][:string]) + provider.class.stubs(:mysql).with([defaults_file, '-NBe', "SELECT CONCAT(User, '@',Host) AS User FROM mysql.user"]).returns(raw_users) + parsed_users.each do |user| + provider.class.stubs(:mysql).with([defaults_file, '-NBe', "SELECT MAX_USER_CONNECTIONS, MAX_CONNECTIONS, MAX_QUESTIONS, MAX_UPDATES, AUTHENTICATION_STRING, PLUGIN FROM mysql.user WHERE CONCAT(user, '@', host) = '#{user}'"]).returns('10 10 10 10 ') + end + + usernames = provider.class.instances.collect {|x| x.name } + expect(parsed_users).to match_array(usernames) + end + it 'returns an array of users mariadb 10.0' do + provider.class.instance_variable_set(:@mysqld_version_string, mysql_version_string_hash['mariadb-10.0'][:string]) + provider.class.stubs(:mysql).with([defaults_file, '-NBe', "SELECT CONCAT(User, '@',Host) AS User FROM mysql.user"]).returns(raw_users) + parsed_users.each do |user| + provider.class.stubs(:mysql).with([defaults_file, '-NBe', "SELECT MAX_USER_CONNECTIONS, MAX_CONNECTIONS, MAX_QUESTIONS, MAX_UPDATES, PASSWORD /*!50508 , PLUGIN */ FROM mysql.user WHERE CONCAT(user, '@', host) = '#{user}'"]).returns('10 10 10 10 ') + end + + usernames = provider.class.instances.collect {|x| x.name } + expect(parsed_users).to match_array(usernames) + end + it 'returns an array of users percona 5.5' do + provider.class.instance_variable_set(:@mysqld_version_string, mysql_version_string_hash['percona-5.5'][:string]) + provider.class.stubs(:mysql).with([defaults_file, '-NBe', "SELECT CONCAT(User, '@',Host) AS User FROM mysql.user"]).returns(raw_users) + parsed_users.each do |user| + provider.class.stubs(:mysql).with([defaults_file, '-NBe', "SELECT MAX_USER_CONNECTIONS, MAX_CONNECTIONS, MAX_QUESTIONS, MAX_UPDATES, PASSWORD /*!50508 , PLUGIN */ FROM mysql.user WHERE CONCAT(user, '@', host) = '#{user}'"]).returns('10 10 10 10 ') + end + + usernames = provider.class.instances.collect {|x| x.name } + expect(parsed_users).to match_array(usernames) + end + end + + describe 'mysql version and type detection' do + mysql_version_string_hash.each do |name,line| + version=line[:version] + string=line[:string] + mysql_type=line[:mysql_type] + it "detects type '#{mysql_type}' with version '#{version}'" do + provider.class.instance_variable_set(:@mysqld_version_string, string) + expect(provider.mysqld_version).to eq(version) + expect(provider.mysqld_type).to eq(mysql_type) + end + end end describe 'self.prefetch' do @@ -85,6 +192,30 @@ usvn_user@localhost end end + describe 'self.mysqld_version' do + it 'queries mysql if unset' do + provider.class.instance_variable_set(:@mysqld_version_string, nil) + provider.class.expects(:mysqld).with(['-V']) + expect(provider.mysqld_version).to be_nil + end + it 'returns 5.7.6 for "mysqld Ver 5.7.6 for Linux on x86_64 (MySQL Community Server (GPL))"' do + provider.class.instance_variable_set(:@mysqld_version_string, 'mysqld Ver 5.7.6 for Linux on x86_64 (MySQL Community Server (GPL))') + expect(provider.mysqld_version).to eq '5.7.6' + end + it 'returns 5.7.6 for "mysqld Ver 5.7.6-rc for Linux on x86_64 (MySQL Community Server (GPL))"' do + provider.class.instance_variable_set(:@mysqld_version_string, 'mysqld Ver 5.7.6-rc for Linux on x86_64 (MySQL Community Server (GPL))') + expect(provider.mysqld_version).to eq '5.7.6' + end + it 'detects >= 5.7.6 for 5.7.7-log' do + provider.class.instance_variable_set(:@mysqld_version_string, 'mysqld Ver 5.7.7-log for Linux on x86_64 (MySQL Community Server (GPL))') + expect(Puppet::Util::Package.versioncmp(provider.mysqld_version, '5.7.6')).to be >= 0 + end + it 'detects < 5.7.6 for 5.7.5-log' do + provider.class.instance_variable_set(:@mysqld_version_string, 'mysqld Ver 5.7.5-log for Linux on x86_64 (MySQL Community Server (GPL))') + expect(Puppet::Util::Package.versioncmp(provider.mysqld_version, '5.7.6')).to be < 0 + end + end + describe 'self.defaults_file' do it 'sets --defaults-extra-file' do File.stubs(:file?).with('/root/.my.cnf').returns(true) @@ -103,7 +234,43 @@ usvn_user@localhost end describe 'password_hash=' do - it 'changes the hash' do + it 'changes the hash mysql 5.5' do + provider.class.instance_variable_set(:@mysqld_version_string, mysql_version_string_hash['mysql-5.5'][:string]) + provider.expects(:mysql).with([defaults_file, '-e', "SET PASSWORD FOR 'joe'@'localhost' = '*6C8989366EAF75BB670AD8EA7A7FC1176A95CEF5'"]).returns('0') + + provider.expects(:password_hash).returns('*6C8989366EAF75BB670AD8EA7A7FC1176A95CEF5') + provider.password_hash=('*6C8989366EAF75BB670AD8EA7A7FC1176A95CEF5') + end + it 'changes the hash mysql 5.6' do + provider.class.instance_variable_set(:@mysqld_version_string, mysql_version_string_hash['mysql-5.6'][:string]) + provider.expects(:mysql).with([defaults_file, '-e', "SET PASSWORD FOR 'joe'@'localhost' = '*6C8989366EAF75BB670AD8EA7A7FC1176A95CEF5'"]).returns('0') + + provider.expects(:password_hash).returns('*6C8989366EAF75BB670AD8EA7A7FC1176A95CEF5') + provider.password_hash=('*6C8989366EAF75BB670AD8EA7A7FC1176A95CEF5') + end + it 'changes the hash mysql < 5.7.6' do + provider.class.instance_variable_set(:@mysqld_version_string, mysql_version_string_hash['mysql-5.7.1'][:string]) + provider.expects(:mysql).with([defaults_file, '-e', "SET PASSWORD FOR 'joe'@'localhost' = '*6C8989366EAF75BB670AD8EA7A7FC1176A95CEF5'"]).returns('0') + + provider.expects(:password_hash).returns('*6C8989366EAF75BB670AD8EA7A7FC1176A95CEF5') + provider.password_hash=('*6C8989366EAF75BB670AD8EA7A7FC1176A95CEF5') + end + it 'changes the hash MySQL >= 5.7.6' do + provider.class.instance_variable_set(:@mysqld_version_string, mysql_version_string_hash['mysql-5.7.6'][:string]) + provider.expects(:mysql).with([defaults_file, '-e', "ALTER USER 'joe'@'localhost' IDENTIFIED WITH mysql_native_password AS '*6C8989366EAF75BB670AD8EA7A7FC1176A95CEF5'"]).returns('0') + + provider.expects(:password_hash).returns('*6C8989366EAF75BB670AD8EA7A7FC1176A95CEF5') + provider.password_hash=('*6C8989366EAF75BB670AD8EA7A7FC1176A95CEF5') + end + it 'changes the hash mariadb-10.0' do + provider.class.instance_variable_set(:@mysqld_version_string, mysql_version_string_hash['mariadb-10.0'][:string]) + provider.expects(:mysql).with([defaults_file, '-e', "SET PASSWORD FOR 'joe'@'localhost' = '*6C8989366EAF75BB670AD8EA7A7FC1176A95CEF5'"]).returns('0') + + provider.expects(:password_hash).returns('*6C8989366EAF75BB670AD8EA7A7FC1176A95CEF5') + provider.password_hash=('*6C8989366EAF75BB670AD8EA7A7FC1176A95CEF5') + end + it 'changes the hash percona-5.5' do + provider.class.instance_variable_set(:@mysqld_version_string, mysql_version_string_hash['percona-5.5'][:string]) provider.expects(:mysql).with([defaults_file, '-e', "SET PASSWORD FOR 'joe'@'localhost' = '*6C8989366EAF75BB670AD8EA7A7FC1176A95CEF5'"]).returns('0') provider.expects(:password_hash).returns('*6C8989366EAF75BB670AD8EA7A7FC1176A95CEF5')