Skip to content

Commit c4c0402

Browse files
author
Travis Fields
committed
Merge pull request puppetlabs#527 from kimor79/psql-onlyif
2 parents 5b2c017 + 39f15c3 commit c4c0402

File tree

4 files changed

+89
-17
lines changed

4 files changed

+89
-17
lines changed

lib/puppet/type/postgresql_psql.rb

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,28 @@ def matches(value)
4343
end
4444
end
4545

46+
newparam(:onlyif) do
47+
desc "An optional SQL command to execute prior to the main :command; " +
48+
"this is generally intended to be used for idempotency, to check " +
49+
"for the existence of an object in the database to determine whether " +
50+
"or not the main SQL command needs to be executed at all."
51+
52+
# Return true if a matching row is found
53+
def matches(value)
54+
if Puppet::PUPPETVERSION.to_f < 4
55+
output, status = provider.run_unless_sql_command(value)
56+
else
57+
output = provider.run_unless_sql_command(value)
58+
status = output.exitcode
59+
end
60+
self.fail("Error evaluating 'onlyif' clause, returned #{status}: '#{output}'") unless status == 0
61+
62+
result_count = output.strip.to_i
63+
self.debug("Found #{result_count} row(s) executing 'onlyif' clause")
64+
result_count > 0
65+
end
66+
end
67+
4668
newparam(:db) do
4769
desc "The name of the database to execute the SQL command against."
4870
end
@@ -97,7 +119,9 @@ def matches(value)
97119
end
98120

99121
def should_run_sql(refreshing = false)
122+
onlyif_param = @parameters[:onlyif]
100123
unless_param = @parameters[:unless]
124+
return false if !onlyif_param.nil? && !onlyif_param.value.nil? && !onlyif_param.matches(onlyif_param.value)
101125
return false if !unless_param.nil? && !unless_param.value.nil? && unless_param.matches(unless_param.value)
102126
return false if !refreshing && @parameters[:refreshonly].value == :true
103127
true

manifests/server/grant.pp

Lines changed: 22 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,13 @@
22
define postgresql::server::grant (
33
$role,
44
$db,
5-
$privilege = undef,
6-
$object_type = 'database',
7-
$object_name = undef,
8-
$psql_db = $postgresql::server::default_database,
9-
$psql_user = $postgresql::server::user,
10-
$port = $postgresql::server::port
5+
$privilege = undef,
6+
$object_type = 'database',
7+
$object_name = undef,
8+
$psql_db = $postgresql::server::default_database,
9+
$psql_user = $postgresql::server::user,
10+
$port = $postgresql::server::port,
11+
$onlyif_exists = false,
1112
) {
1213
$group = $postgresql::server::group
1314
$psql_path = $postgresql::server::psql_path
@@ -18,6 +19,8 @@
1819
$_object_name = $object_name
1920
}
2021

22+
validate_bool($onlyif_exists)
23+
2124
## Munge the input values
2225
$_object_type = upcase($object_type)
2326
$_privilege = upcase($privilege)
@@ -59,6 +62,7 @@
5962
'ALL','ALL PRIVILEGES')
6063
$unless_function = 'has_database_privilege'
6164
$on_db = $psql_db
65+
$onlyif_function = undef
6266
}
6367
'SCHEMA': {
6468
$unless_privilege = $_privilege ? {
@@ -69,6 +73,7 @@
6973
validate_string($_privilege, 'CREATE', 'USAGE', 'ALL', 'ALL PRIVILEGES')
7074
$unless_function = 'has_schema_privilege'
7175
$on_db = $db
76+
$onlyif_function = undef
7277
}
7378
'TABLE': {
7479
$unless_privilege = $_privilege ? {
@@ -79,12 +84,17 @@
7984
'TRUNCATE','REFERENCES','TRIGGER','ALL','ALL PRIVILEGES')
8085
$unless_function = 'has_table_privilege'
8186
$on_db = $db
87+
$onlyif_function = $onlyif_exists ? {
88+
true => 'table_exists',
89+
default => undef,
90+
}
8291
}
8392
'ALL TABLES IN SCHEMA': {
8493
validate_string($_privilege,'SELECT','INSERT','UPDATE','DELETE',
8594
'TRUNCATE','REFERENCES','TRIGGER','ALL','ALL PRIVILEGES')
8695
$unless_function = 'custom'
8796
$on_db = $db
97+
$onlyif_function = undef
8898

8999
$schema = $object_name
90100

@@ -150,6 +160,11 @@
150160
'${_granted_object}', '${unless_privilege}')",
151161
}
152162

163+
$_onlyif = $onlyif_function ? {
164+
'table_exists' => "SELECT true FROM pg_tables WHERE tablename = '${_togrant_object}'",
165+
default => undef,
166+
}
167+
153168
$grant_cmd = "GRANT ${_privilege} ON ${_object_type} \"${_togrant_object}\" TO
154169
\"${role}\""
155170
postgresql_psql { "grant:${name}":
@@ -160,6 +175,7 @@
160175
psql_group => $group,
161176
psql_path => $psql_path,
162177
unless => $_unless,
178+
onlyif => $_onlyif,
163179
require => Class['postgresql::server']
164180
}
165181

manifests/server/table_grant.pp

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -5,18 +5,20 @@
55
$table,
66
$db,
77
$role,
8-
$port = $postgresql::server::port,
9-
$psql_db = undef,
10-
$psql_user = undef
8+
$port = $postgresql::server::port,
9+
$psql_db = undef,
10+
$psql_user = undef,
11+
$onlyif_exists = false,
1112
) {
1213
postgresql::server::grant { "table:${name}":
13-
role => $role,
14-
db => $db,
15-
port => $port,
16-
privilege => $privilege,
17-
object_type => 'TABLE',
18-
object_name => $table,
19-
psql_db => $psql_db,
20-
psql_user => $psql_user,
14+
role => $role,
15+
db => $db,
16+
port => $port,
17+
privilege => $privilege,
18+
object_type => 'TABLE',
19+
object_name => $table,
20+
psql_db => $psql_db,
21+
psql_user => $psql_user,
22+
onlyif_exists => $onlyif_exists,
2123
}
2224
}

spec/acceptance/postgresql_psql_spec.rb

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -114,6 +114,36 @@ class { 'postgresql::server': } ->
114114
end
115115
end
116116

117+
it 'should not run some SQL when the onlyif query returns no rows' do
118+
pp = <<-EOS
119+
class { 'postgresql::server': } ->
120+
postgresql_psql { 'foobar':
121+
db => 'postgres',
122+
psql_user => 'postgres',
123+
command => 'select 1',
124+
onlyif => 'select 1 where 1=2',
125+
}
126+
EOS
127+
128+
apply_manifest(pp, :catch_failures => true)
129+
apply_manifest(pp, :expect_changes => true)
130+
end
131+
132+
it 'should run SQL when the onlyif query returns rows' do
133+
pp = <<-EOS
134+
class { 'postgresql::server': } ->
135+
postgresql_psql { 'foobar':
136+
db => 'postgres',
137+
psql_user => 'postgres',
138+
command => 'select * from pg_database limit 1',
139+
onlfy => 'select 1 where 1=1',
140+
}
141+
EOS
142+
143+
apply_manifest(pp, :catch_failures => true)
144+
apply_manifest(pp, :catch_changes => true)
145+
end
146+
117147
context 'with secure password passing by environment' do
118148
it 'should run SQL that contanins password passed by environment' do
119149
select = "select \\'$PASS_TO_EMBED\\'"

0 commit comments

Comments
 (0)