Skip to content

Commit 8aa14f3

Browse files
committed
Merge pull request #894 from infoxchange/reassign_owned_by
add defined type postgresql::server::reassign_owned_by
2 parents 551f5c3 + b49143f commit 8aa14f3

File tree

4 files changed

+294
-0
lines changed

4 files changed

+294
-0
lines changed

README.md

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
* [Configure a server](#configure-a-server)
1111
* [Create a database](#create-a-database)
1212
* [Manage users, roles, and permissions](#manage-users-roles-and-permissions)
13+
* [Manage ownership of DB objects](#manage-ownership-of-db-objects)
1314
* [Override defaults](#override-defaults)
1415
* [Create an access rule for pg_hba.conf](#create-an-access-rule-for-pg_hbaconf)
1516
* [Create user name maps for pg_ident.conf](#create-user-name-maps-for-pg_identconf)
@@ -116,6 +117,24 @@ postgresql::server::table_grant { 'my_table of test2':
116117

117118
This example grants **all** privileges on the test1 database and on the `my_table` table of the test2 database to the specified user or group. After the values are added into the PuppetDB config file, this database would be ready for use.
118119

120+
### Manage ownership of DB objects
121+
122+
To change the ownership of all objects within a database using REASSIGN OWNED:
123+
124+
```puppet
125+
postgresql::server::reassign_owned_by { 'new owner is meerkat':
126+
db => 'test_db',
127+
old_owner => 'marmot',
128+
new_owner => 'meerkat',
129+
}
130+
```
131+
132+
This would run the PostgreSQL statement 'REASSIGN OWNED' to update to ownership of all tables, sequences, functions and views currently owned by the role 'marmot' to be owned by the role 'meerkat' instead.
133+
134+
This applies to objects within the nominated database, 'test_db' only.
135+
136+
For Postgresql >= 9.3, the ownership of the database is also updated.
137+
119138
### Override defaults
120139

121140
The `postgresql::globals` class allows you to configure the main settings for this module globally, so that other classes and defined resources can use them. By itself, it does nothing.
@@ -327,6 +346,7 @@ The postgresql module comes with many options for configuring the server. While
327346
* [postgresql::server::grant_role](#postgresqlservergrant_role)
328347
* [postgresql::server::pg_hba_rule](#postgresqlserverpg_hba_rule)
329348
* [postgresql::server::pg_ident_rule](#postgresqlserverpg_ident_rule)
349+
* [postgresql::server::reassign_owned_by](#postgresqlserverreassign_owned_by)
330350
* [postgresql::server::recovery](#postgresqlserverrecovery)
331351
* [postgresql::server::role](#postgresqlserverrole)
332352
* [postgresql::server::schema](#postgresqlserverschema)
@@ -1352,6 +1372,40 @@ Provides the target for the rule and is generally an internal only property.
13521372

13531373
**Use with caution.**
13541374

1375+
#### postgresql::server::reassign_owned_by
1376+
1377+
Runs the PostgreSQL command 'REASSIGN OWNED' on a database, to transfer the ownership of existing objects between database roles
1378+
1379+
##### `db`
1380+
1381+
Specifies the database to which the 'REASSIGN OWNED' will be applied
1382+
1383+
##### `old_role`
1384+
1385+
Specifies the role or user who is the current owner of the objects in the specified db
1386+
1387+
##### `new_role`
1388+
1389+
Specifies the role or user who will be the new owner of these objects
1390+
1391+
##### `psql_user`
1392+
1393+
Specifies the OS user for running `psql`.
1394+
1395+
Default value: The default user for the module, usually 'postgres'.
1396+
1397+
##### `port`
1398+
1399+
Port to use when connecting.
1400+
1401+
Default value: `undef`, which generally defaults to port 5432 depending on your PostgreSQL packaging.
1402+
1403+
##### `connect_settings`
1404+
1405+
Specifies a hash of environment variables used when connecting to a remote server.
1406+
1407+
Default value: Connects to the local Postgres instance.
1408+
13551409
#### postgresql::server::recovery
13561410

13571411
Allows you to create the content for `recovery.conf`. For more details see the [usage example](#create-recovery-configuration) and the [PostgreSQL documentation](http://www.postgresql.org/docs/current/static/recovery-config.html).

manifests/server/reassign_owned_by.pp

Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
# Define for reassigning the ownership of objects within a database. See README.md for more details.
2+
# This enables us to force the a particular ownership for objects within a database
3+
define postgresql::server::reassign_owned_by (
4+
String $old_role,
5+
String $new_role,
6+
String $db,
7+
String $psql_user = $postgresql::server::user,
8+
Integer $port = $postgresql::server::port,
9+
Hash $connect_settings = $postgresql::server::default_connect_settings,
10+
) {
11+
12+
$sql_command = "REASSIGN OWNED BY \"${old_role}\" TO \"${new_role}\""
13+
14+
$group = $postgresql::server::group
15+
$psql_path = $postgresql::server::psql_path
16+
17+
#
18+
# Port, order of precedence: $port parameter, $connect_settings[PGPORT], $postgresql::server::port
19+
#
20+
if $port != undef {
21+
$port_override = $port
22+
} elsif $connect_settings != undef and has_key( $connect_settings, 'PGPORT') {
23+
$port_override = undef
24+
} else {
25+
$port_override = $postgresql::server::port
26+
}
27+
28+
$onlyif = "SELECT tablename FROM pg_catalog.pg_tables WHERE
29+
schemaname NOT IN ('pg_catalog', 'information_schema') AND
30+
tableowner = '${old_role}'
31+
UNION ALL SELECT proname FROM pg_catalog.pg_proc WHERE
32+
pg_get_userbyid(proowner) = '${old_role}'
33+
UNION ALL SELECT viewname FROM pg_catalog.pg_views WHERE
34+
pg_views.schemaname NOT IN ('pg_catalog', 'information_schema') AND
35+
viewowner = '${old_role}'
36+
UNION ALL SELECT relname FROM pg_catalog.pg_class WHERE
37+
relkind='S' AND pg_get_userbyid(relowner) = '${old_role}'"
38+
39+
postgresql_psql { "reassign_owned_by:${db}:${sql_command}":
40+
command => $sql_command,
41+
db => $db,
42+
port => $port_override,
43+
connect_settings => $connect_settings,
44+
psql_user => $psql_user,
45+
psql_group => $group,
46+
psql_path => $psql_path,
47+
onlyif => $onlyif,
48+
require => Class['postgresql::server']
49+
}
50+
51+
if($old_role != undef and defined(Postgresql::Server::Role[$old_role])) {
52+
Postgresql::Server::Role[$old_role]->Postgresql_psql["reassign_owned_by:${db}:${sql_command}"]
53+
}
54+
if($new_role != undef and defined(Postgresql::Server::Role[$new_role])) {
55+
Postgresql::Server::Role[$new_role]->Postgresql_psql["reassign_owned_by:${db}:${sql_command}"]
56+
}
57+
58+
if($db != undef and defined(Postgresql::Server::Database[$db])) {
59+
Postgresql::Server::Database[$db]->Postgresql_psql["reassign_owned_by:${db}:${sql_command}"]
60+
}
61+
}
Lines changed: 135 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,135 @@
1+
require 'spec_helper_acceptance'
2+
3+
describe 'postgresql::server::reassign_owned_by:', :unless => UNSUPPORTED_PLATFORMS.include?(fact('osfamily')) do
4+
5+
let(:db) { 'reassign_test' }
6+
let(:old_owner) { 'psql_reassign_old_owner' }
7+
let(:new_owner) { 'psql_reassign_new_owner' }
8+
let(:password) { 'psql_reassign_pw' }
9+
let(:superuser) { 'postgres' }
10+
11+
let(:pp_setup) { pp_setup = <<-EOS.unindent
12+
$db = #{db}
13+
$old_owner = #{old_owner}
14+
$new_owner = #{new_owner}
15+
$password = #{password}
16+
17+
class { 'postgresql::server': }
18+
19+
postgresql::server::role { $old_owner:
20+
password_hash => postgresql_password($old_owner, $password),
21+
}
22+
23+
# Since we are not testing pg_hba or any of that, make a local user for ident auth
24+
user { $old_owner:
25+
ensure => present,
26+
}
27+
28+
# Create a user to reassign ownership to
29+
postgresql::server::role { $new_owner:
30+
db => $db,
31+
require => Postgresql::Server::Database[$db],
32+
}
33+
34+
# Make a local user for ident auth
35+
user { $new_owner:
36+
ensure => present,
37+
}
38+
39+
# Grant the new owner membership of the old owner (must have both for REASSIGN OWNED BY to work)
40+
postgresql::server::grant_role { "grant_role to ${new_owner}":
41+
role => $new_owner,
42+
group => $old_owner,
43+
}
44+
45+
# Grant them connect to the database
46+
postgresql::server::database_grant { "allow connect for ${old_owner}":
47+
privilege => 'CONNECT',
48+
db => $db,
49+
role => $old_owner,
50+
}
51+
EOS
52+
}
53+
54+
let(:pp_db_old_owner) { <<-EOS.unindent
55+
postgresql::server::database { $db:
56+
owner => $old_owner,
57+
require => Postgresql::Server::Role[$old_owner],
58+
}
59+
EOS
60+
}
61+
62+
let(:pp_db_no_owner) { <<-EOS.unindent
63+
postgresql::server::database { $db:
64+
}
65+
EOS
66+
}
67+
68+
context 'reassign_owned_by' do
69+
describe 'REASSIGN OWNED BY tests' do
70+
let(:db) { 'reassign_test' }
71+
let(:old_owner) { 'psql_reassign_old_owner' }
72+
let(:new_owner) { 'psql_reassign_new_owner' }
73+
74+
let(:pp_setup_objects) { <<-EOS.unindent
75+
postgresql_psql { 'create test table':
76+
command => 'CREATE TABLE test_tbl (col1 integer)',
77+
db => '#{db}',
78+
psql_user => '#{old_owner}',
79+
unless => "SELECT tablename FROM pg_catalog.pg_tables WHERE tablename = 'test_tbl'",
80+
require => Postgresql::Server::Database['#{db}'],
81+
}
82+
postgresql_psql { 'create test sequence':
83+
command => 'CREATE SEQUENCE test_seq',
84+
db => '#{db}',
85+
psql_user => '#{old_owner}',
86+
unless => "SELECT relname FROM pg_catalog.pg_class WHERE relkind='S' AND relname = 'test_seq'",
87+
require => [ Postgresql_psql['create test table'], Postgresql::Server::Database['#{db}'] ],
88+
}
89+
EOS
90+
}
91+
let(:pp_reassign_owned_by) { <<-EOS.unindent
92+
postgresql::server::reassign_owned_by { 'test reassign to new_owner':
93+
db => '#{db}',
94+
old_role => '#{old_owner}',
95+
new_role => '#{new_owner}',
96+
psql_user => '#{new_owner}',
97+
}
98+
EOS
99+
}
100+
101+
it 'should reassign all objects to new_owner' do
102+
begin
103+
apply_manifest(pp_setup + pp_db_old_owner + pp_setup_objects, :catch_failures => true)
104+
105+
#postgres version
106+
result = shell('psql --version')
107+
version = result.stdout.match(%r{\s(\d\.\d)})[1]
108+
109+
if version >= '9.0'
110+
111+
apply_manifest(pp_setup + pp_db_no_owner + pp_reassign_owned_by, :catch_failures => true)
112+
apply_manifest(pp_setup + pp_db_no_owner + pp_reassign_owned_by, :catch_changes => true)
113+
114+
## Check that the ownership was transferred
115+
psql("-d #{db} --tuples-only --no-align --command=\"SELECT tablename,tableowner FROM pg_catalog.pg_tables WHERE schemaname NOT IN ('pg_catalog', 'information_schema')\"", superuser) do |r|
116+
expect(r.stdout).to match(/test_tbl.#{new_owner}/)
117+
expect(r.stderr).to eq('')
118+
end
119+
psql("-d #{db} --tuples-only --no-align --command=\"SELECT relname,pg_get_userbyid(relowner) FROM pg_catalog.pg_class c WHERE relkind='S'\"", superuser) do |r|
120+
expect(r.stdout).to match(/test_seq.#{new_owner}/)
121+
expect(r.stderr).to eq('')
122+
end
123+
if version >= '9.3'
124+
psql("-d #{db} --tuples-only --no-align --command=\"SELECT pg_get_userbyid(datdba) FROM pg_database WHERE datname = current_database()\"", superuser) do |r|
125+
expect(r.stdout).to match(/#{new_owner}/)
126+
expect(r.stderr).to eq('')
127+
end
128+
end
129+
end
130+
end
131+
end # it should reassign all objects
132+
end
133+
end
134+
#####################
135+
end
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
require 'spec_helper'
2+
3+
describe 'postgresql::server::reassign_owned_by', :type => :define do
4+
let :facts do
5+
{
6+
:osfamily => 'Debian',
7+
:operatingsystem => 'Debian',
8+
:operatingsystemrelease => '6.0',
9+
:kernel => 'Linux',
10+
:concat_basedir => tmpfilename('reassign_owned_by'),
11+
:id => 'root',
12+
:path => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin',
13+
}
14+
end
15+
16+
let :title do
17+
'test'
18+
end
19+
20+
let :params do
21+
{
22+
:db => 'test',
23+
:old_role => 'test_old_role',
24+
:new_role => 'test_new_role',
25+
}
26+
end
27+
28+
let :pre_condition do
29+
<<-EOS
30+
class {'postgresql::server':}
31+
postgresql::server::role{ ['test_old_role','test_new_role']: }
32+
EOS
33+
end
34+
35+
it { is_expected.to contain_postgresql__server__reassign_owned_by('test') }
36+
37+
it {
38+
is_expected.to contain_postgresql_psql('reassign_owned_by:test:REASSIGN OWNED BY "test_old_role" TO "test_new_role"').with({
39+
'command' => "REASSIGN OWNED BY \"test_old_role\" TO \"test_new_role\"",
40+
'onlyif' => /SELECT tablename FROM pg_catalog.pg_tables WHERE\s*schemaname NOT IN \('pg_catalog', 'information_schema'\) AND\s*tableowner = 'test_old_role'.*/m,
41+
}).that_requires('Class[postgresql::server]')
42+
}
43+
44+
end

0 commit comments

Comments
 (0)