Skip to content

Commit 4dac726

Browse files
author
Helen
authored
Merge pull request #879 from eputnam/validate_db_connection
(MODULES-1394) replace validate_db_connection type with custom type
2 parents 286dc47 + 61ad33d commit 4dac726

File tree

12 files changed

+471
-90
lines changed

12 files changed

+471
-90
lines changed

README.md

Lines changed: 69 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -283,16 +283,16 @@ Only the specified parameters are recognized in the template. The `recovery.conf
283283

284284
### Validate connectivity
285285

286-
To validate client connections to a remote PostgreSQL database before starting dependent tasks, use the `postgresql::validate_db_connection` resource. You can use this on any node where the PostgreSQL client software is installed. It is often chained to other tasks such as starting an application server or performing a database migration.
286+
To validate client connections to a remote PostgreSQL database before starting dependent tasks, use the `postgresql_conn_validator` resource. You can use this on any node where the PostgreSQL client software is installed. It is often chained to other tasks such as starting an application server or performing a database migration.
287287

288288
Example usage:
289289

290290
```puppet
291-
postgresql::validate_db_connection { 'validate my postgres connection':
292-
database_host => 'my.postgres.host',
293-
database_username => 'mydbuser',
294-
database_password => 'mydbpassword',
295-
database_name => 'mydbname',
291+
postgresql_conn_validator { 'validate my postgres connection':
292+
host => 'my.postgres.host',
293+
db_username => 'mydbuser',
294+
db_password => 'mydbpassword',
295+
db_name => 'mydbname',
296296
}->
297297
exec { 'rake db:migrate':
298298
cwd => '/opt/myrubyapp',
@@ -332,13 +332,13 @@ The postgresql module comes with many options for configuring the server. While
332332
* [postgresql::server::schema](#postgresqlserverschema)
333333
* [postgresql::server::table_grant](#postgresqlservertable_grant)
334334
* [postgresql::server::tablespace](#postgresqlservertablespace)
335-
* [postgresql::validate_db_connection](#postgresqlvalidate_db_connection)
336335

337336
**Types:**
338337

339338
* [postgresql_psql](#custom-resource-postgresql_psql)
340339
* [postgresql_replication_slot](#custom-resource-postgresql_replication_slot)
341340
* [postgresql_conf](#custom-resource-postgresql_conf)
341+
* [postgresql_conn_validator](#custom-resource-postgresql_conn_validator)
342342

343343
**Functions:**
344344

@@ -367,13 +367,6 @@ Sets the name of the PostgreSQL client package.
367367

368368
Default value: 'file'.
369369

370-
##### `validcon_script_path`
371-
372-
Specifies the path to validate the connection script.
373-
374-
375-
Default value: '/usr/local/bin/validate_postgresql_connection.sh'.
376-
377370
#### postgresql::lib::docs
378371

379372
Installs PostgreSQL bindings for Postgres-Docs. Set the following parameters if you have a custom version you would like to install.
@@ -1543,64 +1536,6 @@ Specifies the name of the tablespace.
15431536

15441537
Default value: the namevar.
15451538

1546-
#### postgresql::validate_db_connection
1547-
1548-
Validates client connection with a remote PostgreSQL database.
1549-
1550-
##### `connect_settings`
1551-
1552-
Specifies a hash of environment variables used when connecting to a remote server. This is an alternative to providing individual parameters (`database_host`, etc). If provided, the individual parameters take precedence.
1553-
1554-
##### `create_db_first`
1555-
1556-
Ensures that the database is created before running the test. This only works if your test is local.
1557-
1558-
Default value: `true`.
1559-
1560-
##### `database_host`
1561-
1562-
Sets the hostname of the database you wish to test.
1563-
1564-
Default value: `undef`, which generally uses the designated local Unix socket.
1565-
1566-
##### `database_name`
1567-
1568-
Specifies the name of the database you wish to test.
1569-
1570-
Default value: 'postgres'.
1571-
1572-
##### `database_port`
1573-
1574-
Defines the port to use when connecting.
1575-
1576-
Default value: `undef`, which generally defaults to port 5432 depending on your PostgreSQL packaging.
1577-
1578-
##### `database_password`
1579-
1580-
Specifies the password to connect with. Can be left blank, not recommended.
1581-
1582-
##### `database_username`
1583-
1584-
Specifies the username to connect with.
1585-
1586-
Default value: `undef`.
1587-
1588-
When using a Unix socket and ident auth, this is the user you are running as.
1589-
1590-
**If the host is remote you must provide a username.**
1591-
1592-
##### `run_as`
1593-
1594-
Specifies the user to run the `psql` command as. This is important when trying to connect to a database locally using Unix sockets and `ident` authentication. Not needed for remote testing.
1595-
1596-
##### `sleep`
1597-
1598-
Sets the number of seconds to sleep for before trying again after a failure.
1599-
1600-
##### `tries`
1601-
1602-
Sets the number of attempts after failure before giving up and failing the resource.
1603-
16041539
### Types
16051540

16061541
#### postgresql_psql
@@ -1703,6 +1638,68 @@ Specifies the name of the slot to create. Must be a valid replication slot name.
17031638

17041639
This is the namevar.
17051640

1641+
#### postgresql_conn_validator
1642+
1643+
Validate the connection to a local or remote PostgreSQL database using this type.
1644+
1645+
##### `connect_settings`
1646+
1647+
Specifies a hash of environment variables used when connecting to a remote server. This is an alternative to providing individual parameters (`host`, etc). If provided, the individual parameters take precedence.
1648+
1649+
Default value: {}
1650+
1651+
##### `db_name`
1652+
1653+
Specifies the name of the database you wish to test.
1654+
1655+
Default value: ''
1656+
1657+
##### `db_password`
1658+
1659+
Specifies the password to connect with. Can be left blank if `.pgpass` is being used, otherwise not recommended.
1660+
1661+
Default value: ''
1662+
1663+
##### `db_username`
1664+
1665+
Specifies the username to connect with.
1666+
1667+
Default value: ''
1668+
1669+
When using a Unix socket and ident auth, this is the user you are running as.
1670+
1671+
##### `command`
1672+
1673+
This is the command run against the target database to verify connectivity.
1674+
1675+
Default value: 'SELECT 1'
1676+
1677+
##### `host`
1678+
1679+
Sets the hostname of the database you wish to test.
1680+
1681+
Default value: '', which generally uses the designated local Unix socket.
1682+
1683+
**If the host is remote you must provide a username.**
1684+
1685+
##### `port`
1686+
1687+
Defines the port to use when connecting.
1688+
1689+
Default value: ''
1690+
1691+
##### `run_as`
1692+
1693+
Specifies the user to run the `psql` command as. This is important when trying to connect to a database locally using Unix sockets and `ident` authentication. Not needed for remote testing.
1694+
1695+
##### `sleep`
1696+
1697+
Sets the number of seconds to sleep for before trying again after a failure.
1698+
1699+
##### `tries`
1700+
1701+
Sets the number of attempts after failure before giving up and failing the resource.
1702+
17061703
### Functions
17071704

17081705
#### postgresql_password
Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__),"..","..",".."))
2+
require 'puppet/util/postgresql_validator'
3+
4+
# This file contains a provider for the resource type `postgresql_conn_validator`,
5+
# which validates the puppetdb connection by attempting an https connection.
6+
7+
Puppet::Type.type(:postgresql_conn_validator).provide(:ruby) do
8+
desc "A provider for the resource type `postgresql_conn_validator`,
9+
which validates the PostgreSQL connection by attempting a query
10+
to the target PostgreSQL server."
11+
12+
# Test to see if the resource exists, returns true if it does, false if it
13+
# does not.
14+
#
15+
# Here we simply monopolize the resource API, to execute a test to see if the
16+
# database is connectable. When we return a state of `false` it triggers the
17+
# create method where we can return an error message.
18+
#
19+
# @return [bool] did the test succeed?
20+
def exists?
21+
validator.attempt_connection(resource[:sleep], resource[:tries])
22+
end
23+
24+
# This method is called when the exists? method returns false.
25+
#
26+
# @return [void]
27+
def create
28+
# If `#create` is called, that means that `#exists?` returned false, which
29+
# means that the connection could not be established... so we need to
30+
# cause a failure here.
31+
raise Puppet::Error, "Unable to connect to PostgreSQL server! (#{resource[:host]}:#{resource[:port]})"
32+
end
33+
34+
# Returns the existing validator, if one exists otherwise creates a new object
35+
# from the class.
36+
#
37+
# @api private
38+
def validator
39+
@validator ||= Puppet::Util::PostgresqlValidator.new(resource)
40+
end
41+
42+
end
43+
Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
Puppet::Type.newtype(:postgresql_conn_validator) do
2+
3+
@doc = "Verify that a connection can be successfully established between a node
4+
and the PostgreSQL server. Its primary use is as a precondition to
5+
prevent configuration changes from being applied if the PostgreSQL
6+
server cannot be reached, but it could potentially be used for other
7+
purposes such as monitoring."
8+
9+
ensurable do
10+
defaultvalues
11+
defaultto :present
12+
end
13+
14+
newparam(:name, :namevar => true) do
15+
desc 'An arbitrary name used as the identity of the resource.'
16+
end
17+
18+
newparam(:db_name) do
19+
desc "The name of the database you are trying to validate a connection with."
20+
end
21+
22+
newparam(:db_username) do
23+
desc "A user that has access to the target PostgreSQL database."
24+
end
25+
26+
newparam(:db_password) do
27+
desc "The password required to access the target PostgreSQL database."
28+
end
29+
30+
newparam(:host) do
31+
desc 'The DNS name or IP address of the server where PostgreSQL should be running.'
32+
end
33+
34+
newparam(:port) do
35+
desc 'The port that the PostgreSQL server should be listening on.'
36+
37+
validate do |value|
38+
Integer(value)
39+
end
40+
munge do |value|
41+
Integer(value)
42+
end
43+
end
44+
45+
newparam(:connect_settings) do
46+
desc 'Hash of environment variables for connection to a db.'
47+
end
48+
49+
newparam(:sleep) do
50+
desc "The length of sleep time between connection tries."
51+
52+
validate do |value|
53+
Integer(value)
54+
end
55+
munge do |value|
56+
Integer(value)
57+
end
58+
59+
defaultto 2
60+
end
61+
62+
newparam(:tries) do
63+
desc "The number of tries to validate the connection to the target PostgreSQL database."
64+
65+
validate do |value|
66+
Integer(value)
67+
end
68+
munge do |value|
69+
Integer(value)
70+
end
71+
72+
defaultto 10
73+
end
74+
75+
newparam(:psql_path) do
76+
desc "Path to the psql command."
77+
end
78+
79+
newparam(:run_as) do
80+
desc "System user that will run the psql command."
81+
end
82+
83+
newparam(:command) do
84+
desc "Command to run against target database."
85+
86+
defaultto "SELECT 1"
87+
end
88+
end
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
module Puppet
2+
module Util
3+
class PostgresqlValidator
4+
attr_reader :resource
5+
6+
def initialize(resource)
7+
@resource = resource
8+
end
9+
10+
def build_psql_cmd
11+
final_cmd = []
12+
13+
cmd_init = "#{@resource[:psql_path]} --tuples-only --quiet --no-psqlrc"
14+
15+
final_cmd.push cmd_init
16+
17+
cmd_parts = {
18+
:host => "--host=#{@resource[:host]}",
19+
:port => "--port=#{@resource[:port]}",
20+
:db_username => "--username=#{@resource[:db_username]}",
21+
:db_name => "--dbname=#{@resource[:db_name]}",
22+
:command => "--command='#{@resource[:command]}'"
23+
}
24+
25+
cmd_parts[:db_password] = "--no-password " if @resource[:db_password]
26+
27+
cmd_parts.each do |k,v|
28+
final_cmd.push v if @resource[k]
29+
end
30+
31+
final_cmd.join ' '
32+
end
33+
34+
def parse_connect_settings
35+
c_settings = @resource[:connect_settings] || {}
36+
c_settings.merge! ({ 'PGPASSWORD' => @resource[:db_password] }) if @resource[:db_password]
37+
return c_settings.map { |k,v| "#{k}=#{v}" }
38+
end
39+
40+
def attempt_connection(sleep_length, tries)
41+
(0..tries-1).each do |try|
42+
Puppet.debug "PostgresqlValidator.attempt_connection: Attempting connection to #{@resource[:db_name]}"
43+
if execute_command =~ /1/
44+
Puppet.debug "PostgresqlValidator.attempt_connection: Connection to #{@resource[:db_name]} successful!"
45+
return true
46+
else
47+
Puppet.warning "PostgresqlValidator.attempt_connection: Sleeping for #{sleep_length} seconds"
48+
sleep sleep_length
49+
end
50+
end
51+
false
52+
end
53+
54+
private
55+
56+
def execute_command
57+
Execution.execute(build_validate_cmd, :uid => @resource[:run_as])
58+
end
59+
60+
def build_validate_cmd
61+
"#{parse_connect_settings.join(' ')} #{build_psql_cmd} "
62+
end
63+
end
64+
end
65+
end

manifests/server/db.pp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,7 @@
3838
privilege => $grant,
3939
db => $dbname,
4040
role => $user,
41-
} -> Postgresql::Validate_db_connection<| database_name == $dbname |>
41+
} -> Postgresql_conn_validator<| db_name == $dbname |>
4242
}
4343

4444
if($tablespace != undef and defined(Postgresql::Server::Tablespace[$tablespace])) {

0 commit comments

Comments
 (0)