diff --git a/manifests/schema/permission.pp b/manifests/schema/permission.pp index d6edb26..d815812 100644 --- a/manifests/schema/permission.pp +++ b/manifests/schema/permission.pp @@ -1,129 +1,161 @@ # Grant or revoke permissions. # To use this class, a suitable `authenticator` (e.g. PasswordAuthenticator) # and `authorizer` (e.g. CassandraAuthorizer) must be set in the Cassandra # class. # # WARNING: Specifying keyspace 'ALL' and 'ALL' for permissions at the same # time is not currently supported by this module. # # @param user_name [string] The name of the user who is to be granted or # revoked. # @param ensure [ present | absent ] Set to present to grant a permission or # absent to revoke it. # @param keyspace_name [string] The name of the keyspace to grant/revoke the # permissions on. If set to 'ALL' then the permission will be applied to # all of the keyspaces. # @param permission_name [string] Can be one of the following: # # * 'ALTER' - ALTER KEYSPACE, ALTER TABLE, CREATE INDEX, DROP INDEX. # * 'AUTHORIZE' - GRANT, REVOKE. # * 'CREATE' - CREATE KEYSPACE, CREATE TABLE. # * 'DROP' - DROP KEYSPACE, DROP TABLE. # * 'MODIFY' - INSERT, DELETE, UPDATE, TRUNCATE. # * 'SELECT' - SELECT. # # If the permission_name is set to 'ALL', this will set all of the specific # permissions listed. # @param table_name [string] The name of a table within the specified # keyspace. If left unspecified, the procedure will be applied to all # tables within the keyspace. define cassandra::schema::permission ( $user_name, $ensure = present, $keyspace_name = 'ALL', $permission_name = 'ALL', $table_name = undef, $use_scl = $::cassandra::params::use_scl, $scl_name = $::cassandra::params::scl_name, ){ include 'cassandra::schema' + if $use_scl { + $quote = '\"' + } else { + $quote = '"' + } + if upcase($keyspace_name) == 'ALL' and upcase($permission_name) == 'ALL' { fail('"ALL" keyspaces AND "ALL" permissions are mutually exclusive.') } elsif $table_name { $resource = "TABLE ${keyspace_name}.${table_name}" } elsif upcase($keyspace_name) == 'ALL' { $resource = 'ALL KEYSPACES' } else { $resource = "KEYSPACE ${keyspace_name}" } $read_script = "LIST ALL PERMISSIONS ON ${resource}" $upcase_permission_name = upcase($permission_name) $pattern = "\s${user_name} |\s*${user_name} |\s.*\s${upcase_permission_name}$" - $read_command = "${::cassandra::schema::cqlsh_opts} -e \"${read_script}\" ${::cassandra::schema::cqlsh_conn} | grep '${pattern}'" + $read_command_tmp = "${::cassandra::schema::cqlsh_opts} -e ${quote}${read_script}${quote} ${::cassandra::schema::cqlsh_conn} | grep '${pattern}'" + if $use_scl { + $read_command = "/usr/bin/scl enable ${scl_name} \"${read_command_tmp}\"" + } else { + $read_command = $read_command_tmp + } if upcase($permission_name) == 'ALL' { cassandra::schema::permission { "${title} - ALTER": ensure => $ensure, user_name => $user_name, keyspace_name => $keyspace_name, permission_name => 'ALTER', table_name => $table_name, + use_scl => $use_scl, + scl_name => $scl_name, } cassandra::schema::permission { "${title} - AUTHORIZE": ensure => $ensure, user_name => $user_name, keyspace_name => $keyspace_name, permission_name => 'AUTHORIZE', table_name => $table_name, + use_scl => $use_scl, + scl_name => $scl_name, } # The CREATE permission is not relevant to tables. if !$table_name { cassandra::schema::permission { "${title} - CREATE": ensure => $ensure, user_name => $user_name, keyspace_name => $keyspace_name, permission_name => 'CREATE', table_name => $table_name, + use_scl => $use_scl, + scl_name => $scl_name, } } cassandra::schema::permission { "${title} - DROP": ensure => $ensure, user_name => $user_name, keyspace_name => $keyspace_name, permission_name => 'DROP', table_name => $table_name, + use_scl => $use_scl, + scl_name => $scl_name, } cassandra::schema::permission { "${title} - MODIFY": ensure => $ensure, user_name => $user_name, keyspace_name => $keyspace_name, permission_name => 'MODIFY', table_name => $table_name, + use_scl => $use_scl, + scl_name => $scl_name, } cassandra::schema::permission { "${title} - SELECT": ensure => $ensure, user_name => $user_name, keyspace_name => $keyspace_name, permission_name => 'SELECT', table_name => $table_name, + use_scl => $use_scl, + scl_name => $scl_name, } } elsif $ensure == present { $create_script = "GRANT ${permission_name} ON ${resource} TO ${user_name}" - $create_command = "${::cassandra::schema::cqlsh_opts} -e \"${create_script}\" ${::cassandra::schema::cqlsh_conn -}" + $create_command_tmp = "${::cassandra::schema::cqlsh_opts} -e ${quote}${create_script}${quote} ${::cassandra::schema::cqlsh_conn}" + if $use_scl { + $create_command = "/usr/bin/scl enable ${scl_name} \"${create_command_tmp}\"" + } else { + $create_command = $create_command_tmp + } exec { $create_script: command => $create_command, unless => $read_command, require => Exec['::cassandra::schema connection test'], } } elsif $ensure == absent { $delete_script = "REVOKE ${permission_name} ON ${resource} FROM ${user_name}" - $delete_command = "${::cassandra::schema::cqlsh_opts} -e \"${delete_script}\" ${::cassandra::schema::cqlsh_conn}" + $delete_command_tmp = "${::cassandra::schema::cqlsh_opts} -e ${quote}${delete_script}${quote} ${::cassandra::schema::cqlsh_conn}" + if $use_scl { + $delete_command = "/usr/bin/scl enable ${scl_name} \"${delete_command_tmp}\"" + } else { + $delete_command = $delete_command_tmp + } exec { $delete_script: command => $delete_command, onlyif => $read_command, require => Exec['::cassandra::schema connection test'], } } else { fail("Unknown action (${ensure}) for ensure attribute.") } } diff --git a/spec/defines/schema/permission_spec.rb b/spec/defines/schema/permission_spec.rb index fe7dc54..44cf719 100644 --- a/spec/defines/schema/permission_spec.rb +++ b/spec/defines/schema/permission_spec.rb @@ -1,273 +1,399 @@ require 'spec_helper' describe 'cassandra::schema::permission' do context 'Set ensure to latest' do let :facts do { operatingsystemmajrelease: 7, osfamily: 'RedHat' } end let(:title) { 'foobar' } let(:params) do { user_name: 'foobar' } end it { is_expected.to raise_error(Puppet::Error) } end context 'Set ensure to latest' do let :facts do { operatingsystemmajrelease: 7, osfamily: 'RedHat' } end let(:title) { 'foobar' } let(:params) do { ensure: 'latest' } end it { is_expected.to raise_error(Puppet::Error) } end context 'spillman:SELECT:ALL' do let(:title) { 'spillman:SELECT:ALL' } let :facts do { operatingsystemmajrelease: 7, osfamily: 'RedHat' } end let(:params) do { user_name: 'spillman', permission_name: 'SELECT', use_scl: false, scl_name: 'nodefault' } end it do is_expected.to have_resource_count(9) is_expected.to contain_cassandra__schema__permission('spillman:SELECT:ALL') read_script = '/usr/bin/cqlsh -e "LIST ALL PERMISSIONS ON ALL KEYSPACES" ' read_script += 'localhost 9042 | grep \' spillman | *spillman | .* SELECT$\'' script_command = 'GRANT SELECT ON ALL KEYSPACES TO spillman' exec_command = "/usr/bin/cqlsh -e \"#{script_command}\" localhost 9042" is_expected.to contain_exec(script_command). only_with(command: exec_command, unless: read_script, require: 'Exec[::cassandra::schema connection test]') end end + + context 'spillman:SELECT:ALL with SCL' do + let(:title) { 'spillman:SELECT:ALL' } + let :facts do + { + operatingsystemmajrelease: 7, + osfamily: 'RedHat' + } + end + + let(:params) do + { + user_name: 'spillman', + permission_name: 'SELECT', + use_scl: true, + scl_name: 'testscl' + } + end + + it do + is_expected.to have_resource_count(9) + is_expected.to contain_cassandra__schema__permission('spillman:SELECT:ALL') + read_script = '/usr/bin/scl enable testscl "/usr/bin/cqlsh -e \"LIST ALL PERMISSIONS ON ALL KEYSPACES\" ' + read_script += 'localhost 9042 | grep \' spillman | *spillman | .* SELECT$\'"' + script_command = 'GRANT SELECT ON ALL KEYSPACES TO spillman' + exec_command = "/usr/bin/scl enable testscl \"/usr/bin/cqlsh -e \\\"#{script_command}\\\" localhost 9042\"" + is_expected.to contain_exec(script_command). + only_with(command: exec_command, + unless: read_script, + require: 'Exec[::cassandra::schema connection test]') end end context 'akers:modify:field' do let(:title) { 'akers:modify:field' } let :facts do { operatingsystemmajrelease: 7, osfamily: 'RedHat' } end let(:params) do { user_name: 'akers', keyspace_name: 'field', permission_name: 'MODIFY', use_scl: false, scl_name: 'nodefault' } end it do is_expected.to have_resource_count(9) is_expected.to contain_cassandra__schema__permission('akers:modify:field') read_script = '/usr/bin/cqlsh -e "LIST ALL PERMISSIONS ON KEYSPACE field" ' read_script += 'localhost 9042 | grep \' akers | *akers | .* MODIFY$\'' script_command = 'GRANT MODIFY ON KEYSPACE field TO akers' exec_command = "/usr/bin/cqlsh -e \"#{script_command}\" localhost 9042" is_expected.to contain_exec(script_command). only_with(command: exec_command, unless: read_script, require: 'Exec[::cassandra::schema connection test]') end end + + context 'akers:modify:field with SCL' do + let(:title) { 'akers:modify:field' } + let :facts do + { + operatingsystemmajrelease: 7, + osfamily: 'RedHat' + } + end + + let(:params) do + { + user_name: 'akers', + keyspace_name: 'field', + permission_name: 'MODIFY', + use_scl: true, + scl_name: 'testscl' + } + end + + it do + is_expected.to have_resource_count(9) + is_expected.to contain_cassandra__schema__permission('akers:modify:field') + read_script = '/usr/bin/scl enable testscl "/usr/bin/cqlsh -e \"LIST ALL PERMISSIONS ON KEYSPACE field\" ' + read_script += 'localhost 9042 | grep \' akers | *akers | .* MODIFY$\'"' + script_command = 'GRANT MODIFY ON KEYSPACE field TO akers' + exec_command = "/usr/bin/scl enable testscl \"/usr/bin/cqlsh -e \\\"#{script_command}\\\" localhost 9042\"" + is_expected.to contain_exec(script_command). + only_with(command: exec_command, + unless: read_script, + require: 'Exec[::cassandra::schema connection test]') end end context 'boone:alter:forty9ers' do let(:title) { 'boone:alter:forty9ers' } let :facts do { operatingsystemmajrelease: 7, osfamily: 'RedHat' } end let(:params) do { user_name: 'boone', keyspace_name: 'forty9ers', permission_name: 'ALTER', use_scl: false, scl_name: 'nodefault' } end it do is_expected.to have_resource_count(9) is_expected.to contain_cassandra__schema__permission('boone:alter:forty9ers') read_script = '/usr/bin/cqlsh -e "LIST ALL PERMISSIONS ON KEYSPACE forty9ers" ' read_script += 'localhost 9042 | grep \' boone | *boone | .* ALTER$\'' script_command = 'GRANT ALTER ON KEYSPACE forty9ers TO boone' exec_command = "/usr/bin/cqlsh -e \"#{script_command}\" localhost 9042" is_expected.to contain_exec(script_command). only_with(command: exec_command, unless: read_script, require: 'Exec[::cassandra::schema connection test]') end end + context 'boone:alter:forty9ers with SCL' do + let(:title) { 'boone:alter:forty9ers' } + let :facts do + { + operatingsystemmajrelease: 7, + osfamily: 'RedHat' + } + end + + let(:params) do + { + user_name: 'boone', + keyspace_name: 'forty9ers', + permission_name: 'ALTER', + use_scl: true, + scl_name: 'testscl' + } + end + + it do + is_expected.to have_resource_count(9) + is_expected.to contain_cassandra__schema__permission('boone:alter:forty9ers') + read_script = '/usr/bin/scl enable testscl "/usr/bin/cqlsh -e \"LIST ALL PERMISSIONS ON KEYSPACE forty9ers\" ' + read_script += 'localhost 9042 | grep \' boone | *boone | .* ALTER$\'"' + script_command = 'GRANT ALTER ON KEYSPACE forty9ers TO boone' + exec_command = "/usr/bin/scl enable testscl \"/usr/bin/cqlsh -e \\\"#{script_command}\\\" localhost 9042\"" + is_expected.to contain_exec(script_command). + only_with(command: exec_command, + unless: read_script, + require: 'Exec[::cassandra::schema connection test]') + end + end + context 'boone:ALL:ravens.plays' do let(:title) { 'boone:ALL:ravens.plays' } let :facts do { operatingsystemmajrelease: 7, osfamily: 'RedHat' } end let(:params) do { user_name: 'boone', keyspace_name: 'ravens', table_name: 'plays', use_scl: false, scl_name: 'nodefault' } end it do is_expected.to have_resource_count(18) is_expected.to contain_cassandra__schema__permission('boone:ALL:ravens.plays') end - expected_values = %w{ALTER AUTHORIZE DROP MODIFY SELECT} + expected_values = %w[ALTER AUTHORIZE DROP MODIFY SELECT] expected_values.each do |val| it do is_expected.to contain_cassandra__schema__permission("boone:ALL:ravens.plays - #{val}").with( ensure: 'present', user_name: 'boone', keyspace_name: 'ravens', permission_name: val, table_name: 'plays' ) end read_script = '/usr/bin/cqlsh -e "LIST ALL PERMISSIONS ON TABLE ravens.plays" ' read_script += "localhost 9042 | grep ' boone | *boone | .* #{val}$'" script_command = "GRANT #{val} ON TABLE ravens.plays TO boone" exec_command = "/usr/bin/cqlsh -e \"#{script_command}\" localhost 9042" it do is_expected.to contain_exec(script_command). only_with(command: exec_command, unless: read_script, require: 'Exec[::cassandra::schema connection test]') end end end context 'boone:ALL:ravens.plays with SCL' do let(:title) { 'boone:ALL:ravens.plays' } let :facts do { operatingsystemmajrelease: 7, osfamily: 'RedHat' } end let(:params) do { user_name: 'boone', keyspace_name: 'ravens', table_name: 'plays', use_scl: true, scl_name: 'testscl' } end it do is_expected.to have_resource_count(18) is_expected.to contain_cassandra__schema__permission('boone:ALL:ravens.plays') end - expected_values = %w{ALTER AUTHORIZE DROP MODIFY SELECT} + expected_values = %w[ALTER AUTHORIZE DROP MODIFY SELECT] expected_values.each do |val| it do is_expected.to contain_cassandra__schema__permission("boone:ALL:ravens.plays - #{val}").with( ensure: 'present', user_name: 'boone', keyspace_name: 'ravens', permission_name: val, table_name: 'plays' ) end read_script = '/usr/bin/scl enable testscl "/usr/bin/cqlsh -e \"LIST ALL PERMISSIONS ON TABLE ravens.plays\" ' read_script += "localhost 9042 | grep ' boone | *boone | .* #{val}$'\"" script_command = "GRANT #{val} ON TABLE ravens.plays TO boone" exec_command = "/usr/bin/scl enable testscl \"/usr/bin/cqlsh -e \\\"#{script_command}\\\" localhost 9042\"" it do is_expected.to contain_exec(script_command). only_with(command: exec_command, unless: read_script, require: 'Exec[::cassandra::schema connection test]') end end end context 'REVOKE boone:SELECT:ravens.plays' do let(:title) { 'REVOKE boone:SELECT:ravens.plays' } let :facts do { operatingsystemmajrelease: 7, osfamily: 'RedHat' } end let(:params) do { ensure: 'absent', user_name: 'boone', keyspace_name: 'forty9ers', permission_name: 'SELECT', use_scl: false, scl_name: 'nodefault' } end it do is_expected.to have_resource_count(9) is_expected.to contain_cassandra__schema__permission('REVOKE boone:SELECT:ravens.plays') read_script = '/usr/bin/cqlsh -e "LIST ALL PERMISSIONS ON KEYSPACE forty9ers" ' read_script += "localhost 9042 | grep ' boone | *boone | .* SELECT$'" script_command = 'REVOKE SELECT ON KEYSPACE forty9ers FROM boone' exec_command = "/usr/bin/cqlsh -e \"#{script_command}\" localhost 9042" is_expected.to contain_exec(script_command). only_with(command: exec_command, onlyif: read_script, require: 'Exec[::cassandra::schema connection test]') end end + + context 'REVOKE boone:SELECT:ravens.plays with SCL' do + let(:title) { 'REVOKE boone:SELECT:ravens.plays' } + let :facts do + { + operatingsystemmajrelease: 7, + osfamily: 'RedHat' + } + end + + let(:params) do + { + ensure: 'absent', + user_name: 'boone', + keyspace_name: 'forty9ers', + permission_name: 'SELECT', + use_scl: true, + scl_name: 'testscl' + } + end + + it do + is_expected.to have_resource_count(9) + is_expected.to contain_cassandra__schema__permission('REVOKE boone:SELECT:ravens.plays') + read_script = '/usr/bin/scl enable testscl "/usr/bin/cqlsh -e \"LIST ALL PERMISSIONS ON KEYSPACE forty9ers\" ' + read_script += "localhost 9042 | grep ' boone | *boone | .* SELECT$'\"" + script_command = 'REVOKE SELECT ON KEYSPACE forty9ers FROM boone' + exec_command = "/usr/bin/scl enable testscl \"/usr/bin/cqlsh -e \\\"#{script_command}\\\" localhost 9042\"" + is_expected.to contain_exec(script_command). + only_with(command: exec_command, + onlyif: read_script, + require: 'Exec[::cassandra::schema connection test]') end end end