diff --git a/README.md b/README.md index 765b9fe..3d1ab4c 100644 --- a/README.md +++ b/README.md @@ -53,6 +53,7 @@ Usage: gratan [options] -o, --output FILE --ignore-user REGEXP --target-user REGEXP + --ignore-object REGEXP --enable-expired --ignore-not-exist --no-color diff --git a/bin/gratan b/bin/gratan index 70569cd..a4d5148 100755 --- a/bin/gratan +++ b/bin/gratan @@ -42,6 +42,7 @@ ARGV.options do |opt| opt.on('-o', '--output FILE') {|v| output_file = v } opt.on('' , '--ignore-user REGEXP') {|v| options[:ignore_user] = Regexp.new(v) } opt.on('' , '--target-user REGEXP') {|v| options[:target_user] = Regexp.new(v) } + opt.on('' , '--ignore-object REGEXP') {|v| options[:ignore_object] = Regexp.new(v) } opt.on('' , '--enable-expired') { options[:enable_expired] = true } opt.on('' , '--ignore-not-exist') {|v| options[:ignore_not_exist] = true } opt.on('' , '--no-color') { options[:color] = false } diff --git a/lib/gratan/driver.rb b/lib/gratan/driver.rb index 0a5efca..f39c5c2 100644 --- a/lib/gratan/driver.rb +++ b/lib/gratan/driver.rb @@ -38,9 +38,13 @@ def show_all_tables def expand_object(object_or_regexp) if object_or_regexp.kind_of?(Regexp) - show_all_tables.select {|i| i =~ object_or_regexp } + objects = show_all_tables.select {|i| i =~ object_or_regexp } else - [object_or_regexp] + objects = [object_or_regexp] + end + + objects.select do |object| + object !~ @options[:ignore_object] end end diff --git a/lib/gratan/dsl/converter.rb b/lib/gratan/dsl/converter.rb index 46d15d1..962e3e4 100644 --- a/lib/gratan/dsl/converter.rb +++ b/lib/gratan/dsl/converter.rb @@ -38,7 +38,7 @@ def output_user_options(options) end def output_objects(objects) - objects.map {|object, grant| + objects.sort_by {|k, v| k }.map {|object, grant| options = output_object_options(grant) <<-EOS @@ -61,7 +61,7 @@ def output_object_options(grant) end def output_grant(grant) - grant[:privs].map {|priv| + grant[:privs].sort.map {|priv| <<-EOS grant #{priv.inspect} EOS diff --git a/lib/gratan/exporter.rb b/lib/gratan/exporter.rb index 3049a23..9c695e5 100644 --- a/lib/gratan/exporter.rb +++ b/lib/gratan/exporter.rb @@ -36,6 +36,7 @@ def pack(grants) host = grant.delete(:host) user_host = [user, host] object = grant.delete(:object) + next if object =~ @options[:ignore_object] identified = grant.delete(:identified) required = grant.delete(:require) diff --git a/lib/gratan/version.rb b/lib/gratan/version.rb index 04db207..5cc2f32 100644 --- a/lib/gratan/version.rb +++ b/lib/gratan/version.rb @@ -1,3 +1,3 @@ module Gratan - VERSION = '0.2.6' + VERSION = '0.2.7' end diff --git a/spec/change/change_grants_with_ignore_object_spec.rb b/spec/change/change_grants_with_ignore_object_spec.rb new file mode 100644 index 0000000..2d152ae --- /dev/null +++ b/spec/change/change_grants_with_ignore_object_spec.rb @@ -0,0 +1,131 @@ +describe 'Gratan::Client#apply' do + before(:each) do + apply { + <<-RUBY +user 'scott', 'localhost', identified: 'tiger', required: 'SSL' do + on '*.*' do + grant 'SELECT' + grant 'INSERT' + end + + on 'test.*' do + grant 'UPDATE' + grant 'DELETE' + end + + on 'mysql.user' do + grant 'SELECT (user)' + end +end + +user 'bob', 'localhost' do + on '*.*' do + grant 'USAGE' + end + + on 'test.*' do + grant 'ALL PRIVILEGES' + end +end + RUBY + } + end + + context 'when grant privs with ignore_object' do + subject { client(ignore_object: /user/) } + + it do + apply(subject) { + <<-RUBY +user 'scott', 'localhost', identified: 'tiger', required: 'SSL' do + on '*.*' do + grant 'SELECT' + grant 'INSERT' + grant 'UPDATE' + grant 'DELETE' + end + + on 'test.*' do + grant 'SELECT' + grant 'INSERT' + grant 'UPDATE' + grant 'DELETE' + end + + on 'mysql.user' do + grant 'SELECT (user)' + grant 'UPDATE (host)' # ignore + end +end + +user 'bob', 'localhost' do + on '*.*' do + grant 'USAGE' + end + + on 'test.*' do + grant 'ALL PRIVILEGES' + end +end + RUBY + } + + expect(show_grants).to match_array [ + "GRANT ALL PRIVILEGES ON `test`.* TO 'bob'@'localhost'", + "GRANT SELECT (user) ON `mysql`.`user` TO 'scott'@'localhost'", + "GRANT SELECT, INSERT, UPDATE, DELETE ON *.* TO 'scott'@'localhost' IDENTIFIED BY PASSWORD '*F2F68D0BB27A773C1D944270E5FAFED515A3FA40' REQUIRE SSL", + "GRANT SELECT, INSERT, UPDATE, DELETE ON `test`.* TO 'scott'@'localhost'", + "GRANT USAGE ON *.* TO 'bob'@'localhost'", + ] + end + end + + context 'when grant privs with ignore_object (2)' do + subject { client(ignore_object: /user2/) } + + it do + apply(subject) { + <<-RUBY +user 'scott', 'localhost', identified: 'tiger', required: 'SSL' do + on '*.*' do + grant 'SELECT' + grant 'INSERT' + grant 'UPDATE' + grant 'DELETE' + end + + on 'test.*' do + grant 'SELECT' + grant 'INSERT' + grant 'UPDATE' + grant 'DELETE' + end + + on 'mysql.user' do + grant 'SELECT (user)' + grant 'UPDATE (host)' + end +end + +user 'bob', 'localhost' do + on '*.*' do + grant 'USAGE' + end + + on 'test.*' do + grant 'ALL PRIVILEGES' + end +end + RUBY + } + + expect(show_grants).to match_array [ + "GRANT ALL PRIVILEGES ON `test`.* TO 'bob'@'localhost'", + "GRANT SELECT (user), UPDATE (host) ON `mysql`.`user` TO 'scott'@'localhost'", + "GRANT SELECT, INSERT, UPDATE, DELETE ON *.* TO 'scott'@'localhost' IDENTIFIED BY PASSWORD '*F2F68D0BB27A773C1D944270E5FAFED515A3FA40' REQUIRE SSL", + "GRANT SELECT, INSERT, UPDATE, DELETE ON `test`.* TO 'scott'@'localhost'", + "GRANT USAGE ON *.* TO 'bob'@'localhost'", + ] + end + end +end diff --git a/spec/create/create_user_with_ignore_object_spec.rb b/spec/create/create_user_with_ignore_object_spec.rb new file mode 100644 index 0000000..a607e82 --- /dev/null +++ b/spec/create/create_user_with_ignore_object_spec.rb @@ -0,0 +1,76 @@ +describe 'Gratan::Client#apply' do + context 'when user does not exist' do + subject { client } + + it do + result = apply(subject) { '' } + expect(result).to be_falsey + expect(show_grants).to match_array [] + end + end + + context 'when create user with ignore_object' do + subject { client(ignore_object: /test/) } + + it do + result = apply(subject) { + <<-RUBY +user 'scott', 'localhost', identified: 'tiger' do + on '*.*' do + grant 'SELECT' + grant 'INSERT' + grant 'UPDATE' + grant 'DELETE' + end + + on 'test.*' do + grant 'SELECT' + grant 'INSERT' + grant 'UPDATE' + grant 'DELETE' + end +end + RUBY + } + + expect(result).to be_truthy + + expect(show_grants).to match_array [ + "GRANT SELECT, INSERT, UPDATE, DELETE ON *.* TO 'scott'@'localhost' IDENTIFIED BY PASSWORD '*F2F68D0BB27A773C1D944270E5FAFED515A3FA40'", + ] + end + end + + context 'when create user with ignore_object (2)' do + subject { client(ignore_object: /test2/) } + + it do + result = apply(subject) { + <<-RUBY +user 'scott', 'localhost', identified: 'tiger' do + on '*.*' do + grant 'SELECT' + grant 'INSERT' + grant 'UPDATE' + grant 'DELETE' + end + + on 'test.*' do + grant 'SELECT' + grant 'INSERT' + grant 'UPDATE' + grant 'DELETE' + end +end + RUBY + } + + expect(result).to be_truthy + + expect(show_grants).to match_array [ + "GRANT SELECT, INSERT, UPDATE, DELETE ON *.* TO 'scott'@'localhost' IDENTIFIED BY PASSWORD '*F2F68D0BB27A773C1D944270E5FAFED515A3FA40'", + "GRANT SELECT, INSERT, UPDATE, DELETE ON `test`.* TO 'scott'@'localhost'", + ] + end + end +end diff --git a/spec/export/export_chunk_spec.rb b/spec/export/export_chunk_spec.rb index d4e9523..8ce4927 100644 --- a/spec/export/export_chunk_spec.rb +++ b/spec/export/export_chunk_spec.rb @@ -47,14 +47,14 @@ grant "SELECT" end - on "test3.*" do - grant "UPDATE" - grant "DELETE" - end - on "test2.*" do grant "INSERT" end + + on "test3.*" do + grant "DELETE" + grant "UPDATE" + end end RUBY end diff --git a/spec/export/export_with_ignore_object_spec.rb b/spec/export/export_with_ignore_object_spec.rb new file mode 100644 index 0000000..99a3b40 --- /dev/null +++ b/spec/export/export_with_ignore_object_spec.rb @@ -0,0 +1,109 @@ +describe 'Gratan::Client#export' do + context 'when with ignore_object' do + let(:grantfile) { + <<-RUBY +user "scott", "%" do + on "*.*" do + grant "USAGE" + end + + on "test.*" do + grant "SELECT" + end +end + +user "bob", "localhost" do + on "*.*" do + grant "USAGE" + end + + on "test.*" do + grant "SELECT" + end +end + RUBY + } + + subject { client(ignore_object: /test/) } + + before do + apply(subject) do + grantfile + end + end + + it do + expect(subject.export.strip).to eq <<-RUBY.strip +user "scott", "%" do + on "*.*" do + grant "USAGE" + end +end + +user "bob", "localhost" do + on "*.*" do + grant "USAGE" + end +end + RUBY + end + end + + context 'when with ignore_object (2)' do + let(:grantfile) { + <<-RUBY +user "scott", "%" do + on "*.*" do + grant "USAGE" + end + + on "test.*" do + grant "SELECT" + end +end + +user "bob", "localhost" do + on "*.*" do + grant "USAGE" + end + + on "test.*" do + grant "SELECT" + end +end + RUBY + } + + subject { client(ignore_object: /bob/) } + + before do + apply(subject) do + grantfile + end + end + + it do + expect(subject.export.strip).to eq <<-RUBY.strip +user "scott", "%" do + on "*.*" do + grant "USAGE" + end + + on "test.*" do + grant "SELECT" + end +end + +user "bob", "localhost" do + on "*.*" do + grant "USAGE" + end + + on "test.*" do + grant "SELECT" + end +end + RUBY + end + end +end