From e518abd97ed1512bec58599d020b3dccffe58a19 Mon Sep 17 00:00:00 2001 From: Artur Gadelshin Date: Sat, 7 Nov 2015 19:23:20 +0300 Subject: [PATCH] (MODULES-2767) allow to check if table exists before grant --- .../parser/functions/mysql_table_exists.rb | 39 ++++++++++ spec/acceptance/types/mysql_grant_spec.rb | 72 +++++++++++++++++++ .../functions/mysql_table_exists_spec.rb | 22 ++++++ 3 files changed, 133 insertions(+) create mode 100644 lib/puppet/parser/functions/mysql_table_exists.rb create mode 100644 spec/unit/puppet/functions/mysql_table_exists_spec.rb diff --git a/lib/puppet/parser/functions/mysql_table_exists.rb b/lib/puppet/parser/functions/mysql_table_exists.rb new file mode 100644 index 0000000..f3d3761 --- /dev/null +++ b/lib/puppet/parser/functions/mysql_table_exists.rb @@ -0,0 +1,39 @@ +module Puppet::Parser::Functions + newfunction(:mysql_table_exists, :type => :rvalue, :doc => <<-EOS + Check if table exists in database. + + For example: + + mysql_table_exists('*.*') or mysql_table_exists('example_database.*') always return true + mysql_table_exists('example_db.example_table') check existence table `example_table` in `example_database` + + EOS + ) do |args| + + if args.size != 1 + raise(Puppet::ParseError, 'mysql_table_exists(): Wrong number of arguments ' + "given (#{args.size} for 1)") + end + + if match = args[0].match(/(.*)\.(.*)/) + db_name, table_name = match.captures + if db_name.eql?('*') or table_name.eql?('*') + true + else + query = "SELECT TABLE_NAME FROM information_schema.tables WHERE TABLE_NAME = '#{table_name}' AND TABLE_SCHEMA = '#{db_name}';" + + %x{mysql #{defaults_file} -NBe #{query}}.strip.eql?(table_name) + end + else + raise(Puppet::ParseError, 'mysql_table_exists() accept 1 argument - table string like \'database_name.table_name\'') + end + + end +end + +def defaults_file + if File.file?("#{Facter.value(:root_home)}/.my.cnf") + "--defaults-extra-file=#{Facter.value(:root_home)}/.my.cnf" + else + nil + end +end \ No newline at end of file diff --git a/spec/acceptance/types/mysql_grant_spec.rb b/spec/acceptance/types/mysql_grant_spec.rb index d0f94cc..d1bfa25 100644 --- a/spec/acceptance/types/mysql_grant_spec.rb +++ b/spec/acceptance/types/mysql_grant_spec.rb @@ -413,4 +413,76 @@ describe 'mysql_grant' do end end + describe 'adding privileges to specific table' do + # Using puppet_apply as a helper + it 'setup mysql server' do + pp = <<-EOS + class { 'mysql::server': override_options => { 'root_password' => 'password' } } + EOS + + apply_manifest(pp, :catch_failures => true) + end + + it 'creates grant on missing table will fail' do + pp = <<-EOS + mysql_grant { 'test@localhost/grant_spec_db.grant_spec_table': + user => 'test@localhost', + privileges => ['SELECT'], + table => 'grant_spec_db.grant_spec_table', + } + EOS + expect(apply_manifest(pp, :expect_failures => true).stderr).to match(/Table 'grant_spec_db\.grant_spec_table' doesn't exist/) + end + + it 'checks if table exists before grant' do + pp = <<-EOS + if mysql_table_exists('grant_spec_db.grant_spec_table') { + mysql_grant { 'test@localhost/grant_spec_db.grant_spec_table': + user => 'test@localhost', + privileges => 'ALL', + table => 'grant_spec_db.grant_spec_table', + } + } + EOS + apply_manifest(pp, :catch_changes => true) + end + + it 'creates table' do + pp = <<-EOS + file { '/tmp/grant_spec_table.sql': + ensure => file, + content => 'CREATE TABLE grant_spec_table (id int);', + before => Mysql::Db['grant_spec_db'], + } + mysql::db { 'grant_spec_db': + user => 'root1', + password => 'password', + sql => '/tmp/grant_spec_table.sql', + } + EOS + + apply_manifest(pp, :catch_failures => true) + end + + it 'should have the table' do + expect(shell("mysql -e 'show tables;' grant_spec_db|grep grant_spec_table").exit_code).to be_zero + end + + it 'checks if table exists before grant' do + pp = <<-EOS + if mysql_table_exists('grant_spec_db.grant_spec_table') { + mysql_grant { 'test@localhost/grant_spec_db.grant_spec_table': + user => 'test@localhost', + privileges => ['SELECT'], + table => 'grant_spec_db.grant_spec_table', + } + } + EOS + apply_manifest(pp, :catch_failures => true) + apply_manifest(pp, :catch_changes => true) + end + + + end + end diff --git a/spec/unit/puppet/functions/mysql_table_exists_spec.rb b/spec/unit/puppet/functions/mysql_table_exists_spec.rb new file mode 100644 index 0000000..1c5eac3 --- /dev/null +++ b/spec/unit/puppet/functions/mysql_table_exists_spec.rb @@ -0,0 +1,22 @@ +require 'spec_helper' + +describe 'the mysql_table_exists function' do + before :all do + Puppet::Parser::Functions.autoloader.loadall + end + + let(:scope) { PuppetlabsSpec::PuppetInternals.scope } + + it 'should exist' do + expect(Puppet::Parser::Functions.function('mysql_table_exists')).to eq('function_mysql_table_exists') + end + + it 'should raise a ParseError if there is less than 1 arguments' do + expect { scope.function_mysql_table_exists([]) }.to( raise_error(Puppet::ParseError)) + end + + it 'should raise a ParseError if there is more than 1 arguments' do + expect { scope.function_mysql_table_exists(%w(foo bar)) }.to( raise_error(Puppet::ParseError)) + end + +end \ No newline at end of file