diff --git a/README.md b/README.md index 9243a22..bd0fc54 100644 --- a/README.md +++ b/README.md @@ -646,6 +646,39 @@ If provided, this will install the given package prior to activating the extensi ####`package_ensure` By default, the package specified with `package_name` will be installed when the extension is activated, and removed when the extension is deactivated. You can override this behavior by setting the `ensure` value for the package. +###Resource: postgresql::server::grant +This defined type manages grant based access privileges for roles. Consult the PostgreSQL documentation for `grant` for more information. + +####`namevar` +Used to uniquely identify this resource, but functionality not used during grant. + +####`db` +Database of object which you are granting access on. + +####`role` +Role or user whom you are granting access for. + +####`privilege` +The privilege you are granting. Can be `ALL`, `ALL PRIVILEGES` or +`object_type` dependent string. + +####`object_type` +The type of object you are granting privileges on. Can be `DATABASE`, +`SCHEMA`, `SEQUENCE`, `ALL SEQUENCES IN SCHEMA`, `TABLE` or `ALL +TABLES IN SCHEMA`. + +####`object_name` +Object of type `object_type` on which to grant access. + +####`psql_db` +Database to execute the grant against. This should not ordinarily be changed from the default, which is `postgres`. + +####`psql_user` +OS user for running `psql`. Defaults to the default user for the module, usually `postgres`. + +####`port` +Port to use when connecting. Default to 'undef' which generally defaults to 5432 depending on your PostgreSQL packaging. + ###Resource: postgresql::server::pg\_hba\_rule This defined type allows you to create an access rule for `pg_hba.conf`. For more details see the [PostgreSQL documentation](http://www.postgresql.org/docs/8.2/static/auth-pg-hba-conf.html). diff --git a/manifests/server/grant.pp b/manifests/server/grant.pp index 14df099..a24e343 100644 --- a/manifests/server/grant.pp +++ b/manifests/server/grant.pp @@ -34,13 +34,15 @@ define postgresql::server::grant ( #'FUNCTION', #'PROCEDURAL LANGUAGE', 'SCHEMA', - #'SEQUENCE', + 'SEQUENCE', + 'ALL SEQUENCES IN SCHEMA', 'TABLE', 'ALL TABLES IN SCHEMA', #'TABLESPACE', #'VIEW', ) # You can use ALL TABLES IN SCHEMA by passing schema_name to object_name + # You can use ALL SEQUENCES IN SCHEMA by passing schema_name to object_name ## Validate that the object type's privilege is acceptable # TODO: this is a terrible hack; if they pass "ALL" as the desired privilege, @@ -75,6 +77,53 @@ define postgresql::server::grant ( $on_db = $db $onlyif_function = undef } + 'SEQUENCE': { + $unless_privilege = $_privilege ? { + 'ALL' => 'USAGE', + default => $_privilege, + } + validate_string($unless_privilege,'USAGE','ALL','ALL PRIVILEGES') + $unless_function = 'has_sequence_privilege' + $on_db = $db + } + 'ALL SEQUENCES IN SCHEMA': { + validate_string($_privilege,'USAGE','ALL','ALL PRIVILEGES') + $unless_function = 'custom' + $on_db = $db + + $schema = $object_name + + $custom_privilege = $_privilege ? { + 'ALL' => 'USAGE', + 'ALL PRIVILEGES' => 'USAGE', + default => $_privilege, + } + + # This checks if there is a difference between the sequences in the + # specified schema and the sequences for which the role has the specified + # privilege. It uses the EXCEPT clause which computes the set of rows + # that are in the result of the first SELECT statement but not in the + # result of the second one. It then counts the number of rows from this + # operation. If this number is zero then the role has the specified + # privilege for all sequences in the schema and the whole query returns a + # single row, which satisfies the `unless` parameter of Postgresql_psql. + # If this number is not zero then there is at least one sequence for which + # the role does not have the specified privilege, making it necessary to + # execute the GRANT statement. + $custom_unless = "SELECT 1 FROM ( + SELECT sequence_name + FROM information_schema.sequences + WHERE sequence_schema='${schema}' + EXCEPT DISTINCT + SELECT object_name as sequence_name + FROM information_schema.role_usage_grants + WHERE object_type='SEQUENCE' + AND grantee='${role}' + AND object_schema='${schema}' + AND privilege_type='${custom_privilege}' + ) P + HAVING count(P.sequence_name) = 0" + } 'TABLE': { $unless_privilege = $_privilege ? { 'ALL' => 'INSERT', diff --git a/spec/unit/defines/server/grant_spec.rb b/spec/unit/defines/server/grant_spec.rb index 5371663..13588d4 100644 --- a/spec/unit/defines/server/grant_spec.rb +++ b/spec/unit/defines/server/grant_spec.rb @@ -17,16 +17,63 @@ describe 'postgresql::server::grant', :type => :define do 'test' end - let :params do - { - :db => 'test', - :role => 'test', - } + context 'plain' do + let :params do + { + :db => 'test', + :role => 'test', + } + end + + let :pre_condition do + "class {'postgresql::server':}" + end + + it { is_expected.to contain_postgresql__server__grant('test') } end - let :pre_condition do - "class {'postgresql::server':}" + context 'sequence' do + let :params do + { + :db => 'test', + :role => 'test', + :privilege => 'usage', + :object_type => 'sequence', + } + end + + let :pre_condition do + "class {'postgresql::server':}" + end + + it { is_expected.to contain_postgresql__server__grant('test') } + it { is_expected.to contain_postgresql_psql('grant:test').with( + { + 'command' => "GRANT USAGE ON SEQUENCE \"test\" TO\n \"test\"", + 'unless' => "SELECT 1 WHERE has_sequence_privilege('test',\n 'test', 'USAGE')", + }) } end - it { is_expected.to contain_postgresql__server__grant('test') } + context 'all sequences' do + let :params do + { + :db => 'test', + :role => 'test', + :privilege => 'usage', + :object_type => 'all sequences in schema', + :object_name => 'public', + } + end + + let :pre_condition do + "class {'postgresql::server':}" + end + + it { is_expected.to contain_postgresql__server__grant('test') } + it { is_expected.to contain_postgresql_psql('grant:test').with( + { + 'command' => "GRANT USAGE ON ALL SEQUENCES IN SCHEMA \"public\" TO\n \"test\"", + 'unless' => "SELECT 1 FROM (\n SELECT sequence_name\n FROM information_schema.sequences\n WHERE sequence_schema='public'\n EXCEPT DISTINCT\n SELECT object_name as sequence_name\n FROM information_schema.role_usage_grants\n WHERE object_type='SEQUENCE'\n AND grantee='test'\n AND object_schema='public'\n AND privilege_type='USAGE'\n ) P\n HAVING count(P.sequence_name) = 0", + }) } + end end