From 475f758178069760025549ad5c0a761ddaba4cd9 Mon Sep 17 00:00:00 2001 From: Arnaud Launay Date: Sun, 21 Jan 2024 13:43:14 +0100 Subject: [PATCH 1/4] Add support for ALL grant on mysql >= 8.0.33 (add the new TELEMETRY_LOG_ADMIN privilege) https://docs.oracle.com/cd/E17952_01/mysql-8.0-relnotes-en/news-8-0-33.html#mysqld-8-0-33-feature --- lib/puppet/provider/mysql_grant/mysql.rb | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/lib/puppet/provider/mysql_grant/mysql.rb b/lib/puppet/provider/mysql_grant/mysql.rb index 20af17151..10fb1ab22 100644 --- a/lib/puppet/provider/mysql_grant/mysql.rb +++ b/lib/puppet/provider/mysql_grant/mysql.rb @@ -91,8 +91,16 @@ def self.instances 'RESOURCE_GROUP_ADMIN', 'RESOURCE_GROUP_USER', 'ROLE_ADMIN', 'SENSITIVE_VARIABLES_OBSERVER', 'SERVICE_CONNECTION_ADMIN', 'SESSION_VARIABLES_ADMIN', 'SET_USER_ID', 'SHOW_ROUTINE', 'SYSTEM_USER', 'SYSTEM_VARIABLES_ADMIN', 'TABLE_ENCRYPTION_ADMIN', 'XA_RECOVER_ADMIN'] + mysql_pre_v8_privileges_three = ['ALL', 'APPLICATION_PASSWORD_ADMIN', 'AUDIT_ABORT_EXEMPT', 'AUDIT_ADMIN', 'AUTHENTICATION_POLICY_ADMIN', 'BACKUP_ADMIN', 'BINLOG_ADMIN', + 'BINLOG_ENCRYPTION_ADMIN', 'CLONE_ADMIN', 'CONNECTION_ADMIN', 'ENCRYPTION_KEY_ADMIN', 'FIREWALL_EXEMPT', 'FLUSH_OPTIMIZER_COSTS', 'FLUSH_STATUS', + 'FLUSH_TABLES', 'FLUSH_USER_RESOURCES', 'GROUP_REPLICATION_ADMIN', 'GROUP_REPLICATION_STREAM', 'INNODB_REDO_LOG_ARCHIVE', + 'INNODB_REDO_LOG_ENABLE', 'PASSWORDLESS_USER_ADMIN', 'PERSIST_RO_VARIABLES_ADMIN', 'REPLICATION_APPLIER', 'REPLICATION_SLAVE_ADMIN', + 'RESOURCE_GROUP_ADMIN', 'RESOURCE_GROUP_USER', 'ROLE_ADMIN', 'SENSITIVE_VARIABLES_OBSERVER', 'SERVICE_CONNECTION_ADMIN', + 'SESSION_VARIABLES_ADMIN', 'SET_USER_ID', 'SHOW_ROUTINE', 'SYSTEM_USER', 'SYSTEM_VARIABLES_ADMIN', 'TABLE_ENCRYPTION_ADMIN', 'TELEMETRY_LOG_ADMIN', + 'XA_RECOVER_ADMIN'] + # rubocop:disable Layout/LineLength - if (newer_than('mysql' => '8.0.0') && (sorted_privileges == mysql_v8_privileges || sorted_privileges == mysqlcluster_v8_privileges)) || sorted_privileges == mysql_pre_v8_privileges_one || sorted_privileges == mysql_pre_v8_privileges_two + if (newer_than('mysql' => '8.0.0') && (sorted_privileges == mysql_v8_privileges || sorted_privileges == mysqlcluster_v8_privileges)) || sorted_privileges == mysql_pre_v8_privileges_one || sorted_privileges == mysql_pre_v8_privileges_two || sorted_privileges == mysql_pre_v8_privileges_three sorted_privileges = ['ALL'] end # rubocop:enable Layout/LineLength From 040d16a72720d9ef21228d99fcff633a17d50f4b Mon Sep 17 00:00:00 2001 From: rahuls02997 Date: Wed, 18 Sep 2024 17:42:32 +0530 Subject: [PATCH 2/4] Fix mysql_users failing for SLES fix mistakes fix spec for the changed query --- lib/puppet/provider/mysql_user/mysql.rb | 3 ++- .../puppet/provider/mysql_user/mysql_spec.rb | 16 ++++++++-------- 2 files changed, 10 insertions(+), 9 deletions(-) diff --git a/lib/puppet/provider/mysql_user/mysql.rb b/lib/puppet/provider/mysql_user/mysql.rb index a381d6898..b552a5620 100644 --- a/lib/puppet/provider/mysql_user/mysql.rb +++ b/lib/puppet/provider/mysql_user/mysql.rb @@ -8,7 +8,8 @@ # Build a property_hash containing all the discovered information about MySQL # users. def self.instances - users = mysql_caller("SELECT CONCAT(User, '@',Host) AS User FROM mysql.user", 'regular').split("\n") + users = mysql_caller("SELECT CONCAT(User, '@',Host) AS User FROM mysql.user where HOST IS NOT NULL AND HOST != ''", 'regular').split("\n") + # users = users_full.reject { |user| user == 'PUBLIC@' } # To reduce the number of calls to MySQL we collect all the properties in # one big swoop. users.map do |name| diff --git a/spec/unit/puppet/provider/mysql_user/mysql_spec.rb b/spec/unit/puppet/provider/mysql_user/mysql_spec.rb index 6a900f8ae..2617e256c 100644 --- a/spec/unit/puppet/provider/mysql_user/mysql_spec.rb +++ b/spec/unit/puppet/provider/mysql_user/mysql_spec.rb @@ -101,14 +101,14 @@ allow(Puppet::Util).to receive(:which).with('mysql').and_return('/usr/bin/mysql') allow(Puppet::Util).to receive(:which).with('mysqld').and_return('/usr/sbin/mysqld') allow(File).to receive(:file?).with('/root/.my.cnf').and_return(true) - allow(provider.class).to receive(:mysql_caller).with("SELECT CONCAT(User, '@',Host) AS User FROM mysql.user", 'regular').and_return('joe@localhost') + allow(provider.class).to receive(:mysql_caller).with("SELECT CONCAT(User, '@',Host) AS User FROM mysql.user where HOST IS NOT NULL AND HOST != ''", 'regular').and_return('joe@localhost') allow(provider.class).to receive(:mysql_caller).with("SELECT MAX_USER_CONNECTIONS, MAX_CONNECTIONS, MAX_QUESTIONS, MAX_UPDATES, SSL_TYPE, SSL_CIPHER, X509_ISSUER, X509_SUBJECT, PASSWORD /*!50508 , PLUGIN */ FROM mysql.user WHERE CONCAT(user, '@', host) = 'joe@localhost'", 'regular').and_return('10 10 10 10 *6C8989366EAF75BB670AD8EA7A7FC1176A95CEF4') # rubocop:disable Layout/LineLength end describe 'self.instances' 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]) - allow(provider.class).to receive(:mysql_caller).with("SELECT CONCAT(User, '@',Host) AS User FROM mysql.user", 'regular').and_return(raw_users) + allow(provider.class).to receive(:mysql_caller).with("SELECT CONCAT(User, '@',Host) AS User FROM mysql.user where HOST IS NOT NULL AND HOST != ''", 'regular').and_return(raw_users) parsed_users.each { |user| allow(provider.class).to receive(:mysql_caller).with("SELECT MAX_USER_CONNECTIONS, MAX_CONNECTIONS, MAX_QUESTIONS, MAX_UPDATES, SSL_TYPE, SSL_CIPHER, X509_ISSUER, X509_SUBJECT, PASSWORD /*!50508 , PLUGIN */ FROM mysql.user WHERE CONCAT(user, '@', host) = '#{user}'", 'regular').and_return('10 10 10 10 ') } # rubocop:disable Layout/LineLength usernames = provider.class.instances.map(&:name) @@ -117,7 +117,7 @@ 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]) - allow(provider.class).to receive(:mysql_caller).with("SELECT CONCAT(User, '@',Host) AS User FROM mysql.user", 'regular').and_return(raw_users) + allow(provider.class).to receive(:mysql_caller).with("SELECT CONCAT(User, '@',Host) AS User FROM mysql.user where HOST IS NOT NULL AND HOST != ''", 'regular').and_return(raw_users) parsed_users.each { |user| allow(provider.class).to receive(:mysql_caller).with("SELECT MAX_USER_CONNECTIONS, MAX_CONNECTIONS, MAX_QUESTIONS, MAX_UPDATES, SSL_TYPE, SSL_CIPHER, X509_ISSUER, X509_SUBJECT, PASSWORD /*!50508 , PLUGIN */ FROM mysql.user WHERE CONCAT(user, '@', host) = '#{user}'", 'regular').and_return('10 10 10 10 ') } # rubocop:disable Layout/LineLength usernames = provider.class.instances.map(&:name) @@ -126,7 +126,7 @@ 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]) - allow(provider.class).to receive(:mysql_caller).with("SELECT CONCAT(User, '@',Host) AS User FROM mysql.user", 'regular').and_return(raw_users) + allow(provider.class).to receive(:mysql_caller).with("SELECT CONCAT(User, '@',Host) AS User FROM mysql.user where HOST IS NOT NULL AND HOST != ''", 'regular').and_return(raw_users) parsed_users.each { |user| allow(provider.class).to receive(:mysql_caller).with("SELECT MAX_USER_CONNECTIONS, MAX_CONNECTIONS, MAX_QUESTIONS, MAX_UPDATES, SSL_TYPE, SSL_CIPHER, X509_ISSUER, X509_SUBJECT, PASSWORD /*!50508 , PLUGIN */ FROM mysql.user WHERE CONCAT(user, '@', host) = '#{user}'", 'regular').and_return('10 10 10 10 ') } # rubocop:disable Layout/LineLength usernames = provider.class.instances.map(&:name) @@ -135,7 +135,7 @@ 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]) - allow(provider.class).to receive(:mysql_caller).with("SELECT CONCAT(User, '@',Host) AS User FROM mysql.user", 'regular').and_return(raw_users) + allow(provider.class).to receive(:mysql_caller).with("SELECT CONCAT(User, '@',Host) AS User FROM mysql.user where HOST IS NOT NULL AND HOST != ''", 'regular').and_return(raw_users) parsed_users.each { |user| allow(provider.class).to receive(:mysql_caller).with("SELECT MAX_USER_CONNECTIONS, MAX_CONNECTIONS, MAX_QUESTIONS, MAX_UPDATES, SSL_TYPE, SSL_CIPHER, X509_ISSUER, X509_SUBJECT, AUTHENTICATION_STRING, PLUGIN FROM mysql.user WHERE CONCAT(user, '@', host) = '#{user}'", 'regular').and_return('10 10 10 10 ') } # rubocop:disable Layout/LineLength usernames = provider.class.instances.map(&:name) @@ -144,7 +144,7 @@ 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]) - allow(provider.class).to receive(:mysql_caller).with("SELECT CONCAT(User, '@',Host) AS User FROM mysql.user", 'regular').and_return(raw_users) + allow(provider.class).to receive(:mysql_caller).with("SELECT CONCAT(User, '@',Host) AS User FROM mysql.user where HOST IS NOT NULL AND HOST != ''", 'regular').and_return(raw_users) parsed_users.each { |user| allow(provider.class).to receive(:mysql_caller).with("SELECT MAX_USER_CONNECTIONS, MAX_CONNECTIONS, MAX_QUESTIONS, MAX_UPDATES, SSL_TYPE, SSL_CIPHER, X509_ISSUER, X509_SUBJECT, PASSWORD /*!50508 , PLUGIN */ FROM mysql.user WHERE CONCAT(user, '@', host) = '#{user}'", 'regular').and_return('10 10 10 10 ') } # rubocop:disable Layout/LineLength usernames = provider.class.instances.map(&:name) @@ -153,7 +153,7 @@ it 'returns an array of users mariadb >= 10.1.21' do provider.class.instance_variable_set(:@mysqld_version_string, mysql_version_string_hash['mariadb-10.1.44'][:string]) - allow(provider.class).to receive(:mysql_caller).with("SELECT CONCAT(User, '@',Host) AS User FROM mysql.user", 'regular').and_return(raw_users) + allow(provider.class).to receive(:mysql_caller).with("SELECT CONCAT(User, '@',Host) AS User FROM mysql.user where HOST IS NOT NULL AND HOST != ''", 'regular').and_return(raw_users) parsed_users.each { |user| allow(provider.class).to receive(:mysql_caller).with("SELECT MAX_USER_CONNECTIONS, MAX_CONNECTIONS, MAX_QUESTIONS, MAX_UPDATES, SSL_TYPE, SSL_CIPHER, X509_ISSUER, X509_SUBJECT, PASSWORD, PLUGIN, AUTHENTICATION_STRING FROM mysql.user WHERE CONCAT(user, '@', host) = '#{user}'", 'regular').and_return('10 10 10 10 ') } # rubocop:disable Layout/LineLength usernames = provider.class.instances.map(&:name) @@ -162,7 +162,7 @@ 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]) - allow(provider.class).to receive(:mysql_caller).with("SELECT CONCAT(User, '@',Host) AS User FROM mysql.user", 'regular').and_return(raw_users) + allow(provider.class).to receive(:mysql_caller).with("SELECT CONCAT(User, '@',Host) AS User FROM mysql.user where HOST IS NOT NULL AND HOST != ''", 'regular').and_return(raw_users) parsed_users.each { |user| allow(provider.class).to receive(:mysql_caller).with("SELECT MAX_USER_CONNECTIONS, MAX_CONNECTIONS, MAX_QUESTIONS, MAX_UPDATES, SSL_TYPE, SSL_CIPHER, X509_ISSUER, X509_SUBJECT, PASSWORD /*!50508 , PLUGIN */ FROM mysql.user WHERE CONCAT(user, '@', host) = '#{user}'", 'regular').and_return('10 10 10 10 ') } # rubocop:disable Layout/LineLength usernames = provider.class.instances.map(&:name) From a877d40144ca27fc501813c22350b965e680c6dc Mon Sep 17 00:00:00 2001 From: Marc Simonetti Date: Wed, 28 Aug 2024 16:26:11 +0200 Subject: [PATCH 3/4] Fix spec unit for mysql_server_id Value of the facter :macaddress was nil, causing tests to have two failures (contexts "igalic's laptop" and "node with lo only"). Update the facter initialization allows to pass the tests successfully. --- spec/unit/facter/mysql_server_id_spec.rb | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/spec/unit/facter/mysql_server_id_spec.rb b/spec/unit/facter/mysql_server_id_spec.rb index fb914a9d4..00f20013e 100644 --- a/spec/unit/facter/mysql_server_id_spec.rb +++ b/spec/unit/facter/mysql_server_id_spec.rb @@ -10,7 +10,7 @@ describe 'mysql_server_id' do context "igalic's laptop" do before :each do - allow(Facter.fact(:macaddress)).to receive(:value).and_return('3c:97:0e:69:fb:e1') + allow(Facter).to receive(:value).with(:macaddress).and_return('3c:97:0e:69:fb:e1') end it do @@ -20,7 +20,7 @@ context 'node with lo only' do before :each do - allow(Facter.fact(:macaddress)).to receive(:value).and_return('00:00:00:00:00:00') + allow(Facter).to receive(:value).with(:macaddress).and_return('00:00:00:00:00:00') end it do @@ -30,7 +30,7 @@ context 'test nil case' do before :each do - allow(Facter.fact(:macaddress)).to receive(:value).and_return(nil) + allow(Facter).to receive(:value).with(:macaddress).and_return(nil) end it do From 499faf963628d23d31b0ff4c9b66d263ba0cbd64 Mon Sep 17 00:00:00 2001 From: Jonathan Buch Date: Mon, 11 Dec 2023 10:56:11 +0100 Subject: [PATCH 4/4] Fix backup/rotation with multiple excluded databases * When using multiple excluded databases, the list of databases is filtered using `grep -v`. i.e. `grep -v '^\(information_schema|performance_schema\)$` * When using Basic vs Extended Regular Expressions, the characters `(` and `|` lose their special meaning, the backslashed versions have to be used. For the group (`()`) the escaping has been done, however the alternation is unescaped. Leading to: * All the excluded databases will be backed up. * In case a database is not backuppable (which is why it had been excluded), this leads to the cleanup not being run at all, as it depends on the backup having been successful. This MR aims to fix this issue, by revising the regular expression and specifying that behaviour in the respective class spec. --- spec/classes/mysql_backup_mysqldump_spec.rb | 4 ++-- templates/mysqlbackup.sh.epp | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/spec/classes/mysql_backup_mysqldump_spec.rb b/spec/classes/mysql_backup_mysqldump_spec.rb index 6389e580a..b44c2b7ce 100644 --- a/spec/classes/mysql_backup_mysqldump_spec.rb +++ b/spec/classes/mysql_backup_mysqldump_spec.rb @@ -76,13 +76,13 @@ class { 'mysql::server': } let(:params) do { 'file_per_database' => true, - 'excludedatabases' => ['information_schema'] + 'excludedatabases' => ['information_schema', 'performance_schema'] }.merge(default_params) end it { expect(subject).to contain_file('mysqlbackup.sh').with_content( - %r{information_schema}, + %r{information_schema\\\|performance_schema}, ) } end diff --git a/templates/mysqlbackup.sh.epp b/templates/mysqlbackup.sh.epp index f1301043b..3111296c3 100644 --- a/templates/mysqlbackup.sh.epp +++ b/templates/mysqlbackup.sh.epp @@ -84,7 +84,7 @@ cleanup <% if $excludedatabases.empty { -%> mysql --defaults-extra-file=$TMPFILE -s -r -N -e 'SHOW DATABASES' | while read dbname <%} else {-%> -mysql --defaults-extra-file=$TMPFILE -s -r -N -e 'SHOW DATABASES' | grep -v '^\(<%= $excludedatabases.join('|') %>\)$' | while read dbname +mysql --defaults-extra-file=$TMPFILE -s -r -N -e 'SHOW DATABASES' | grep -v '^\(<%= $excludedatabases.join('\\|') %>\)$' | while read dbname <% } -%> do <%= $backupmethod %> --defaults-extra-file=$TMPFILE --opt --flush-logs --single-transaction \