Initial commit

This commit is contained in:
vic 2012-10-22 16:41:23 +04:00
commit 9e1b438ce7
36 changed files with 1746 additions and 0 deletions

View File

@ -0,0 +1,6 @@
*.swp
pkg/
.DS_Store
metadata.json
coverage/
.project

View File

@ -0,0 +1,9 @@
2012-09-17 - Version 0.3.0 released
2012-09-14 - Chris Price <chris@puppetlabs.com>
* Add a type for validating a postgres connection (ce4a049)
2012-08-25 - Jari Bakken <jari.bakken@gmail.com>
* Remove trailing commas. (e6af5e5)
2012-08-16 - Version 0.2.0 released

View File

@ -0,0 +1,202 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS
APPENDIX: How to apply the Apache License to your work.
To apply the Apache License to your work, attach the following
boilerplate notice, with the fields enclosed by brackets "[]"
replaced with your own identifying information. (Don't include
the brackets!) The text should be enclosed in the appropriate
comment syntax for the file format. We also recommend that a
file or class name and description of purpose be included on the
same "printed page" as the copyright notice for easier
identification within third-party archives.
Copyright [yyyy] [name of copyright owner]
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

View File

@ -0,0 +1,11 @@
name 'inkling-postgresql'
version '0.3.0'
author 'Inkling'
license 'Apache'
project_page 'https://github.com/inkling/puppet-postgresql'
source 'git://github.com/inkling/puppet-postgresql.git'
summary 'PostgreSQL defined resource types'
description 'PostgreSQL defined resource types'
dependency 'puppetlabs/stdlib', '>=2.4.0'
dependency 'puppetlabs/firewall', '>=0.0.4'

View File

@ -0,0 +1,82 @@
Puppet module for PostgreSQL resources
======================================
This module provides the following defined resource types for managing postgres:
* `postgresql::initdb`
* `postgresql::db`
* `postgresql::role`
* `postgresql::user` (just for clarity; users are roles in postgres)
* `postgresql::grant`
And the fallback, analogous to exec resources, only for SQL statements:
* `postgresql::psql`
Basic usage
-----------
postgresql::user{'marmot':
password => 'foo',
}
postgresql::grant{'grant select to marmot':
grantee => 'marmot',
on_object => 'my_table',
perm => 'select',
require => Postgresql::User['marmot'],
}
etc, etc.
Automated testing
-----------------
Install and setup an [RVM](http://beginrescueend.com/) with
[vagrant](http://vagrantup.com/),
[sahara](https://github.com/jedi4ever/sahara), and
[rspec](http://rspec.info/)
$ curl -L get.rvm.io | bash -s stable
$ rvm install 1.9.3
$ rvm use --create 1.9.3@puppet-postgresql
$ gem install vagrant sahara rspec
Run the tests like so:
$ (cd spec; vagrant up)
$ rspec -f -d -c
The test suite will snapshot the VM and rollback between each test.
Next, take a look at the manifests used for the automated tests.
spec/
manifests/
test_*.pp
Contributors
------------
* Andrew Moon
* [Kenn Knowles](https://github.com/kennknowles) ([@kennknowles](https://twitter.com/KennKnowles))
Copyright and License
---------------------
Copyright 2012 Inkling Systems, Inc.
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.

View File

@ -0,0 +1,30 @@
def get_debian_postgres_version
depends = Facter::Util::Resolution.exec('apt-cache show postgresql |grep "^Depends" |head -n 1')
if match = /^Depends: postgresql-(.*)$/.match(depends)
match[1]
else
nil
end
end
def get_redhat_postgres_version
version = Facter::Util::Resolution.exec('yum info postgresql-server |grep "^Version"')
if match = /^Version\s*:\s*(\d+\.\d+).*$/.match(version)
match[1]
else
nil
end
end
Facter.add("postgres_default_version") do
setcode do
case Facter.value('osfamily')
when 'RedHat'
get_redhat_postgres_version()
when 'Debian'
get_debian_postgres_version()
else
nil
end
end
end

View File

@ -0,0 +1,18 @@
# hash a string as mysql's "PASSWORD()" function would do it
require 'digest/md5'
module Puppet::Parser::Functions
newfunction(:postgresql_password, :type => :rvalue, :doc => <<-EOS
Returns the postgresql password hash from the clear text username / password.
EOS
) do |args|
raise(Puppet::ParseError, "postgresql_password(): Wrong number of arguments " +
"given (#{args.size} for 2)") if args.size != 2
username = args[0]
password = args[1]
'md5' + Digest::MD5.hexdigest(password + username)
end
end

View File

@ -0,0 +1,64 @@
# Class: postgresql::config
#
# Parameters:
#
# [*postgres_password*] - postgres db user password.
# [*ip_mask_deny_postgres_user*] - ip mask for denying remote access for postgres user; defaults to '0.0.0.0/0',
# meaning that all TCP access for postgres user is denied.
# [*ip_mask_allow_all_users*] - ip mask for allowing remote access for other users (besides postgres);
# defaults to '127.0.0.1/32', meaning only allow connections from localhost
# [*listen_addresses*] - what IP address(es) to listen on; comma-separated list of addresses; defaults to
# 'localhost', '*' = all
# [*pg_hba_conf_path*] - path to pg_hba.conf file
# [*postgresql_conf_path*] - path to postgresql.conf file
# [*manage_redhat_firewall*] - boolean indicating whether or not the module should open a port in the firewall on
# redhat-based systems; this parameter is likely to change in future versions. Possible
# changes include support for non-RedHat systems and finer-grained control over the
# firewall rule (currently, it simply opens up the postgres port to all TCP connections).
#
#
# Actions:
#
# Requires:
#
# Usage:
#
# class { 'postgresql::config':
# postgres_password => 'postgres',
# ip_mask_allow_all_users => '0.0.0.0/0',
# }
#
class postgresql::config(
$postgres_password = undef,
$ip_mask_deny_postgres_user = $postgresql::params::ip_mask_postgres_user,
$ip_mask_allow_all_users = $postgresql::params::ip_mask_all_users,
$listen_addresses = $postgresql::params::listen_addresses,
$pg_hba_conf_path = $postgresql::params::pg_hba_conf_path,
$postgresql_conf_path = $postgresql::params::postgresql_conf_path,
$manage_redhat_firewall = $postgresql::params::manage_redhat_firewall
) inherits postgresql::params {
# Basically, all this class needs to handle is passing parameters on
# to the "beforeservice" and "afterservice" classes, and ensure
# the proper ordering.
class { "postgresql::config::beforeservice":
ip_mask_deny_postgres_user => $ip_mask_deny_postgres_user,
ip_mask_allow_all_users => $ip_mask_allow_all_users,
listen_addresses => $listen_addresses,
pg_hba_conf_path => $pg_hba_conf_path,
postgresql_conf_path => $postgresql_conf_path,
manage_redhat_firewall => $manage_redhat_firewall,
}
class { "postgresql::config::afterservice":
postgres_password => $postgres_password,
}
Class['postgresql::config'] ->
Class['postgresql::config::beforeservice'] ->
Service['postgresqld'] ->
Class['postgresql::config::afterservice']
}

View File

@ -0,0 +1,44 @@
# Class: postgresql::config::afterservice
#
# Parameters:
#
# [*postgres_password*] - postgres db user password.
#
# Actions:
#
# Requires:
#
# Usage:
# This class is not intended to be used directly; it is
# managed by postgresl::config. It contains resources
# that should be handled *after* the postgres service
# has been started up.
#
# class { 'postgresql::config::afterservice':
# postgres_password => 'postgres'
# }
#
class postgresql::config::afterservice(
$postgres_password = undef
) inherits postgresql::params {
if ($postgres_password != undef) {
# NOTE: this password-setting logic relies on the pg_hba.conf being configured
# to allow the postgres system user to connect via psql without specifying
# a password ('ident', 'peer', or 'trust' security). This is the default
# for pg_hba.conf.
exec { 'set_postgres_postgrespw':
# This command works w/no password because we run it as postgres system user
command => "psql -c \"ALTER ROLE postgres PASSWORD '$postgres_password'\"",
user => $postgresql::params::user,
group => $postgresql::params::group,
logoutput => true,
cwd => '/tmp',
# With this command we're passing -h to force TCP authentication, which does require
# a password. We specify the password via the PGPASSWORD environment variable. If
# the password is correct (current), this command will exit with an exit code of 0,
# which will prevent the main command from running.
unless => "env PGPASSWORD=\"$postgres_password\" psql -h localhost -c 'select 1' > /dev/null",
path => '/usr/bin:/usr/local/bin',
}
}
}

View File

@ -0,0 +1,85 @@
# Class: postgresql::config::beforeservice
#
# Parameters:
#
# [*ip_mask_deny_postgres_user*] - ip mask for denying remote access for postgres user; defaults to '0.0.0.0/0',
# meaning that all TCP access for postgres user is denied.
# [*ip_mask_allow_all_users*] - ip mask for allowing remote access for other users (besides postgres);
# defaults to '127.0.0.1/32', meaning only allow connections from localhost
# [*listen_addresses*] - what IP address(es) to listen on; comma-separated list of addresses; defaults to
# 'localhost', '*' = all
# [*pg_hba_conf_path*] - path to pg_hba.conf file
# [*postgresql_conf_path*] - path to postgresql.conf file
# [*manage_redhat_firewall*] - boolean indicating whether or not the module should open a port in the firewall on
# redhat-based systems; this parameter is likely to change in future versions. Possible
# changes include support for non-RedHat systems and finer-grained control over the
# firewall rule (currently, it simply opens up the postgres port to all TCP connections).
#
# Actions:
#
# Requires:
#
# Usage:
# This class is not intended to be used directly; it is
# managed by postgresl::config. It contains resources
# that should be handled *before* the postgres service
# has been started up.
#
# class { 'postgresql::config::before_service':
# ip_mask_allow_all_users => '0.0.0.0/0',
# }
#
class postgresql::config::beforeservice(
$ip_mask_deny_postgres_user = $postgresql::params::ip_mask_deny_postgres_user,
$ip_mask_allow_all_users = $postgresql::params::ip_mask_allow_all_users,
$listen_addresses = $postgresql::params::listen_addresses,
$pg_hba_conf_path = $postgresql::params::pg_hba_conf_path,
$postgresql_conf_path = $postgresql::params::postgresql_conf_path,
$manage_redhat_firewall = $postgresql::params::manage_redhat_firewall
) inherits postgresql::params {
File {
owner => $postgresql::params::user,
group => $postgresql::params::group,
}
# We use a templated version of pg_hba.conf. Our main needs are to
# make sure that md5 authentication can be made available for
# remote hosts.
file { 'pg_hba.conf':
ensure => file,
path => $pg_hba_conf_path,
content => template("postgresql/pg_hba.conf.erb"),
notify => Service['postgresqld'],
}
# We must set a "listen_addresses" line in the postgresql.conf if we
# want to allow any connections from remote hosts.
file_line { 'postgresql.conf':
path => $postgresql_conf_path,
match => '^listen_addresses\s*=.*$',
line => "listen_addresses = '${listen_addresses}'",
notify => Service['postgresqld'],
}
# TODO: is this a reasonable place for this firewall stuff?
# TODO: figure out a way to make this not platform-specific; debian and ubuntu have
# an out-of-the-box firewall configuration that seems trickier to manage
# TODO: get rid of hard-coded port
if ($manage_redhat_firewall and $firewall_supported) {
exec { "persist-firewall":
command => $persist_firewall_command,
refreshonly => true,
}
Firewall {
notify => Exec["persist-firewall"]
}
firewall { '5432 accept - postgres':
port => '5432',
proto => 'tcp',
action => 'accept',
}
}
}

View File

@ -0,0 +1,49 @@
# puppet-postgresql
# For all details and documentation:
# http://github.com/inkling/puppet-postgresql
#
# Copyright 2012- Inkling Systems, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# TODO: in order to match up more closely with the mysql module, this probably
# needs to be moved over to ruby, and add support for ensurable.
define postgresql::database(
$dbname = $title,
$charset = 'UTF8')
{
require postgresql::params
if ($::postgres_default_version != "8.1") {
$locale_option = "--locale=C"
}
$createdb_command = "${postgresql::params::createdb_path} --template=template0 --encoding '$charset' $locale_option '$dbname'"
exec { $createdb_command :
unless => "${postgresql::params::psql_path} --command=\"SELECT datname FROM pg_database WHERE datname=\'$dbname\' \" --pset=tuples_only | grep -q $dbname",
user => 'postgres',
}
# This will prevent users from connecting to the database unless they've been
# granted privileges.
postgresql::psql {"REVOKE CONNECT ON DATABASE $dbname FROM public":
db => 'postgres',
user => 'postgres',
unless => 'SELECT 1 where 1 = 0',
refreshonly => true,
subscribe => Exec[$createdb_command],
}
}

View File

@ -0,0 +1,58 @@
# puppet-postgresql
# For all details and documentation:
# http://github.com/inkling/puppet-postgresql
#
# Copyright 2012- Inkling Systems, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# TODO: in mysql module, the grant resource name might look like this: 'user@host/dbname';
# I think that the API for the resource type should split these up, because it's
# easier / safer to recombine them for mysql than it is to parse them for other
# databases. Also, in the mysql module, the hostname portion of that string
# affects the user's ability to connect from remote hosts. In postgres this is
# managed via pg_hba.conf; not sure if we want to try to reconcile that difference
# in the modules or not.
define postgresql::database_grant(
# TODO: mysql supports an array of privileges here. We should do that if we
# port this to ruby.
$privilege,
$db,
$role,
$psql_db = 'postgres',
$psql_user='postgres'
) {
# TODO: FIXME: only works on databases, due to using has_database_privilege
# TODO: this is a terrible hack; if they pass "ALL" as the desired privilege,
# we need a way to test for it--and has_database_privilege does not recognize
# 'ALL' as a valid privilege name. So we probably need to hard-code a mapping
# between 'ALL' and the list of actual privileges that it entails, and loop
# over them to check them. That sort of thing will probably need to wait until
# we port this over to ruby, so, for now, we're just going to assume that if
# they have "CREATE" privileges on a database, then they have "ALL". (I told
# you that it was terrible!)
$unless_privilege = $privilege ? {
'ALL' => 'CREATE',
default => $privilege,
}
postgresql::psql {"GRANT $privilege ON database $db TO $role":
db => $psql_db,
user => $psql_user,
unless => "SELECT 1 WHERE has_database_privilege('$role', '$db', '$unless_privilege')",
}
}

View File

@ -0,0 +1,56 @@
# puppet-postgresql
# For all details and documentation:
# http://github.com/inkling/puppet-postgresql
#
# Copyright 2012- Inkling Systems, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
# Define: postgresql::database_user
#
# This type creates a postgres database user.
#
# Parameters:
# [*user*] - username to create.
# [*password_hash*] - user's password; this may be clear text, or an md5 hash as returned by the
# "postgresql_password" function in this module.
#
# Actions:
#
# Requires:
#
#
# Sample Usage:
#
# postgresql::database_user { 'frank':
# password_hash => postgresql_password('frank', 'password'),
# }
#
define postgresql::database_user(
$user=$title,
$password_hash,
$db = 'postgres',
$createdb=false,
$superuser=false,
$createrole=false
) {
postgresql::role {$user:
db => $db,
password_hash => $password_hash,
login => true,
createdb => $createdb,
superuser => $superuser,
createrole => $createrole,
}
}

View File

@ -0,0 +1,65 @@
# Define: postgresql::db
#
# This module creates database instances, a user, and grants that user
# privileges to the database.
#
# Since it requires class postgresql::server, we assume to run all commands as the
# postgresql user against the local postgresql server.
#
# TODO: support an array of privileges for "grant"; currently only supports a single
# privilege, which is pretty useless unless that privilege is "ALL"
#
# Parameters:
# [*title*] - postgresql database name.
# [*user*] - username to create and grant access.
# [*password*] - user's password. may be md5-encoded, in the format returned by the "postgresql_password"
# function in this module
# [*charset*] - database charset.
# [*grant*] - privilege to grant user.
#
# Actions:
#
# Requires:
#
# class postgresql::server
#
# Sample Usage:
#
# postgresql::db { 'mydb':
# user => 'my_user',
# password => 'password',
# grant => 'all'
# }
#
define postgresql::db (
$user,
$password,
$charset = 'utf8',
$grant = 'ALL'
) {
postgresql::database { $name:
# TODO: ensure is not yet supported
#ensure => present,
charset => $charset,
#provider => 'postgresql',
require => Class['postgresql::server'],
}
postgresql::database_user { "${user}":
# TODO: ensure is not yet supported
#ensure => present,
password_hash => $password,
#provider => 'postgresql',
require => Postgresql::Database[$name],
}
postgresql::database_grant { "GRANT ${user} - ${grant} - ${name}":
privilege => $grant,
db => $name,
role => $user,
#provider => 'postgresql',
require => Postgresql::Database_user["${user}"],
}
}

View File

@ -0,0 +1,24 @@
# Class: postgresql
#
# This class installs postgresql client software.
#
# Parameters:
# [*client_package_name*] - The name of the postgresql client package.
#
# Actions:
#
# Requires:
#
# Sample Usage:
#
class postgresql (
$package_name = $postgresql::params::client_package_name,
$package_ensure = 'present'
) inherits postgresql::params {
package { 'postgresql_client':
name => $package_name,
ensure => $package_ensure,
}
}

View File

@ -0,0 +1,33 @@
# puppet-postgresql
# For all details and documentation:
# http://github.com/inkling/puppet-postgresql
#
# Copyright 2012- Inkling Systems, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
class postgresql::initdb(
$datadir = $postgresql::params::datadir,
$initdb_path = $postgresql::params::initdb_path,
$user = 'postgres',
$group = 'postgres',
$encoding = 'UTF8',
$options=''
) inherits postgresql::params {
exec {"${initdb_path} --encoding '$encoding' --pgdata '$datadir'":
creates => "${datadir}/PG_VERSION",
user => "$user",
group => "$group",
}
}

View File

@ -0,0 +1,90 @@
# Class: postgresql::params
#
# The postgresql configuration settings.
#
# Parameters:
#
# Actions:
#
# Requires:
#
# Sample Usage:
#
class postgresql::params {
$user = 'postgres'
$group = 'postgres'
$ip_mask_deny_postgres_user = '0.0.0.0/0'
$ip_mask_allow_all_users = '127.0.0.1/32'
$listen_addresses = 'localhost'
# TODO: figure out a way to make this not platform-specific
$manage_redhat_firewall = false
# This is a bit hacky, but if the puppet nodes don't have pluginsync enabled,
# they will fail with a not-so-helpful error message. Here we are explicitly
# verifying that the custom fact exists (which implies that pluginsync is
# enabled and succeeded). If not, we fail with a hint that tells the user
# that pluginsync might not be enabled. Ideally this would be handled directly
# in puppet.
if ($::postgres_default_version == undef) {
fail "No value for postgres_default_version facter fact; it's possible that you don't have pluginsync enabled."
}
case $::operatingsystem {
default: {
$service_provider = undef
}
}
case $::osfamily {
'RedHat': {
$service_name = 'postgresql'
$client_package_name = 'postgresql'
$server_package_name = 'postgresql-server'
$needs_initdb = true
$initdb_path = '/usr/bin/initdb'
$createdb_path = '/usr/bin/createdb'
$psql_path = '/usr/bin/psql'
$datadir = '/var/lib/pgsql/data/'
$pg_hba_conf_path = '/var/lib/pgsql/data/pg_hba.conf'
$postgresql_conf_path = '/var/lib/pgsql/data/postgresql.conf'
$firewall_supported = true
$persist_firewall_command = '/sbin/iptables-save > /etc/sysconfig/iptables'
}
'Debian': {
case $::operatingsystem {
'Debian': {
$service_name = "postgresql"
}
'Ubuntu': {
case $::lsbmajdistrelease {
# thanks, ubuntu
'10': { $service_name = "postgresql-${::postgres_default_version}" }
default: { $service_name = "postgresql" }
}
}
}
$client_package_name = 'postgresql-client'
$server_package_name = 'postgresql'
$needs_initdb = false
$initdb_path = "/usr/lib/postgresql/${::postgres_default_version}/bin/initdb"
$createdb_path = "/usr/lib/postgresql/${::postgres_default_version}/bin/createdb"
$psql_path = "/usr/lib/postgresql/${::postgres_default_version}/bin/psql"
$datadir = "/var/lib/postgresql/${::postgres_default_version}/main"
$pg_hba_conf_path = "/etc/postgresql/${::postgres_default_version}/main/pg_hba.conf"
$postgresql_conf_path = "/etc/postgresql/${::postgres_default_version}/main/postgresql.conf"
$firewall_supported = false
# TODO: not exactly sure yet what the right thing to do for Debian/Ubuntu is.
#$persist_firewall_command = '/sbin/iptables-save > /etc/iptables/rules.v4'
}
default: {
fail("Unsupported osfamily: ${::osfamily} operatingsystem: ${::operatingsystem}, module ${module_name} currently only supports osfamily RedHat and Debian")
}
}
}

View File

@ -0,0 +1,49 @@
# puppet-postgresql
# For all details and documentation:
# http://github.com/inkling/puppet-postgresql
#
# Copyright 2012- Inkling Systems, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
define postgresql::psql(
$command = $title,
$unless,
$db,
$user = 'postgres',
$refreshonly = false
) {
require postgresql::params
# TODO: FIXME: shellquote does not work, and this regex works for trivial things but not nested escaping.
# Need a lexer, preferably a ruby SQL parser to catch errors at catalog time
# Possibly https://github.com/omghax/sql ?
if ($::postgres_default_version != "8.1") {
$no_password_option = "--no-password"
}
$psql = "${postgresql::params::psql_path} $no_password_option --tuples-only --quiet --dbname $db"
$quoted_command = regsubst($command, '"', '\\"')
$quoted_unless = regsubst($unless, '"', '\\"')
exec {"/bin/echo \"$quoted_command\" | $psql |egrep -v -q '^$'":
cwd => '/tmp',
user => $user,
returns => 1,
unless => "/bin/echo \"$quoted_$unless\" | $psql | egrep -v -q '^$'",
refreshonly => $refreshonly,
}
}

View File

@ -0,0 +1,40 @@
# puppet-postgresql
# For all details and documentation:
# http://github.com/inkling/puppet-postgresql
#
# Copyright 2012- Inkling Systems, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
define postgresql::role(
$username=$title,
$password_hash,
$db='postgres',
$login=false,
$createrole=false,
$createdb=false,
$superuser=false
) {
$login_sql = $login ? { true => 'LOGIN' , false => 'NOLOGIN' }
$createrole_sql = $createrole ? { true => 'CREATEROLE', false => 'NOCREATEROLE' }
$createdb_sql = $createdb ? { true => 'CREATEDB' , false => 'NOCREATEDB' }
$superuser_sql = $superuser ? { true => 'SUPERUSER' , false => 'NOSUPERUSER' }
# TODO: FIXME: Will not correct the superuser / createdb / createrole / login status of a role that already exists
postgresql::psql {"CREATE ROLE ${username} ENCRYPTED PASSWORD '${password_hash}' $login_sql $createrole_sql $createdb_sql $superuser_sql":
db => $db,
user => 'postgres',
unless => "SELECT rolname FROM pg_roles WHERE rolname='$username'",
}
}

View File

@ -0,0 +1,51 @@
# Class: postgresql::server
#
# manages the installation of the postgresql server. manages the package and service
#
# Parameters:
# [*package_name*] - name of package
# [*service_name*] - name of service
#
# Actions:
#
# Requires:
#
# Sample Usage:
#
class postgresql::server (
$package_name = $postgresql::params::server_package_name,
$package_ensure = 'present',
$service_name = $postgresql::params::service_name,
$service_provider = $postgresql::params::service_provider,
$config_hash = {}
) inherits postgresql::params {
package { 'postgresql-server':
name => $package_name,
ensure => $package_ensure,
}
$config_class = {}
$config_class['postgresql::config'] = $config_hash
create_resources( 'class', $config_class )
Package['postgresql-server'] -> Class['postgresql::config']
if ($needs_initdb) {
include postgresql::initdb
Class['postgresql::initdb'] -> Class['postgresql::config']
Class['postgresql::initdb'] -> Service['postgresqld']
}
service { 'postgresqld':
name => $service_name,
ensure => running,
enable => true,
require => Package['postgresql-server'],
provider => $service_provider,
}
}

View File

@ -0,0 +1,95 @@
# Define: postgresql::validate_db_connection
#
# This type validates that a successful postgres connection can be established
# between the node on which this resource is run and a specified postgres
# instance (host/port/user/password/database name).
#
# Parameters:
# [*database_host*] - the hostname or IP address of the machine where the
# postgres server should be running.
# [*database_port*] - the port on which postgres server should be
# listening (defaults to 5432).
# [*database_username*] - the postgres username
# [*database_password*] - the postgres user's password
# [*database_name*] - the database name that the connection should be
# established against
# [*client_package_name*] - (optional) the name of the postgres client package
# that provides the psql tool, if you aren't using
# the default system package.
#
# NOTE: to some degree this type assumes that you've created the corresponding
# postgres database instance that you are validating by using the
# `postgresql::db` or `postgresql::database` type provided by this module
# elsewhere in your manifests.
#
# Actions:
#
# Attempts to establish a connection to the specified postgres database. If
# a connection cannot be established, the resource will fail; this allows you
# to use it as a dependency for other resources that would be negatively
# impacted if they were applied without the postgres connection being available.
#
# Requires:
#
# `psql` commandline tool (will automatically install the system's postgres
# client package if it is not already installed.)
#
# Sample Usage:
#
# postgresql::validate_db_connection { 'validate my postgres connection':
# database_host => 'my.postgres.host',
# database_username => 'mydbuser',
# database_password => 'mydbpassword',
# database_name => 'mydbname',
# }
#
define postgresql::validate_db_connection(
$database_host,
$database_port = 5432,
$database_username,
$database_password,
$database_name,
$client_package_name = "",
) {
include postgresql::params
# This is a bit messy, but we need to use the correct client package name
# from the params class if the user did not explicitly provide one.
if (! $client_package_name) {
$package_name = $postgresql::params::client_package_name
} else {
$package_name = $client_package_name
}
# Make sure the postgres client package is installed; we need it for
# `psql`.
package { 'postgresql-client':
name => $package_name,
ensure => present,
}
# TODO: port to ruby
$psql = "${postgresql::params::psql_path} --tuples-only --quiet -h $database_host -U $database_username -p $database_port --dbname $database_name"
$exec_name = "validate postgres connection for $database_host/$database_name"
exec {$exec_name:
command => "/bin/echo \"SELECT 1\" | $psql",
cwd => '/tmp',
environment => "PGPASSWORD=$database_password",
logoutput => 'on_failure',
require => Package['postgresql-client'],
}
# This is a little bit of puppet magic. What we want to do here is make
# sure that if the validation and the database instance creation are being
# applied on the same machine, then the database resource is applied *before*
# the validation resource. Otherwise, the validation is guaranteed to fail
# on the first run.
#
# We accomplish this by using Puppet's resource collection syntax to search
# for the Database resource in our current catalog; if it exists, the
# appropriate relationship is created here.
Database<|title == $database_name|> -> Exec[$exec_name]
}

View File

@ -0,0 +1,46 @@
# -*- mode: ruby -*-
# vi: set ft=ruby :
# puppet-postgresql
# For all details and documentation:
# http://github.com/inkling/puppet-postgresql
#
# Copyright 2012- Inkling Systems, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
Vagrant::Config.run do |config|
# Test on 64 bit lucid
config.vm.box = "lucid64"
config.vm.box_url = "http://files.vagrantup.com/lucid64.box"
# Resolve DNS via NAT
config.vm.customize ["modifyvm", :id, "--natdnshostresolver1", "on"]
# Share the stdlib module
# TODO: it would be better to install this via the puppet module tool
config.vm.share_folder "puppetlabs-stdlib-module", "/usr/share/puppet/modules/stdlib", "../../puppetlabs-stdlib"
# Share the postgressql module
config.vm.share_folder "puppet-postgresql-module", "/usr/share/puppet/modules/postgresql", ".."
# Share the module of test classes
config.vm.share_folder "puppet-postgresql-tests", "/usr/share/puppet/modules/postgresql_tests", "."
# Provision with a base puppet config just so we don't have to repeat the puppet user/group
config.vm.provision :puppet do |puppet|
puppet.manifests_path = "."
puppet.manifest_file = "base.pp"
end
end

View File

@ -0,0 +1,34 @@
# puppet-postgresql
# For all details and documentation:
# http://github.com/inkling/puppet-postgresql
#
# Copyright 2012- Inkling Systems, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
group {'puppet':
ensure => present,
}
user {'puppet':
ensure => present,
gid => 'puppet',
}
file {'/etc/sudoers.d/puppet_postgresql_tests':
ensure => file,
content => 'vagrant ALL=(ALL) ALL',
mode => 0440,
owner => root,
group => root,
}

View File

@ -0,0 +1,27 @@
# puppet-postgresql
# For all details and documentation:
# http://github.com/inkling/puppet-postgresql
#
# Copyright 2012- Inkling Systems, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
class postgresql_tests::test_db($db) {
include postgresql::server
postgresql::db { $db:
user => $db,
password => $db,
}
}

View File

@ -0,0 +1,45 @@
# puppet-postgresql
# For all details and documentation:
# http://github.com/inkling/puppet-postgresql
#
# Copyright 2012- Inkling Systems, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
class postgresql_tests::test_grant_create($user, $password, $db) {
include postgresql::server
# Since we are not testing pg_hba or any of that, make a local user for ident auth
user { $user:
ensure => present,
}
postgresql::database_user { $user:
password_hash => postgresql_password($user, $password),
require => [ Class['postgresql::server'],
User[$user] ],
}
postgresql::database { $db:
require => Class['postgresql::server'],
}
postgresql::database_grant { "grant create test":
privilege => 'CREATE',
db => $db,
role => $user,
require => [ Postgresql::Database[$db],
Postgresql::Database_user[$user] ],
}
}

View File

@ -0,0 +1,26 @@
# puppet-postgresql
# For all details and documentation:
# http://github.com/inkling/puppet-postgresql
#
# Copyright 2012- Inkling Systems, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
class postgresql_tests::test_initdb {
include postgresql::server
class { "postgresql::initdb":
require => Class['postgresql::server']
}
}

View File

@ -0,0 +1,30 @@
# puppet-postgresql
# For all details and documentation:
# http://github.com/inkling/puppet-postgresql
#
# Copyright 2012- Inkling Systems, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
class postgresql_tests::test_psql($command = $title, $unless) {
include postgresql::server
postgresql::psql { $title:
db => 'postgres',
user => 'postgres',
command => $command,
unless => $unless,
require => Class['postgresql::server'],
}
}

View File

@ -0,0 +1,33 @@
# puppet-postgresql
# For all details and documentation:
# http://github.com/inkling/puppet-postgresql
#
# Copyright 2012- Inkling Systems, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
class postgresql_tests::test_user($user, $password) {
include postgresql::server
# Since we are not testing pg_hba or any of that, make a local user for ident auth
user { $user:
ensure => present,
}
postgresql::database_user { $user:
password_hash => postgresql_password($user, $password),
require => [ Class['postgresql::server'],
User[$user] ],
}
}

View File

@ -0,0 +1,152 @@
# puppet-postgresql
# For all details and documentation:
# http://github.com/inkling/puppet-postgresql
#
# Copyright 2012- Inkling Systems, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
require 'logger'
require 'vagrant'
# VM-based tests for postgresql::* defined resource types.
#
# The general structure is:
#
# - Roll back the VM
# - Apply a minimal puppet config for the type and fail only on crashes
# - Apply it again and fail if there were any new changes reported
# - Check the state of the system
describe "postgresql" do
def sudo_and_log(*args)
@logger.debug("Running command: '#{args[0]}'")
@env.primary_vm.channel.sudo(args[0]) do |ch, data|
@logger.debug(data)
end
end
before(:all) do
@logger = Logger.new(STDOUT)
@logger.level = Logger::DEBUG # TODO: get from environment or rspec?
vagrant_dir = File.dirname(__FILE__)
@env = Vagrant::Environment::new(:cwd => vagrant_dir)
# Sahara ignores :cwd so we have to chdir for now, see https://github.com/jedi4ever/sahara/issues/9
Dir.chdir(vagrant_dir)
# @env.cli("destroy") # Takes too long
@env.cli("up")
# We are not testing the "package" resource type, so pull stuff in in advance
sudo_and_log('apt-get update')
sudo_and_log('apt-get install --yes --download-only postgresql-8.4')
@env.cli("sandbox", "on")
end
after(:each) do
@env.cli("sandbox", "rollback")
end
describe 'postgresql::initdb' do
it "should idempotently create a working --pgdata directory so postgres can run" do
@logger.info("starting")
# A bare-minimum class to initdb the specified dir
test_class = 'class {"postgresql_tests::test_initdb": }'
# Run once to check for crashes
sudo_and_log("puppet apply -e '#{test_class}'")
# Run again to check for idempotence via --detailed-exitcodes
sudo_and_log("puppet apply --detailed-exitcodes -e '#{test_class}'")
sudo_and_log("service postgresql-8.4 restart")
# Connect to it and list the databases
sudo_and_log('sudo -n -u postgres /usr/lib/postgresql/8.4/bin/psql --list --tuples-only')
end
end
describe 'postgresql::db' do
it 'should idempotently create a db that we can connect to' do
# A bare-minimum class to add a DB to postgres, which will be running due to ubuntu
test_class = 'class {"postgresql_tests::test_db": db => "postgresql_test_db" }'
# Run once to check for crashes
sudo_and_log("puppet apply -e '#{test_class}'")
# Run again to check for idempotence
sudo_and_log("puppet apply --detailed-exitcodes -e '#{test_class}'")
# Check that the database name is present
sudo_and_log('sudo -u postgres psql postgresql_test_db --command="select datname from pg_database limit 1"')
end
end
describe 'postgresql::psql' do
it 'should run some SQL when the unless query returns no rows' do
test_class = 'class {"postgresql_tests::test_psql": command => "SELECT \'foo\'", unless => "SELECT 1 WHERE 1=2" }'
# Run once to get all packages set up
sudo_and_log("puppet apply -e '#{test_class}'")
# Check for exit code 2
sudo_and_log("puppet apply --detailed-exitcodes -e '#{test_class}' ; [ $? == 2 ]")
end
it 'should not run SQL when the unless query returns rows' do
test_class = 'class {"postgresql_tests::test_psql": command => "SELECT * FROM pg_datbase limit 1", unless => "SELECT 1 WHERE 1=1" }'
# Run once to get all packages set up
sudo_and_log("puppet apply -e '#{test_class}'")
# Check for exit code 0
sudo_and_log("puppet apply --detailed-exitcodes -e '#{test_class}'")
end
end
describe 'postgresql::user' do
it 'should idempotently create a user who can log in' do
test_class = 'class {"postgresql_tests::test_user": user => "postgresql_test_user", password => "postgresql_test_password" }'
# Run once to check for crashes
sudo_and_log("puppet apply -e '#{test_class}'")
# Run again to check for idempotence
sudo_and_log("puppet apply --detailed-exitcodes -e '#{test_class}'")
# Check that the user can log in
sudo_and_log('sudo -u postgresql_test_user psql --command="select datname from pg_database limit 1" postgres')
end
end
describe 'postgresql::grant' do
it 'should grant access so a user can create in a database' do
test_class = 'class {"postgresql_tests::test_grant_create": db => "postgres", user => "psql_grant_tester", password => "psql_grant_pw" }'
# Run once to check for crashes
sudo_and_log("puppet apply -e '#{test_class}'")
# Run again to check for idempotence
sudo_and_log("puppet apply --detailed-exitcodes -e '#{test_class}'")
# Check that the user can select from the table in
sudo_and_log('sudo -u psql_grant_tester psql --command="create table foo (foo int)" postgres')
end
end
end

View File

@ -0,0 +1,88 @@
# PostgreSQL Client Authentication Configuration File
# ===================================================
#
# Refer to the "Client Authentication" section in the
# PostgreSQL documentation for a complete description
# of this file. A short synopsis follows.
#
# This file controls: which hosts are allowed to connect, how clients
# are authenticated, which PostgreSQL user names they can use, which
# databases they can access. Records take one of these forms:
#
# local DATABASE USER METHOD [OPTIONS]
# host DATABASE USER CIDR-ADDRESS METHOD [OPTIONS]
# hostssl DATABASE USER CIDR-ADDRESS METHOD [OPTIONS]
# hostnossl DATABASE USER CIDR-ADDRESS METHOD [OPTIONS]
#
# (The uppercase items must be replaced by actual values.)
#
# The first field is the connection type: "local" is a Unix-domain socket,
# "host" is either a plain or SSL-encrypted TCP/IP socket, "hostssl" is an
# SSL-encrypted TCP/IP socket, and "hostnossl" is a plain TCP/IP socket.
#
# DATABASE can be "all", "sameuser", "samerole", a database name, or
# a comma-separated list thereof.
#
# USER can be "all", a user name, a group name prefixed with "+", or
# a comma-separated list thereof. In both the DATABASE and USER fields
# you can also write a file name prefixed with "@" to include names from
# a separate file.
#
# CIDR-ADDRESS specifies the set of hosts the record matches.
# It is made up of an IP address and a CIDR mask that is an integer
# (between 0 and 32 (IPv4) or 128 (IPv6) inclusive) that specifies
# the number of significant bits in the mask. Alternatively, you can write
# an IP address and netmask in separate columns to specify the set of hosts.
#
# METHOD can be "trust", "reject", "md5", "password", "gss", "sspi", "krb5",
# "ident", "pam", "ldap" or "cert". Note that "password" sends passwords
# in clear text; "md5" is preferred since it sends encrypted passwords.
#
# OPTIONS are a set of options for the authentication in the format
# NAME=VALUE. The available options depend on the different authentication
# methods - refer to the "Client Authentication" section in the documentation
# for a list of which options are available for which authentication methods.
#
# Database and user names containing spaces, commas, quotes and other special
# characters must be quoted. Quoting one of the keywords "all", "sameuser" or
# "samerole" makes the name lose its special character, and just match a
# database or username with that name.
#
# This file is read on server startup and when the postmaster receives
# a SIGHUP signal. If you edit the file on a running system, you have
# to SIGHUP the postmaster for the changes to take effect. You can use
# "pg_ctl reload" to do that.
# Put your actual configuration here
# ----------------------------------
#
# If you want to allow non-local connections, you need to add more
# "host" records. In that case you will also need to make PostgreSQL listen
# on a non-local interface via the listen_addresses configuration parameter,
# or via the -i or -h command line switches.
#
# DO NOT DISABLE!
# If you change this first entry you will need to make sure that the
# database
# super user can access the database using some other method.
# Noninteractive
# access to all databases is required during automatic maintenance
# (custom daily cronjobs, replication, and similar tasks).
#
# Database administrative login by UNIX sockets
local all postgres ident <%= "sameuser" if @postgres_default_version == "8.1" %>
# TYPE DATABASE USER CIDR-ADDRESS METHOD
# "local" is for Unix domain socket connections only
local all all ident <%= "sameuser" if @postgres_default_version == "8.1" %>
# IPv4 local connections:
host all postgres <%= @ip_mask_deny_postgres_user + "\t" %> reject
host all all <%= @ip_mask_allow_all_users + "\t" %> md5
# IPv6 local connections:
host all all ::1/128 md5

View File

@ -0,0 +1 @@
include postgresql

View File

@ -0,0 +1,22 @@
class { 'postgresql::server':
config_hash => {
'ip_mask_deny_postgres_user' => '0.0.0.0/32',
'ip_mask_allow_all_users' => '0.0.0.0/0',
'listen_addresses' => '*',
'manage_redhat_firewall' => true,
'postgres_password' => 'postgres',
},
}
postgresql::database{ ['test1', 'test2', 'test3']:
# TODO: ensure not yet supported
#ensure => present,
charset => 'utf8',
require => Class['postgresql::server'],
}
postgresql::database{ 'test4':
# TODO: ensure not yet supported
#ensure => present,
charset => 'latin1',
require => Class['postgresql::server'],
}

View File

@ -0,0 +1,30 @@
class { 'postgresql::server':
config_hash => {
'ip_mask_allow_all_users' => '0.0.0.0/0',
'listen_addresses' => '*',
'manage_redhat_firewall' => true,
#'ip_mask_deny_postgres_user' => '0.0.0.0/32',
#'postgres_password' => 'puppet',
},
}
postgresql::db{ 'test1':
user => 'test1',
password => 'test1',
grant => 'all',
}
postgresql::db{ 'test2':
user => 'test2',
password => postgresql_password('test2', 'test2'),
grant => 'all',
}
postgresql::db{ 'test3':
user => 'test3',
# The password here is a copy/paste of the output of the 'postgresql_password'
# function from this module, with a u/p of 'test3', 'test3'.
password => 'md5e12234d4575a12bfd61d61294f32b086',
grant => 'all',
}

View File

@ -0,0 +1,14 @@
# TODO: in mysql module, the grant resource name might look like this: 'user@host/dbname';
# I think that the API for the resource type should split these up, because it's
# easier / safer to recombine them for mysql than it is to parse them for other
# databases. Also, in the mysql module, the hostname portion of that string
# affects the user's ability to connect from remote hosts. In postgres this is
# managed via pg_hba.conf; not sure if we want to try to reconcile that difference
# in the modules or not.
postgresql::database_grant{'test1':
# TODO: mysql supports an array of privileges here. We should do that if we
# port this to ruby.
privilege => 'ALL',
db => 'test1',
role => 'dan',
}

View File

@ -0,0 +1,28 @@
class { 'postgresql::server':
config_hash => {
'ip_mask_deny_postgres_user' => '0.0.0.0/32',
'ip_mask_allow_all_users' => '0.0.0.0/0',
'listen_addresses' => '*',
'manage_redhat_firewall' => true,
'postgres_password' => 'postgres',
},
}
# TODO: in mysql module, the username includes, e.g., '@%' or '@localhost', which
# affects the user's ability to connect from remote hosts. In postgres this is
# managed via pg_hba.conf; not sure if we want to try to reconcile that difference
# in the modules or not.
postgresql::database_user{ 'redmine':
# TODO: ensure is not yet supported
#ensure => present,
password_hash => postgresql_password('redmine', 'redmine'),
require => Class['postgresql::server'],
}
postgresql::database_user{ 'dan':
# TODO: ensure is not yet supported
#ensure => present,
password_hash => postgresql_password('dan', 'blah'),
require => Class['postgresql::server'],
}

View File

@ -0,0 +1,9 @@
class { 'postgresql::server':
config_hash => {
'ip_mask_deny_postgres_user' => '0.0.0.0/32',
'ip_mask_allow_all_users' => '0.0.0.0/0',
'listen_addresses' => '*',
'manage_redhat_firewall' => true,
'postgres_password' => 'postgres',
},
}