diff --git a/.gitignore b/.gitignore index 0cd25de..f6e8b46 100644 --- a/.gitignore +++ b/.gitignore @@ -1,12 +1,24 @@ #This file is generated by ModuleSync, do not edit. pkg/ Gemfile.lock +Gemfile.local vendor/ spec/fixtures/manifests/ spec/fixtures/modules/ +log/ +junit/ .vagrant/ .bundle/ coverage/ log/ .idea/ +.metadata *.iml +.*.sw[op] +.yardoc +.yardwarns +.DS_Store +tmp/ +vendor/ +doc/ + diff --git a/.project b/.project index a680a0b..96606a4 100644 --- a/.project +++ b/.project @@ -1,23 +1,23 @@ - postgresql + puppetlabs-postgresql - org.cloudsmith.geppetto.pp.dsl.ui.modulefileBuilder + com.puppetlabs.geppetto.pp.dsl.ui.modulefileBuilder org.eclipse.xtext.ui.shared.xtextBuilder - org.cloudsmith.geppetto.pp.dsl.ui.puppetNature + com.puppetlabs.geppetto.pp.dsl.ui.puppetNature org.eclipse.xtext.ui.shared.xtextNature diff --git a/.sync.yml b/.sync.yml index 781584a..5850fed 100644 --- a/.sync.yml +++ b/.sync.yml @@ -1,20 +1,7 @@ --- -.travis.yml: - includes: - - rvm: 2.3.1 - env: PUPPET_GEM_VERSION="~> 4.0" STDLIB_LOG_DEPRECATIONS="false" - bundler_args: --without system_tests - - rvm: 2.1.9 - env: PUPPET_GEM_VERSION="~> 4.0" STDLIB_LOG_DEPRECATIONS="false" - bundler_args: --without system_tests - - rvm: 2.1.5 - env: PUPPET_GEM_VERSION="~> 3.0" FUTURE_PARSER="yes" - bundler_args: --without system_tests - - rvm: 2.1.5 - env: PUPPET_GEM_VERSION="~> 3.0" - bundler_args: --without system_tests - - rvm: 1.9.3 - env: PUPPET_GEM_VERSION="~> 3.0" - bundler_args: --without system_tests +NOTICE: + unmanaged: true +appveyor.yml: + delete: true spec/spec_helper.rb: allow_deprecations: true diff --git a/.travis.yml b/.travis.yml index 6b0a097..4981b25 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,38 +1,32 @@ #This file is generated by ModuleSync, do not edit. --- sudo: false language: ruby cache: bundler -script: "bundle exec rake validate lint spec" +script: "bundle exec rake release_checks" +#Inserting below due to the following issue: https://github.com/travis-ci/travis-ci/issues/3531#issuecomment-88311203 +before_install: + - gem update bundler matrix: fast_finish: true include: - rvm: 2.3.1 dist: trusty env: PUPPET_INSTALL_TYPE=agent BEAKER_debug=true BEAKER_set=docker/ubuntu-14.04 script: bundle exec rake beaker services: docker sudo: required - rvm: 2.3.1 dist: trusty env: PUPPET_INSTALL_TYPE=agent BEAKER_debug=true BEAKER_set=docker/centos-7 script: bundle exec rake beaker services: docker sudo: required - rvm: 2.3.1 bundler_args: --without system_tests - env: PUPPET_GEM_VERSION="~> 4.0" STDLIB_LOG_DEPRECATIONS="false" - - rvm: 2.1.9 + env: PUPPET_GEM_VERSION="~> 4.0" + - rvm: 2.1.7 bundler_args: --without system_tests - env: PUPPET_GEM_VERSION="~> 4.0" STDLIB_LOG_DEPRECATIONS="false" - - rvm: 2.1.5 - bundler_args: --without system_tests - env: PUPPET_GEM_VERSION="~> 3.0" FUTURE_PARSER="yes" - - rvm: 2.1.5 - bundler_args: --without system_tests - env: PUPPET_GEM_VERSION="~> 3.0" - - rvm: 1.9.3 - bundler_args: --without system_tests - env: PUPPET_GEM_VERSION="~> 3.0" + env: PUPPET_GEM_VERSION="~> 4.0" notifications: email: false diff --git a/CHANGELOG.md b/CHANGELOG.md index e5e0299..e4480c7 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,864 +1,856 @@ ## Supported Release 4.8.0 ### Summary This release primarily fixes an issue with `postgresql_conf` values of ipaddresses being considered floats and not getting quoted. #### Features - Add `default_connect_settings` parameter to `postgresql::server` - Running under strict variables is now supported - Add timestamps into logs by default #### Bugfixes - Obscure password in postgresql\_psql type - Fix ip address quoting in postgresql\_conf type - Fix handling of systemd service on Ubuntu - Mark log_min_duration_statement setting as requiring a service restart - Add fixes for Fedora 23, Fedora 24, FreeBSD, OpenBSD - Fix environment handling to avoid "Overriding environment setting" message - Work around PUP-6385, using empty arrays instead of undef when specifying resource relationships - README editorial pass - Reduce whitespace in templates - Update build/test infrastructure ## Supported Release 4.7.1 ### Summary This release contains some bugfixes and documentation updates. #### Bugfixes - (MODULES-3024) Quote database objects when creating databases. - Properly escape case where password ends with '$'. - Fixes password change when postgres is configure to non-standard port. - Unpins concat dependency to be able to use concat 2.x. - Workaround to fix installing on Amazon Linux. - Fixes proper defaulting of `$service_provider` parameter. - Fixes postgres server init script naming on Amazon Linux. - Fixes service reload parameter on Arch Linux. - Adds missing onlyif_function to sequence grant code. - Fixes to the markdown of the README. ## Supported Release 4.7.0 ### Summary A release with a considerable amount of new features, including remote db support and several platform support updates. Various bugfixes including several to address warnings and a sizable README update. #### Features - Remote DB support - Connection-settings allows a hash of options that can be used when connecting to a remote DB. - Debian 8 support. - Updated systemd-override to support fedora and CentOS paths. - Adds the ability to define the extension name separately from the title of the resource, which allows you to add the extension to more than one database. - Added parameter to disable automatic service restarts on config changes. - Ubuntu 15.10 compatibility. - OpenBSD version is now 9.4. - Added .gitattributes to maintain line endings for .sh and .rb files. - Adds default postgis version for 9.5. - Allows float postgresql_conf values. - Schedule apt update after install of repo. #### Bugfixes - Fixed systemd-override for RedHat systems with unmanaged Yum repos. - Removed inherits postgresql::params. - Multi-node tests are now not ran by default. - Change apt::pin to apt_postgresql_org to prevent error message. - Removed syntax error near UTF8. - Removal of extra blanks and backslashes in README. - Double quotes now used around database name to prevent syntax error. - Removes ruby 1.8.7 and puppet 2.7 from travis-ci jobs. - Fixed paths to work on Amazon Linux. - Fixed quotes around locale options. - Huge README update. - Update to use current msync configs. - Fixes postgresql::server acceptance test descriptions. ## Supported Release 4.6.1 ###Summary Small release for support of newer PE versions. This increments the version of PE in the metadata.json file. ## 2015-09-01 - Supported Release 4.6.0 ### Summary This release adds a proxy feature for yum, Postgis improvements, and decoupling pg_hba_rule from postgresql::server. #### Features - Support setting a proxy for yum operations - Allow for undefined PostGIS version - Decouple pg_hba_rule from postgresql::server #### Bugfixes - Fix postgis default package name on RedHat ## 2015-07-27 - Supported Release 4.5.0 ### Summary This release adds sequence grants, some postgresql 9.4 fixes, and `onlyif` to the psql resource. ### Features - Add `onlyif` parameter to `postgresql_psql` - Add unsupported compatibility with Ubuntu 15.04 - Add unsupported compatibility with SLES 11/12 and OpenSuSE 13.2 - Add `postgresql::server::grant::onlyif_exists` attribute - Add `postgresql::server::table_grant::onlyif_exists` attribute - Add granting permissions on sequences ### Bugfixes - Added docs for `postgresql::server::grant` - Fix `pg_hba_conf_defaults => false` to not disable ipv4/ipv6 acls - Fix 9.4 for `postgresql::server::pg_hba_rule` ## 2015-07-07 - Supported Release 4.4.2 ### Summary This release fixes a bug introduced in 4.4.0. #### Bugfixes - Fixes `withenv` execution under Puppet 2.7. (MODULES-2185) ## 2015-07-01 - Supported Release 4.4.1 ### Summary This release fixes RHEL 7 & Fedora with manage_package_repo switched on. #### Bugfixes - Ensure manage_package_repo variable is in scope for systemd-override file for RHEL7 ## 2015-06-30 - Supported Release 4.4.0 ### Summary This release has several new features, bugfixes, and test improvements. #### Features - Adds a resource to manage recovery.conf. - Adds a parameter that allows the specification of a validate connection script in `postgresql::client`. - Adds support for plpython package management. - Adds support for postgresql-docs management. - Adds ability to make `postgresql::server::schema` titles unique. (MODULES-2049) - Updates puppetlabs-apt module dependency to support version 2.1.0. #### Bugfixes - Fix `postgresql_psql` parameter ordering to work on OpenBSD with Future Parser - Fix setting postgres role password (MODULES-1869) - Fix execution command with puppet <3.4 (MODULES-1923) - Fix Puppet.newtype deprecation warning (MODULES-2007) - Fix systemd override for manage_repo package versions - Fix Copy snakeoil certificate and key instead of symlinking #### Test Improvements - Allows setting BEAKER and BEAKER_RSPEC versions via environment variables. - Enables Unit testing on Travis CI with Puppet 4. - Cleans up spec_helper_acceptance.rb to use new puppet_install_helper gem. ## 2015-03-24 - Supported Release 4.3.0 ### Summary This release fixes compatibility with Puppet 4 and removes opportunities for local users to view the postgresql password. It also adds a new custom resource to aid in managing replication. #### Features - Add `postgresql::server::logdir` parameter to manage the logdir - Add `environment` parameter to `postgresql_psql` - Add `postgresql_replication_slot` custom resource #### Bugfixes - Fix for Puppet 4 - Don't print postgresql\_psql password in command - Allow `postgresql::validate_db_connection` for more than one host+port+database combo - Fix service command on Debian 8 and up - Fix `postgresql::server::extension` to work with custom user/group/port - Fix `postgresql::server::initdb` to work with custom user/group/port - Fix changing template1 encoding - Fix default `postgresql::server::grant::object_name` value - Fix idempotency of granting all tables in schema with `puppet::server::grant` - Fix lint warnings - Fix apt key to use 40 character key and bump puppetlabs-apt to >= 1.8.0 < 2.0.0 ##2015-03-10 - Supported Release 4.2.0 ###Summary This release has several new features including support for server extensions, improved grant support, and a number of bugfixes. ####Features - Changes to support OpenBSD - Add `service_reload` parameter to `postgresql::server` - Add `comment` parameter to `postgresql::server::database` (MODULES-1153) - Add `postgresql::server::extension` defined type - Add postgresql versions for utopic and jessie - Update `postgresql::server::grant` to support 'GRANT SCHEMA' and 'ALL TABLES IN SCHEMA' ####Bugfixes - Lint cleanup - Remove outdated upgrade info from README - Use correct TCP port when checking password - Create role before database - Fix template1 encoding on Debian - Require server package before user permissions - Fix `service_status` default for FreeBSD to allow PostgreSQL to start the first run - Fix invalid US-ASCII byte sequence in `postgresql::server::grant` comments - Reverted to default behavior for Debian systems as `pg_config` should not be overwritten (MODULES-1485) ##2014-11-04 - Supported Release 4.1.0 ###Summary This release adds the ability to change the PGDATA directory, and also includes documentation and test updates, future parser support, and a few other new features. ####Features - Future parser support - Documentation updates - Test updates - Add a link from `/etc/sysconfig/pgsql/postgresql-${version}` to `/etc/sysconfig/pgsql/postgresql` to support init scripts from the postgresql.org repo - Add support for changing the PGDATA directory - Set default versions for Fedora 21 and FreeBSD ##2014-09-03 - Supported Release 4.0.0 ###Summary This release removes the uninstall ability from the module, removes the firewall management, overhauls all of the acceptance testing, as well as adds better support for SuSE and Fedora. ###Backwards Incompatible changes. - Uninstall code removal. - Firewall management for Postgres. - Set manage_pg_ident_conf to true. ####Uninstallation removal We rely heavily on the ability to uninstall and reinstall postgres throughout our testing code, testing features like "can I move from the distribution packages to the upstream packages through the module" and over time we've learnt that the uninstall code simply doesn't work a lot of the time. It leaves traces of postgres behind or fails to remove certain packages on Ubuntu, and generally causes bits to be left on your system that you didn't expect. When we then reinstall things fail because it's not a true clean slate, and this causes us enormous problems during test. We've spent weeks and months working on these tests and they simply don't hold up well across the full range of PE platforms. Due to all these problems we've decided to take a stance on uninstalling in general. We feel that in 2014 it's completely reasonable and normal to have a good provisioning pipeline combined with your configuration management and the "correct" way to uninstall a fully installed service like postgresql is to simply reprovision the server without it in the first place. As a general rule this is how I personally like to work and I think is a good practice. ####I'm not OK with this! We understand that there are environments and situations in which it's not easy to do that. What if you accidently deployed Postgres on 100,000 nodes? In the future we're going to take a look at building some example 'profiles' to be found under examples/ within this module that can uninstall postgres on popular platforms. These can be modified and used in your specific case to uninstall postgresql. They will be much more brute force and reliant on deleting entire directories and require you to do more work up front in specifying where things are installed but we think it'll prove to be a much cleaner mechanism for this kind of thing rather than trying to weave it into the main module logic itself. ####Features - Removal of uninstall. - Removal of firewall management. - Tests ported to rspec3. - Acceptance tests rewritten. - Add a defined type for creating database schemas. - Add a pg_ident_rule defined type. - Set manage_pg_ident_conf to true. - Manage pg_ident.conf by default. - Improve selinux support for tablespace. - Remove deprecation warnings. - Support changing PGDATA on RedHat. - Add SLES 11 support. ####Bugfixes - Link pg_config binary into /usr/bin. - Fix fedora support by using systemd. - Initdb should create xlogdir if set. - -##2014-08-27 - Supported Release 3.4.3 -###Summary - -This release fixes Ubuntu 10.04 with Facter 2.2. - -####Features -####Bugfixes - Use a regular expression to match the major OS version on Ubuntu. ##2014-07-31 - Supported Release 3.4.2 ###Summary This release fixes recent Fedora versions. ####Features ####Bugfixes - Fix Fedora. ##2014-07-15 - Supported Release 3.4.1 ###Summary This release merely updates metadata.json so the module can be uninstalled and upgraded via the puppet module command. ##2014-04-14 - Supported Release 3.4.0 ###Summary This feature rolls up several important features, the biggest being PostGIS handling and allowing `port` to be set on postgresql::server in order to change the port that Postgres listens on. We've added support for RHEL7 and Ubuntu 14.04, as well as allowing you to manage the service via `service_ensure` finally. ####Features - Added `perl_package_name` for installing bindings. - Added `service_ensure` for allowing control of services. - Added `postgis_version` and postgis class for installing postgis. - Added `port` for selecting the port Postgres runs on. - Add support for RHEL7 and Ubuntu 14.04. - Add `default_db` to postgresql::server::database. - Widen the selection of unquoted parameters in postgresql_conf{} - Require the service within postgresql::server::reload for RHEL7. - Add `inherit` to postgresql::server::role. ####Bugfixes ##2014-03-04 - Supported Release 3.3.3 ###Summary This is a supported release. This release removes a testing symlink that can cause trouble on systems where /var is on a seperate filesystem from the modulepath. ####Features ####Bugfixes ####Known Bugs * SLES is not supported. ##2014-03-04 - Supported Release 3.3.2 ###Summary This is a supported release. It fixes a problem with updating passwords on postgresql.org distributed versions of PostgreSQL. ####Bugfixes - Correct psql path when setting password on custom versions. - Documentation updates - Test updates ####Known Bugs * SLES is not supported. ##2014-02-12 - Version 3.3.1 ####Bugfix: - Allow dynamic rubygems host ##2014-01-28 - Version 3.3.0 ###Summary This release rolls up a bunch of bugfixes our users have found and fixed for us over the last few months. This improves things for 9.1 users, and makes this module usable on FreeBSD. This release is dedicated to 'bma', who's suffering with Puppet 3.4.1 issues thanks to Puppet::Util::SUIDManager.run_and_capture. ####Features - Add lc_ config entry settings - Can pass template at database creation. - Add FreeBSD support. - Add support for customer `xlogdir` parameter. - Switch tests from rspec-system to beaker. (This isn't really a feature) ####Bugfixes - Properly fix the deprecated Puppet::Util::SUIDManager.run_and_capture errors. - Fix NOREPLICATION option for Postgres 9.1 - Wrong parameter name: manage_pg_conf -> manage_pg_hba_conf - Add $postgresql::server::client_package_name, referred to by install.pp - Add missing service_provider/service_name descriptions in ::globals. - Fix several smaller typos/issues throughout. - Exec['postgresql_initdb'] needs to be done after $datadir exists - Prevent defined resources from floating in the catalog. - Fix granting all privileges on a table. - Add some missing privileges. - Remove deprecated and unused concat::fragment parameters. ##2013-11-05 - Version 3.2.0 ###Summary Add's support for Ubuntu 13.10 (and 14.04) as well as x, y, z. ####Features - Add versions for Ubuntu 13.10 and 14.04. - Use default_database in validate_db_connection instead of a hardcoded 'postgres' - Add globals/params layering for default_database. - Allow specification of default database name. ####Bugs - Fixes to the README. ##2013-10-25 - Version 3.1.0 ###Summary This is a minor feature and bug fix release. Firstly, the postgresql_psql type now includes a new parameter `search_path` which is equivalent to using `set search_path` which allows you to change the default schema search path. The default version of Fedora 17 has now been added, so that Fedora 17 users can enjoy the module. And finally we've extended the capabilities of the defined type postgresql::validate_db_connection so that now it can handle retrying and sleeping between retries. This feature has been monopolized to fix a bug we were seeing with startup race conditions, but it can also be used by remote systems to 'wait' for PostgreSQL to start before their Puppet run continues. ####Features - Defined $default_version for Fedora 17 (Bret Comnes) - add search_path attribute to postgresql_psql resource (Jeremy Kitchen) - (GH-198) Add wait and retry capability to validate_db_connection (Ken Barber) ####Bugs - enabling defined postgres user password without resetting on every puppet run (jonoterc) - periods are valid in configuration variables also (Jeremy Kitchen) - Add zero length string to join() function (Jarl Stefansson) - add require of install to reload class (cdenneen) - (GH-198) Fix race condition on postgresql startup (Ken Barber) - Remove concat::setup for include in preparation for the next concat release (Ken Barber) ##2013-10-14 - Version 3.0.0 Final release of 3.0, enjoy! ##2013-10-14 - Version 3.0.0-rc3 ###Summary Add a parameter to unmanage pg_hba.conf to fix a regression from 2.5, as well as allowing owner to be passed into x. ####Features - `manage_pg_hba_conf` parameter added to control pg_hba.conf management. - `owner` parameter added to server::db. ##2013-10-09 - Version 3.0.0-rc2 ###Summary A few bugfixes have been found since -rc1. ####Fixes - Special case for $datadir on Amazon - Fix documentation about username/password for the postgresql_hash function ##2013-10-01 - Version 3.0.0-rc1 ###Summary Version 3 was a major rewrite to fix some internal dependency issues, and to make the new Public API more clear. As a consequence a lot of things have changed for version 3 and older revisions that we will try to outline here. (NOTE: The format of this CHANGELOG differs to normal in an attempt to explain the scope of changes) * Server specific objects now moved under `postgresql::server::` namespace: To restructure server specific elements under the `postgresql::server::` namespaces the following objects were renamed as such: `postgresql::database` -> `postgresql::server::database` `postgresql::database_grant` -> `postgresql::server::database_grant` `postgresql::db` -> `postgresql::server::db` `postgresql::grant` -> `postgresql::server::grant` `postgresql::pg_hba_rule` -> `postgresql::server::pg_hba_rule` `postgresql::plperl` -> `postgresql::server::plperl` `postgresql::contrib` -> `postgresql::server::contrib` `postgresql::role` -> `postgresql::server::role` `postgresql::table_grant` -> `postgresql::server::table_grant` `postgresql::tablespace` -> `postgresql::server::tablespace` * New `postgresql::server::config_entry` resource for managing configuration: Previously we used the `file_line` resource to modify `postgresql.conf`. This new revision now adds a new resource named `postgresql::server::config_entry` for managing this file. For example: ```puppet postgresql::server::config_entry { 'check_function_bodies': value => 'off', } ``` If you were using `file_line` for this purpose, you should change to this new methodology. * `postgresql_puppet_extras.conf` has been removed: Now that we have a methodology for managing `postgresql.conf`, and due to concerns over the file management methodology using an `exec { 'touch ...': }` as a way to create an empty file the existing postgresql\_puppet\_extras.conf file is no longer managed by this module. If you wish to recreate this methodology yourself, use this pattern: ```puppet class { 'postgresql::server': } $extras = "/tmp/include.conf" file { $extras: content => 'max_connections = 123', notify => Class['postgresql::server::service'], }-> postgresql::server::config_entry { 'include': value => $extras, } ``` * All uses of the parameter `charset` changed to `encoding`: Since PostgreSQL uses the terminology `encoding` not `charset` the parameter has been made consisent across all classes and resources. * The `postgresql` base class is no longer how you set globals: The old global override pattern was less then optimal so it has been fixed, however we decided to demark this properly by specifying these overrides in the class `postgresql::global`. Consult the documentation for this class now to see what options are available. Also, some parameter elements have been moved between this and the `postgresql::server` class where it made sense. * `config_hash` parameter collapsed for the `postgresql::server` class: Because the `config_hash` was really passing data through to what was in effect an internal class (`postgresql::config`). And since we don't want this kind of internal exposure the parameters were collapsed up into the `postgresql::server` class directly. * Lots of changes to 'private' or 'undocumented' classes: If you were using these before, these have changed names. You should only use what is documented in this README.md, and if you don't have what you need you should raise a patch to add that feature to a public API. All internal classes now have a comment at the top indicating them as private to make sure the message is clear that they are not supported as Public API. * `pg_hba_conf_defaults` parameter included to turn off default pg\_hba rules: The defaults should be good enough for most cases (if not raise a bug) but if you simply need an escape hatch, this setting will turn off the defaults. If you want to do this, it may affect the rest of the module so make sure you replace the rules with something that continues operation. * `postgresql::database_user` has now been removed: Use `postgresql::server::role` instead. * `postgresql::psql` resource has now been removed: Use `postgresql_psql` instead. In the future we may recreate this as a wrapper to add extra capability, but it will not match the old behaviour. * `postgresql_default_version` fact has now been removed: It didn't make sense to have this logic in a fact any more, the logic has been moved into `postgresql::params`. * `ripienaar/concat` is no longer used, instead we use `puppetlabs/concat`: The older concat module is now deprecated and moved into the `puppetlabs/concat` namespace. Functionality is more or less identical, but you may need to intervene during the installing of this package - as both use the same `concat` namespace. --- ##2013-09-09 Release 2.5.0 ###Summary The focus of this release is primarily to capture the fixes done to the types and providers to make sure refreshonly works properly and to set the stage for the large scale refactoring work of 3.0.0. ####Features ####Bugfixes - Use boolean for refreshonly. - Fix postgresql::plperl documentation. - Add two missing parameters to config::beforeservice - Style fixes ##2013-08-01 Release 2.4.1 ###Summary This minor bugfix release solves an idempotency issue when using plain text passwords for the password_hash parameter for the postgresql::role defined type. Without this, users would continually see resource changes everytime your run Puppet. ####Bugfixes - Alter role call not idempotent with cleartext passwords (Ken Barber) ##2013-07-19 Release 2.4.0 ###Summary This updates adds the ability to change permissions on tables, create template databases from normal databases, manage PL-Perl's postgres package, and disable the management of `pg_hba.conf`. ####Features - Add `postgresql::table_grant` defined resource - Add `postgresql::plperl` class - Add `manage_pg_hba_conf` parameter to the `postgresql::config` class - Add `istemplate` parameter to the `postgresql::database` define ####Bugfixes - Update `postgresql::role` class to be able to update roles when modified instead of only on creation. - Update tests - Fix documentation of `postgresql::database_grant` ##2.3.0 This feature release includes the following changes: * Add a new parameter `owner` to the `database` type. This can be used to grant ownership of a new database to a specific user. (Bruno Harbulot) * Add support for operating systems other than Debian/RedHat, as long as the user supplies custom values for all of the required paths, package names, etc. (Chris Price) * Improved integration testing (Ken Barber) ##2.2.1 This release fixes a bug whereby one of our shell commands (psql) were not ran from a globally accessible directory. This was causing permission denied errors when the command attempted to change user without changing directory. Users of previous versions might have seen this error: Error: Error executing SQL; psql returned 256: 'could not change directory to "/root" This patch should correct that. #### Detail Changes * Set /tmp as default CWD for postgresql_psql ##2.2.0 This feature release introduces a number of new features and bug fixes. First of all it includes a new class named `postgresql::python` which provides you with a convenient way of install the python Postgresql client libraries. class { 'postgresql::python': } You are now able to use `postgresql::database_user` without having to specify a password_hash, useful for different authentication mechanisms that do not need passwords (ie. cert, local etc.). We've also provided a lot more advanced custom parameters now for greater control of your Postgresql installation. Consult the class documentation for PuppetDB in the README. This release in particular has largely been contributed by the community members below, a big thanks to one and all. #### Detailed Changes * Add support for psycopg installation (Flaper Fesp and Dan Prince) * Added default PostgreSQL version for Ubuntu 13.04 (Kamil Szymanski) * Add ability to create users without a password (Bruno Harbulot) * Three Puppet 2.6 fixes (Dominic Cleal) * Add explicit call to concat::setup when creating concat file (Dominic Cleal) * Fix readme typo (Jordi Boggiano) * Update postgres_default_version for Ubuntu (Kamil Szymanski) * Allow to set connection for noew role (Kamil Szymanski) * Fix pg_hba_rule for postgres local access (Kamil Szymanski) * Fix versions for travis-ci (Ken Barber) * Add replication support (Jordi Boggiano) * Cleaned up and added unit tests (Ken Barber) * Generalization to provide more flexability in postgresql configuration (Karel Brezina) * Create dependent directory for sudoers so tests work on Centos 5 (Ken Barber) * Allow SQL commands to be run against a specific DB (Carlos Villela) * Drop trailing comma to support Puppet 2.6 (Michael Arnold) ##2.1.1 This release provides a bug fix for RHEL 5 and Centos 5 systems, or specifically systems using PostgreSQL 8.1 or older. On those systems one would have received the error: Error: Could not start Service[postgresqld]: Execution of ‘/sbin/service postgresql start’ returned 1: And the postgresql log entry: FATAL: unrecognized configuration parameter "include" This bug is due to a new feature we had added in 2.1.0, whereby the `include` directive in `postgresql.conf` was not compatible. As a work-around we have added checks in our code to make sure systems running PostgreSQL 8.1 or older do not have this directive added. #### Detailed Changes 2013-01-21 - Ken Barber * Only install `include` directive and included file on PostgreSQL >= 8.2 * Add system tests for Centos 5 ##2.1.0 This release is primarily a feature release, introducing some new helpful constructs to the module. For starters, we've added the line `include 'postgresql_conf_extras.conf'` by default so extra parameters not managed by the module can be added by other tooling or by Puppet itself. This provides a useful escape-hatch for managing settings that are not currently managed by the module today. We've added a new defined resource for managing your tablespace, so you can now create new tablespaces using the syntax: postgresql::tablespace { 'dbspace': location => '/srv/dbspace', } We've added a locale parameter to the `postgresql` class, to provide a default. Also the parameter has been added to the `postgresql::database` and `postgresql::db` defined resources for changing the locale per database: postgresql::db { 'mydatabase': user => 'myuser', password => 'mypassword', encoding => 'UTF8', locale => 'en_NG', } There is a new class for installing the necessary packages to provide the PostgreSQL JDBC client jars: class { 'postgresql::java': } And we have a brand new defined resource for managing fine-grained rule sets within your pg_hba.conf access lists: postgresql::pg_hba { 'Open up postgresql for access from 200.1.2.0/24': type => 'host', database => 'app', user => 'app', address => '200.1.2.0/24', auth_method => 'md5', } Finally, we've also added Travis-CI support and unit tests to help us iterate faster with tests to reduce regression. The current URL for these tests is here: https://travis-ci.org/puppetlabs/puppet-postgresql. Instructions on how to run the unit tests available are provided in the README for the module. A big thanks to all those listed below who made this feature release possible :-). #### Detailed Changes 2013-01-18 - Simão Fontes & Flaper Fesp * Remove trailing commas from params.pp property definition for Puppet 2.6.0 compatibility 2013-01-18 - Lauren Rother * Updated README.md to conform with best practices template 2013-01-09 - Adrien Thebo * Update postgresql_default_version to 9.1 for Debian 7.0 2013-01-28 - Karel Brezina * Add support for tablespaces 2013-01-16 - Chris Price & Karel Brezina * Provide support for an 'include' config file 'postgresql_conf_extras.conf' that users can modify manually or outside of the module. 2013-01-31 - jv * Fix typo in README.pp for postgresql::db example 2013-02-03 - Ken Barber * Add unit tests and travis-ci support 2013-02-02 - Ken Barber * Add locale parameter support to the 'postgresql' class 2013-01-21 - Michael Arnold * Add a class for install the packages containing the PostgreSQL JDBC jar 2013-02-06 - fhrbek * Coding style fixes to reduce warnings in puppet-lint and Geppetto 2013-02-10 - Ken Barber * Provide new defined resource for managing pg_hba.conf 2013-02-11 - Ken Barber * Fix bug with reload of Postgresql on Redhat/Centos 2013-02-15 - Erik Dalén * Fix more style issues to reduce warnings in puppet-lint and Geppetto 2013-02-15 - Erik Dalén * Fix case whereby we were modifying a hash after creation ##2.0.1 Minor bugfix release. 2013-01-16 - Chris Price * Fix revoke command in database.pp to support postgres 8.1 (43ded42) 2013-01-15 - Jordi Boggiano * Add support for ubuntu 12.10 status (3504405) ##2.0.0 Many thanks to the following people who contributed patches to this release: * Adrien Thebo * Albert Koch * Andreas Ntaflos * Brett Porter * Chris Price * dharwood * Etienne Pelletier * Florin Broasca * Henrik * Hunter Haugen * Jari Bakken * Jordi Boggiano * Ken Barber * nzakaria * Richard Arends * Spenser Gilliland * stormcrow * William Van Hevelingen Notable features: * Add support for versions of postgres other than the system default version (which varies depending on OS distro). This includes optional support for automatically managing the package repo for the "official" postgres yum/apt repos. (Major thanks to Etienne Pelletier and Ken Barber for their tireless efforts and patience on this feature set!) For example usage see `tests/official-postgresql-repos.pp`. * Add some support for Debian Wheezy and Ubuntu Quantal * Add new `postgres_psql` type with a Ruby provider, to replace the old exec-based `psql` type. This gives us much more flexibility around executing SQL statements and controlling their logging / reports output. * Major refactor of the "spec" tests--which are actually more like acceptance tests. We now support testing against multiple OS distros via vagrant, and the framework is in place to allow us to very easily add more distros. Currently testing against Cent6 and Ubuntu 10.04. * Fixed a bug that was preventing multiple databases from being owned by the same user (9adcd182f820101f5e4891b9f2ff6278dfad495c - Etienne Pelletier ) * Add support for ACLs for finer-grained control of user/interface access (b8389d19ad78b4fb66024897097b4ed7db241930 - dharwood ) * Many other bug fixes and improvements! --- ##1.0.0 2012-09-17 - Version 0.3.0 released 2012-09-14 - Chris Price * Add a type for validating a postgres connection (ce4a049) 2012-08-25 - Jari Bakken * Remove trailing commas. (e6af5e5) 2012-08-16 - Version 0.2.0 released diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 3c3f1e7..990edba 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,218 +1,217 @@ Checklist (and a short version for the impatient) ================================================= * Commits: - Make commits of logical units. - Check for unnecessary whitespace with "git diff --check" before committing. - Commit using Unix line endings (check the settings around "crlf" in git-config(1)). - Do not check in commented out code or unneeded files. - The first line of the commit message should be a short description (50 characters is the soft limit, excluding ticket number(s)), and should skip the full stop. - Associate the issue in the message. The first line should include the issue number in the form "(#XXXX) Rest of message". - The body should provide a meaningful commit message, which: - uses the imperative, present tense: "change", not "changed" or "changes". - includes motivation for the change, and contrasts its implementation with the previous behavior. - Make sure that you have tests for the bug you are fixing, or feature you are adding. - Make sure the test suites passes after your commit: `bundle exec rspec spec/acceptance` More information on [testing](#Testing) below - When introducing a new feature, make sure it is properly documented in the README.md * Submission: * Pre-requisites: - Make sure you have a [GitHub account](https://github.com/join) - - [Create a ticket](https://tickets.puppetlabs.com/secure/CreateIssue!default.jspa), or [watch the ticket](https://tickets.puppetlabs.com/browse/) you are patching for. + - [Create a ticket](https://tickets.puppet.com/secure/CreateIssue!default.jspa), or [watch the ticket](https://tickets.puppet.com/browse/) you are patching for. * Preferred method: - Fork the repository on GitHub. - Push your changes to a topic branch in your fork of the repository. (the format ticket/1234-short_description_of_change is usually preferred for this project). - Submit a pull request to the repository in the puppetlabs organization. The long version ================ 1. Make separate commits for logically separate changes. Please break your commits down into logically consistent units which include new or changed tests relevant to the rest of the change. The goal of doing this is to make the diff easier to read for whoever is reviewing your code. In general, the easier your diff is to read, the more likely someone will be happy to review it and get it into the code base. If you are going to refactor a piece of code, please do so as a separate commit from your feature or bug fix changes. We also really appreciate changes that include tests to make sure the bug is not re-introduced, and that the feature is not accidentally broken. Describe the technical detail of the change(s). If your description starts to get too long, that is a good sign that you probably need to split up your commit into more finely grained pieces. Commits which plainly describe the things which help reviewers check the patch and future developers understand the code are much more likely to be merged in with a minimum of bike-shedding or requested changes. Ideally, the commit message would include information, and be in a form suitable for inclusion in the release notes for the version of Puppet that includes them. Please also check that you are not introducing any trailing whitespace or other "whitespace errors". You can do this by running "git diff --check" on your changes before you commit. 2. Sending your patches To submit your changes via a GitHub pull request, we _highly_ recommend that you have them on a topic branch, instead of directly on "master". It makes things much easier to keep track of, especially if you decide to work on another thing before your first change is merged in. GitHub has some pretty good [general documentation](http://help.github.com/) on using their site. They also have documentation on [creating pull requests](http://help.github.com/send-pull-requests/). In general, after pushing your topic branch up to your repository on GitHub, you can switch to the branch in the GitHub UI and click "Pull Request" towards the top of the page in order to open a pull request. 3. Update the related GitHub issue. If there is a GitHub issue associated with the change you submitted, then you should update the ticket to include the location of your branch, along with any other commentary you may wish to make. Testing ======= Getting Started --------------- Our puppet modules provide [`Gemfile`](./Gemfile)s which can tell a ruby package manager such as [bundler](http://bundler.io/) what Ruby packages, or Gems, are required to build, develop, and test this software. Please make sure you have [bundler installed](http://bundler.io/#getting-started) on your system, then use it to install all dependencies needed for this project, by running ```shell % bundle install Fetching gem metadata from https://rubygems.org/........ Fetching gem metadata from https://rubygems.org/.. Using rake (10.1.0) Using builder (3.2.2) -- 8><-- many more --><8 -- Using rspec-system-puppet (2.2.0) Using serverspec (0.6.3) Using rspec-system-serverspec (1.0.0) Using bundler (1.3.5) Your bundle is complete! Use `bundle show [gemname]` to see where a bundled gem is installed. ``` NOTE some systems may require you to run this command with sudo. If you already have those gems installed, make sure they are up-to-date: ```shell % bundle update ``` With all dependencies in place and up-to-date we can now run the tests: ```shell % bundle exec rake spec ``` This will execute all the [rspec tests](http://rspec-puppet.com/) tests under [spec/defines](./spec/defines), [spec/classes](./spec/classes), and so on. rspec tests may have the same kind of dependencies as the module they are testing. While the module defines in its [Modulefile](./Modulefile), rspec tests define them in [.fixtures.yml](./fixtures.yml). Some puppet modules also come with [beaker](https://github.com/puppetlabs/beaker) tests. These tests spin up a virtual machine under [VirtualBox](https://www.virtualbox.org/)) with, controlling it with [Vagrant](http://www.vagrantup.com/) to actually simulate scripted test scenarios. In order to run these, you will need both of those tools installed on your system. You can run them by issuing the following command ```shell % bundle exec rake spec_clean % bundle exec rspec spec/acceptance ``` This will now download a pre-fabricated image configured in the [default node-set](./spec/acceptance/nodesets/default.yml), install puppet, copy this module and install its dependencies per [spec/spec_helper_acceptance.rb](./spec/spec_helper_acceptance.rb) and then run all the tests under [spec/acceptance](./spec/acceptance). Writing Tests ------------- XXX getting started writing tests. If you have commit access to the repository =========================================== Even if you have commit access to the repository, you will still need to go through the process above, and have someone else review and merge in your changes. The rule is that all changes must be reviewed by a developer on the project (that did not write the code) to ensure that all changes go through a code review process. Having someone other than the author of the topic branch recorded as performing the merge is the record that they performed the code review. Additional Resources ==================== * [Getting additional help](http://puppet.com/community/get-help) * [Writing tests](https://docs.puppet.com/guides/module_guides/bgtm.html#step-three-module-testing) * [General GitHub documentation](http://help.github.com/) * [GitHub pull request documentation](http://help.github.com/send-pull-requests/) - diff --git a/Gemfile b/Gemfile index c97275b..5d86325 100644 --- a/Gemfile +++ b/Gemfile @@ -1,48 +1,86 @@ #This file is generated by ModuleSync, do not edit. source ENV['GEM_SOURCE'] || "https://rubygems.org" -def location_from_env(env, default_location = []) - if location = ENV[env] - if location =~ /^((?:git|https?)[:@][^#]*)#(.*)/ - [{ :git => $1, :branch => $2, :require => false }] - elsif location =~ /^file:\/\/(.*)/ - ['>= 0', { :path => File.expand_path($1), :require => false }] - else - [location, { :require => false }] - end +# Determines what type of gem is requested based on place_or_version. +def gem_type(place_or_version) + if place_or_version =~ /^git:/ + :git + elsif place_or_version =~ /^file:/ + :file else - default_location + :gem end end -group :development, :unit_tests do - gem 'metadata-json-lint' - gem 'puppet_facts' - gem 'puppet-blacksmith', '>= 3.4.0' - gem 'puppetlabs_spec_helper', '>= 1.2.1' - gem 'rspec-puppet', '>= 2.3.2' - gem 'rspec-puppet-facts' - gem 'simplecov' - gem 'parallel_tests' - gem 'rubocop', '0.41.2' if RUBY_VERSION < '2.0.0' - gem 'rubocop' if RUBY_VERSION >= '2.0.0' - gem 'rubocop-rspec', '~> 1.6' if RUBY_VERSION >= '2.3.0' - gem 'json_pure', '<= 2.0.1' if RUBY_VERSION < '2.0.0' +# Find a location or specific version for a gem. place_or_version can be a +# version, which is most often used. It can also be git, which is specified as +# `git://somewhere.git#branch`. You can also use a file source location, which +# is specified as `file://some/location/on/disk`. +def location_for(place_or_version, fake_version = nil) + if place_or_version =~ /^(git[:@][^#]*)#(.*)/ + [fake_version, { :git => $1, :branch => $2, :require => false }].compact + elsif place_or_version =~ /^file:\/\/(.*)/ + ['>= 0', { :path => File.expand_path($1), :require => false }] + else + [place_or_version, { :require => false }] + end +end + +# Used for gem conditionals +supports_windows = false + +group :development do + gem 'puppet-lint', :require => false + gem 'metadata-json-lint', :require => false, :platforms => 'ruby' + gem 'puppet_facts', :require => false + gem 'puppet-blacksmith', '>= 3.4.0', :require => false, :platforms => 'ruby' + gem 'puppetlabs_spec_helper', '>= 1.2.1', :require => false + gem 'rspec-puppet', '>= 2.3.2', :require => false + gem 'rspec-puppet-facts', :require => false, :platforms => 'ruby' + gem 'mocha', '< 1.2.0', :require => false + gem 'simplecov', :require => false, :platforms => 'ruby' + gem 'parallel_tests', '< 2.10.0', :require => false if Gem::Version.new(RUBY_VERSION.dup) < Gem::Version.new('2.0.0') + gem 'parallel_tests', :require => false if Gem::Version.new(RUBY_VERSION.dup) >= Gem::Version.new('2.0.0') + gem 'rubocop', '0.41.2', :require => false if Gem::Version.new(RUBY_VERSION.dup) < Gem::Version.new('2.0.0') + gem 'rubocop', :require => false if Gem::Version.new(RUBY_VERSION.dup) >= Gem::Version.new('2.0.0') + gem 'rubocop-rspec', '~> 1.6', :require => false if Gem::Version.new(RUBY_VERSION.dup) >= Gem::Version.new('2.3.0') + gem 'pry', :require => false + gem 'json_pure', '<= 2.0.1', :require => false if Gem::Version.new(RUBY_VERSION.dup) < Gem::Version.new('2.0.0') + gem 'fast_gettext', '1.1.0', :require => false if Gem::Version.new(RUBY_VERSION.dup) < Gem::Version.new('2.1.0') + gem 'fast_gettext', :require => false if Gem::Version.new(RUBY_VERSION.dup) >= Gem::Version.new('2.1.0') + gem 'rainbow', '< 2.2.0', :require => false end + group :system_tests do - gem 'beaker', *location_from_env('BEAKER_VERSION', []) if RUBY_VERSION >= '2.3.0' - gem 'beaker', *location_from_env('BEAKER_VERSION', ['< 3']) if RUBY_VERSION < '2.3.0' - gem 'beaker-rspec', *location_from_env('BEAKER_RSPEC_VERSION', ['>= 3.4']) - gem 'serverspec' - gem 'beaker-puppet_install_helper' - gem 'master_manipulator' - gem 'beaker-hostgenerator', *location_from_env('BEAKER_HOSTGENERATOR_VERSION', []) + gem 'beaker', *location_for(ENV['BEAKER_VERSION'] || '>= 3') + gem 'beaker-pe', :require => false + gem 'beaker-rspec', *location_for(ENV['BEAKER_RSPEC_VERSION']) + gem 'beaker-puppet_install_helper', :require => false + gem 'beaker-module_install_helper', :require => false + gem 'master_manipulator', :require => false + gem 'beaker-hostgenerator', *location_for(ENV['BEAKER_HOSTGENERATOR_VERSION']) + gem 'beaker-abs', *location_for(ENV['BEAKER_ABS_VERSION'] || '~> 0.1') end -gem 'facter', *location_from_env('FACTER_GEM_VERSION') -gem 'puppet', *location_from_env('PUPPET_GEM_VERSION') +gem 'puppet', *location_for(ENV['PUPPET_GEM_VERSION']) +# Only explicitly specify Facter/Hiera if a version has been specified. +# Otherwise it can lead to strange bundler behavior. If you are seeing weird +# gem resolution behavior, try setting `DEBUG_RESOLVER` environment variable +# to `1` and then run bundle install. +gem 'facter', *location_for(ENV['FACTER_GEM_VERSION']) if ENV['FACTER_GEM_VERSION'] +gem 'hiera', *location_for(ENV['HIERA_GEM_VERSION']) if ENV['HIERA_GEM_VERSION'] + + +# Evaluate Gemfile.local if it exists if File.exists? "#{__FILE__}.local" eval(File.read("#{__FILE__}.local"), binding) end + +# Evaluate ~/.gemfile if it exists +if File.exists?(File.join(Dir.home, '.gemfile')) + eval(File.read(File.join(Dir.home, '.gemfile')), binding) +end + +# vim:ft=ruby diff --git a/MAINTAINERS.md b/MAINTAINERS.md new file mode 100644 index 0000000..d8c8f6f --- /dev/null +++ b/MAINTAINERS.md @@ -0,0 +1,6 @@ +## Maintenance + +Maintainers: + - Puppet Forge Modules Team `forge-modules |at| puppet |dot| com` + +Tickets: https://tickets.puppet.com/browse/MODULES. Make sure to set component to `postgresql`. diff --git a/README.md b/README.md index 0212fd4..a44819d 100644 --- a/README.md +++ b/README.md @@ -1,1464 +1,1461 @@ # postgresql #### Table of Contents 1. [Module Description - What does the module do?](#module-description) 2. [Setup - The basics of getting started with postgresql module](#setup) * [What postgresql affects](#what-postgresql-affects) * [Getting started with postgresql](#getting-started-with-postgresql) 3. [Usage - Configuration options and additional functionality](#usage) * [Configure a server](#configure-a-server) * [Create a database](#create-a-database) * [Manage users, roles, and permissions](#manage-users-roles-and-permissions) * [Override defaults](#override-defaults) * [Create an access rule for pg_hba.conf](#create-an-access-rule-for-pg_hbaconf) * [Create user name maps for pg_ident.conf](#create-user-name-maps-for-pg_identconf) * [Validate connectivity](#validate-connectivity) 4. [Reference - An under-the-hood peek at what the module is doing and how](#reference) * [Classes](#classes) * [Defined Types](#defined-types) * [Types](#types) * [Functions](#functions) 5. [Limitations - OS compatibility, etc.](#limitations) 6. [Development - Guide for contributing to the module](#development) * [Contributors - List of module contributors](#contributors) 7. [Tests](#tests) 8. [Contributors - List of module contributors](#contributors) ## Module description The postgresql module allows you to manage PostgreSQL databases with Puppet. PostgreSQL is a high-performance, free, open-source relational database server. The postgresql module allows you to manage packages, services, databases, users, and common security settings in PostgreSQL. ## Setup ### What postgresql affects * Package, service, and configuration files for PostgreSQL * Listened-to ports * IP and mask (optional) ### Getting started with postgresql To configure a basic default PostgreSQL server, declare the `postgresql::server` class. ```puppet class { 'postgresql::server': } ``` ## Usage ### Configure a server For default settings, declare the `postgresql::server` class as above. To customize PostgreSQL server settings, specify the [parameters](#postgresqlserver) you want to change: ```puppet class { 'postgresql::server': ip_mask_deny_postgres_user => '0.0.0.0/32', ip_mask_allow_all_users => '0.0.0.0/0', listen_addresses => '*', ipv4acls => ['hostssl all johndoe 192.168.0.0/24 cert'], postgres_password => 'TPSrep0rt!', } ``` After configuration, test your settings from the command line: ``` psql -h localhost -U postgres psql -h my.postgres.server -U ``` If you get an error message from these commands, your permission settings restrict access from the location you're trying to connect from. Depending on whether you want to allow connections from that location, you might need to adjust your permissions. For more details about server configuration parameters, consult the [PostgreSQL Runtime Configuration documentation](http://www.postgresql.org/docs/current/static/runtime-config.html). ### Create a database You can set up a variety of PostgreSQL databases with the `postgresql::server::db` defined type. For instance, to set up a database for PuppetDB: ```puppet class { 'postgresql::server': } postgresql::server::db { 'mydatabasename': user => 'mydatabaseuser', password => postgresql_password('mydatabaseuser', 'mypassword'), } ``` ### Manage users, roles, and permissions To manage users, roles, and permissions: ```puppet class { 'postgresql::server': } postgresql::server::role { 'marmot': password_hash => postgresql_password('marmot', 'mypasswd'), } postgresql::server::database_grant { 'test1': privilege => 'ALL', db => 'test1', role => 'marmot', } postgresql::server::table_grant { 'my_table of test2': privilege => 'ALL', table => 'my_table', db => 'test2', role => 'marmot', } ``` 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. ### Override defaults 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. For example, to overwrite the default `locale` and `encoding` for all classes, use the following: ```puppet class { 'postgresql::globals': encoding => 'UTF-8', locale => 'en_US.UTF-8', }-> class { 'postgresql::server': } ``` To use a specific version of the PostgreSQL package: ```puppet class { 'postgresql::globals': manage_package_repo => true, version => '9.2', }-> class { 'postgresql::server': } ``` ### Manage remote users, roles, and permissions Remote SQL objects are managed using the same Puppet resources as local SQL objects, along with a [`connect_settings`](#connect_settings) hash. This provides control over how Puppet connects to the remote Postgres instances and which version is used for generating SQL commands. The `connect_settings` hash can contain environment variables to control Postgres client connections, such as 'PGHOST', 'PGPORT', 'PGPASSWORD', and 'PGSSLKEY'. See the [PostgreSQL Environment Variables](http://www.postgresql.org/docs/9.4/static/libpq-envars.html) documentation for a complete list of variables. Additionally, you can specify the target database version with the special value of 'DBVERSION'. If the `connect_settings` hash is omitted or empty, then Puppet connects to the local PostgreSQL instance. You can provide a `connect_settings` hash for each of the Puppet resources, or you can set a default `connect_settings` hash in `postgresql::globals`. Configuring `connect_settings` per resource allows SQL objects to be created on multiple databases by multiple users. ```puppet $connection_settings_super2 = { 'PGUSER' => "super2", 'PGPASSWORD' => "foobar2", 'PGHOST' => "127.0.0.1", 'PGPORT' => "5432", 'PGDATABASE' => "postgres", } include postgresql::server # Connect with no special settings, i.e domain sockets, user postgres postgresql::server::role{'super2': password_hash => "foobar2", superuser => true, connect_settings => {}, require => [ Class['postgresql::globals'], Class['postgresql::server::service'], ], } # Now using this new user connect via TCP postgresql::server::database { 'db1': connect_settings => $connection_settings_super2, require => Postgresql::Server::Role['super2'], } ``` ### Create an access rule for pg_hba.conf To create an access rule for `pg_hba.conf`: ```puppet postgresql::server::pg_hba_rule { 'allow application network to access app database': description => "Open up PostgreSQL for access from 200.1.2.0/24", type => 'host', database => 'app', user => 'app', address => '200.1.2.0/24', auth_method => 'md5', } ``` This would create a ruleset in `pg_hba.conf` similar to: ``` # Rule Name: allow application network to access app database # Description: Open up PostgreSQL for access from 200.1.2.0/24 # Order: 150 host app app 200.1.2.0/24 md5 ``` By default, `pg_hba_rule` requires that you include `postgresql::server`. However, you can override that behavior by setting target and postgresql_version when declaring your rule. That might look like the following: ```puppet postgresql::server::pg_hba_rule { 'allow application network to access app database': description => "Open up postgresql for access from 200.1.2.0/24", type => 'host', database => 'app', user => 'app', address => '200.1.2.0/24', auth_method => 'md5', target => '/path/to/pg_hba.conf', postgresql_version => '9.4', } ``` ### Create user name maps for pg_ident.conf To create a user name map for the pg_ident.conf: ```puppet postgresql::server::pg_ident_rule{ 'Map the SSL certificate of the backup server as a replication user': map_name => 'sslrepli', system_username => 'repli1.example.com', database_username => 'replication', } ``` This would create a user name map in `pg_ident.conf` similar to: ``` #Rule Name: Map the SSL certificate of the backup server as a replication user #Description: none #Order: 150 sslrepli repli1.example.com replication ``` ### Create recovery configuration To create the recovery configuration file (`recovery.conf`): ```puppet postgresql::server::recovery{ 'Create a recovery.conf file with the following defined parameters': restore_command => 'cp /mnt/server/archivedir/%f %p', archive_cleanup_command => undef, recovery_end_command => undef, recovery_target_name => 'daily backup 2015-01-26', recovery_target_time => '2015-02-08 22:39:00 EST', recovery_target_xid => undef, recovery_target_inclusive => true, recovery_target => 'immediate', recovery_target_timeline => 'latest', pause_at_recovery_target => true, standby_mode => 'on', primary_conninfo => 'host=localhost port=5432', primary_slot_name => undef, trigger_file => undef, recovery_min_apply_delay => 0, } ``` The above creates this `recovery.conf` config file: ``` restore_command = 'cp /mnt/server/archivedir/%f %p' recovery_target_name = 'daily backup 2015-01-26' recovery_target_time = '2015-02-08 22:39:00 EST' recovery_target_inclusive = true recovery_target = 'immediate' recovery_target_timeline = 'latest' pause_at_recovery_target = true standby_mode = 'on' primary_conninfo = 'host=localhost port=5432' recovery_min_apply_delay = 0 ``` Only the specified parameters are recognized in the template. The `recovery.conf` is only be created if at least one parameter is set **and** [manage_recovery_conf](#manage_recovery_conf) is set to true. ### Validate connectivity 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. Example usage: ```puppet postgresql::validate_db_connection { 'validate my postgres connection': database_host => 'my.postgres.host', database_username => 'mydbuser', database_password => 'mydbpassword', database_name => 'mydbname', }-> exec { 'rake db:migrate': cwd => '/opt/myrubyapp', } ``` ## Reference The postgresql module comes with many options for configuring the server. While you are unlikely to use all of the settings below, they provide a decent amount of control over your security settings. **Classes:** * [postgresql::client](#postgresqlclient) * [postgresql::globals](#postgresqlglobals) * [postgresql::lib::devel](#postgresqllibdevel) * [postgresql::lib::java](#postgresqllibjava) * [postgresql::lib::perl](#postgresqllibperl) * [postgresql::lib::python](#postgresqllibpython) * [postgresql::server](#postgresqlserver) * [postgresql::server::plperl](#postgresqlserverplperl) * [postgresql::server::contrib](#postgresqlservercontrib) * [postgresql::server::postgis](#postgresqlserverpostgis) **Defined Types:** * [postgresql::server::config_entry](#postgresqlserverconfig_entry) * [postgresql::server::database](#postgresqlserverdatabase) * [postgresql::server::database_grant](#postgresqlserverdatabase_grant) * [postgresql::server::db](#postgresqlserverdb) * [postgresql::server::extension](#postgresqlserverextension) +* [postgresql::server::grant](#postgresqlservergrant) * [postgresql::server::grant_role](#postgresqlservergrant_role) * [postgresql::server::pg_hba_rule](#postgresqlserverpg_hba_rule) * [postgresql::server::pg_ident_rule](#postgresqlserverpg_ident_rule) * [postgresql::server::recovery](#postgresqlserverrecovery) * [postgresql::server::role](#postgresqlserverrole) * [postgresql::server::schema](#postgresqlserverschema) * [postgresql::server::table_grant](#postgresqlservertable_grant) * [postgresql::server::tablespace](#postgresqlservertablespace) * [postgresql::validate_db_connection](#postgresqlvalidate_db_connection) **Types:** * [postgresql_psql](#custom-resource-postgresql_psql) * [postgresql_replication_slot](#custom-resource-postgresql_replication_slot) * [postgresql_conf](#custom-resource-postgresql_conf) **Functions:** * [postgresql_password](#function-postgresql_password) * [postgresql_acls_to_resources_hash](#function-postgresql_acls_to_resources_hashacl_array-id-order_offset) ### Classes #### postgresql::client Installs PostgreSQL client software. Set the following parameters if you have a custom version you would like to install. >**Note:** Make sure to add any necessary yum or apt repositories if specifying a custom version. ##### `package_ensure` Whether the PostgreSQL client package resource should be present. Valid values: 'present', 'absent'. Default: 'present'. ##### `package_name` Sets the name of the PostgreSQL client package. Default: 'file'. ##### `validcon_script_path` Specifies the path to validate the connection script. Default: '/usr/local/bin/validate_postgresql_connection.sh'. #### postgresql::lib::docs Installs PostgreSQL bindings for Postgres-Docs. Set the following parameters if you have a custom version you would like to install. **Note:** Make sure to add any necessary yum or apt repositories if specifying a custom version. ##### `package_name` Specifies the name of the PostgreSQL docs package. ##### `package_ensure` Whether the PostgreSQL docs package resource should be present. Valid values: 'present', 'absent'. Default: 'present'. #### postgresql::globals **Note:** Most server-specific defaults should be overridden in the `postgresql::server` class. This class should be used only if you are using a non-standard OS, or if you are changing elements that can only be changed here, such as `version` or `manage_package_repo`. ##### `bindir` Overrides the default PostgreSQL binaries directory for the target platform. Default: OS dependent. ##### `client_package_name` Overrides the default PostgreSQL client package name. Default: OS dependent. ##### `confdir` Overrides the default PostgreSQL configuration directory for the target platform. Default: OS dependent. ##### `contrib_package_name` Overrides the default PostgreSQL contrib package name. Default: OS dependent. ##### `createdb_path` **Deprecated.** Path to the `createdb` command. Default: "${bindir}/createdb". ##### `datadir` Overrides the default PostgreSQL data directory for the target platform. Default: OS dependent. **Note:** Changing the datadir after installation causes the server to come to a full stop before making the change. For Red Hat systems, the data directory must be labeled appropriately for SELinux. On Ubuntu, you must explicitly set `needs_initdb = true` to allow Puppet to initialize the database in the new datadir (`needs_initdb` defaults to true on other systems). **Warning:** If datadir is changed from the default, Puppet does not manage purging of the original data directory, which causes it to fail if the data directory is changed back to the original. ##### `default_database` Specifies the name of the default database to connect with. On most systems, this is 'postgres'. ##### `devel_package_name` Overrides the default PostgreSQL devel package name. Default: OS dependent. ##### `docs_package_name` Overrides the default PostgreSQL docs package name. If not specified, the module uses the default for your OS distro. ##### `encoding` Sets the default encoding for all databases created with this module. On certain operating systems, this is also used during the `template1` initialization, so it becomes a default outside of the module as well. Defaults to the operating system's default encoding. ##### `group` Overrides the default postgres user group to be used for related files in the file system. Default: 'postgres'. ##### `initdb_path` Path to the `initdb` command. ##### `java_package_name` Overrides the default PostgreSQL java package name. Default: OS dependent. ##### `locale` Sets the default database locale for all databases created with this module. On certain operating systems, this is also used during the `template1` initialization, so it becomes a default outside of the module as well. Default: undef, which is effectively `C`. **On Debian, you'll need to ensure that the 'locales-all' package is installed for full functionality of PostgreSQL.** +##### `timezone` + +Sets the default timezone of the postgresql server. The postgresql built-in default is taking the systems timezone information. + ##### `logdir` Overrides the default PostgreSQL log directory. Default: initdb's default path. ##### `log_line_prefix` Set a prefix for the server logs. Default: `'%t '` ##### `manage_package_repo` Sets up official PostgreSQL repositories on your host if set to true. Default: false. ##### `module_workdir` -Specifies working directory under which the psql command should be executed. May need to specify if /tmp is on volume mounted with noexec option. Default: /tmp +Specifies working directory under which the psql command should be executed. May need to specify if /tmp is on volume mounted with noexec option. Default: /tmp ##### `needs_initdb` Explicitly calls the initdb operation after the server package is installed and before the PostgreSQL service is started. Default: OS dependent. ##### `perl_package_name` Overrides the default PostgreSQL Perl package name. Default: OS dependent. ##### `pg_hba_conf_defaults` Disables the defaults supplied with the module for `pg_hba.conf` if set to false. This is useful if you want to override the defaults. Be sure that your changes align with the rest of the module, as some access is required to perform some operations, such as basic `psql` operations. Default: true. ##### `pg_hba_conf_path` Specifies the path to your `pg_hba.conf` file. Default: '${confdir}/pg_hba.conf'. ##### `pg_ident_conf_path` Specifies the path to your `pg_ident.conf` file. Default: "${confdir}/pg_ident.conf". ##### `plperl_package_name` Overrides the default PostgreSQL PL/Perl package name. Default: OS dependent. ##### `plpython_package_name` Overrides the default PostgreSQL PL/Python package name. Default: OS dependent. ##### `postgis_version` Defines the version of PostGIS to install, if you install PostGIS. Defaults to the lowest available with the version of PostgreSQL to be installed. ##### `postgresql_conf_path` Sets the path to your `postgresql.conf` file. Default: "${confdir}/postgresql.conf". ##### `psql_path` Sets the path to the `psql` command. ##### `python_package_name` Overrides the default PostgreSQL Python package name. Default: OS dependent. ##### `recovery_conf_path` Path to your `recovery.conf` file. ##### `repo_proxy` Sets the proxy option for the official PostgreSQL yum-repositories only. Debian is currently not supported. This is useful if your server is behind a corporate firewall and needs to use proxy servers for outside connectivity. +##### `repo_baseurl` + +Sets the baseurl for the PostgreSQL repository. Useful if you host your own mirror of the repository. Defaults to the official PostgreSQL repository. + ##### `server_package_name` Overrides the default PostgreSQL server package name. Default: OS dependent. ##### `service_name` Overrides the default PostgreSQL service name. Default: OS dependent. ##### `service_provider` Overrides the default PostgreSQL service provider. Default: OS dependent. ##### `service_status` Overrides the default status check command for your PostgreSQL service. Default: OS dependent. ##### `user` Overrides the default PostgreSQL super user and owner of PostgreSQL related files in the file system. Default: 'postgres'. ##### `version` The version of PostgreSQL to install and manage. Default: OS system default. ##### `xlogdir` Overrides the default PostgreSQL xlog directory. Default: initdb's default path. ####postgresql::lib::devel Installs the packages containing the development libraries for PostgreSQL and symlinks `pg_config` into `/usr/bin` (if not in `/usr/bin` or `/usr/local/bin`). ##### `link_pg_config` If the bin directory used by the PostgreSQL page is not `/usr/bin` or `/usr/local/bin`, symlinks `pg_config` from the package's bin dir into `usr/bin` (not applicable to Debian systems). Set to false to disable this behavior. Valid values: true, false. Default: true. ##### `package_ensure` Overrides the `ensure` parameter during package installation. Defaults to `present`. ##### `package_name` Overrides the default package name for the distribution you are installing to. Defaults to `postgresql-devel` or `postgresql-devel` depending on your distro. #### postgresql::lib::java Installs PostgreSQL bindings for Java (JDBC). Set the following parameters if you have a custom version you would like to install. **Note:** Make sure to add any necessary yum or apt repositories if specifying a custom version. ##### `package_ensure` Specifies whether the package is present. Valid values: 'present', 'absent'. Default: 'present'. ##### `package_name` Specifies the name of the PostgreSQL java package. #### postgresql::lib::perl Installs the PostgreSQL Perl libraries. ##### `package_ensure` Specifies whether the package is present. Valid values: 'present', 'absent'. Default: 'present'. ##### `package_name` Specifies the name of the PostgreSQL perl package to install. #### postgresql::server::plpython Installs the PL/Python procedural language for PostgreSQL. ##### `package_name` Specifies the name of the postgresql PL/Python package. ##### `package_ensure` Specifies whether the package is present. Valid values: 'present', 'absent'. Default: 'present'. #### postgresql::lib::python Installs PostgreSQL Python libraries. ##### `package_ensure` Specifies whether the package is present. Valid values: 'present', 'absent'. Default: 'present'. ##### `package_name` The name of the PostgreSQL Python package. #### postgresql::server ##### `createdb_path` **Deprecated.** Specifies the path to the `createdb` command. Default: "${bindir}/createdb". ##### `default_database` Specifies the name of the default database to connect with. On most systems this is "postgres". ##### `default_connect_settings` Specifies a hash of environment variables used when connecting to a remote server. Becomes the default for other defined-types. i.e. `postgresql::server::role` ##### `encoding` Sets the default encoding for all databases created with this module. On certain operating systems this is also used during the `template1` initialization, so it becomes a default outside of the module as well. Default: undef. ##### `group` Overrides the default postgres user group to be used for related files in the file system. Default: OS dependent default. ##### `initdb_path` Specifies the path to the `initdb` command. Default: "${bindir}/initdb". ##### `ipv4acls` Lists strings for access control for connection method, users, databases, IPv4 addresses; see [PostgreSQL documentation](http://www.postgresql.org/docs/current/static/auth-pg-hba-conf.html) on `pg_hba.conf` for information. ##### `ipv6acls` Lists strings for access control for connection method, users, databases, IPv6 addresses; see [PostgreSQL documentation](http://www.postgresql.org/docs/current/static/auth-pg-hba-conf.html) on `pg_hba.conf` for information. ##### `ip_mask_allow_all_users` Overrides PostgreSQL defaults for remote connections. By default, PostgreSQL does not allow database user accounts to connect via TCP from remote machines. If you'd like to allow this, you can override this setting. Set to `0.0.0.0/0` to allow database users to connect from any remote machine, or `192.168.0.0/16` to allow connections from any machine on your local 192.168 subnet. Default: `127.0.0.1/32`. ##### `ip_mask_deny_postgres_user` Specifies the IP mask from which remote connections should be denied for the postgres superuser. Defaults to `0.0.0.0/0`, which denies any remote connection. ##### `listen_addresses` Specifies the addresses the server accepts connections to. Valid values: * 'localhost': Accept connections from local host only. * '*': Accept connections from any remote machine. * Specified comma-separated list of hostnames or IP addresses. ##### `locale` Sets the default database locale for all databases created with this module. On certain operating systems this is used during the `template1` initialization as well, so it becomes a default outside of the module. Default: undef, which is effectively `C`. **On Debian, you must ensure that the 'locales-all' package is installed for full functionality of PostgreSQL.** ##### `log_line_prefix` Set a prefix for the server logs. Default: `'%t '` ##### `manage_pg_hba_conf` Whether to manage the pg_hba.conf. If set to true, Puppet overwrites this file. If set to false, Puppet does not modify the file. Valid values: true, false. Default ##### `manage_pg_ident_conf` Overwrites the pg_ident.conf file. If set to true, Puppet overwrites the file. If set to false, Puppet does not modify the file. Valid values: true, false. Default: true. ##### `manage_recovery_conf` Specifies whether or not manage the recovery.conf. If set to true, Puppet overwrites this file. Valid values: true, false. Default: false. ##### `needs_initdb` Explicitly calls the `initdb` operation after server package is installed, and before the PostgreSQL service is started. Default: OS dependent. ##### `package_ensure` Passes a value through to the `package` resource when creating the server instance. Default: undef. ##### `package_name` Specifies the name of the package to use for installing the server software. Default: OS dependent. ##### `pg_hba_conf_defaults` If false, disables the defaults supplied with the module for `pg_hba.conf`. This is useful if you disagree with the defaults and wish to override them yourself. Be sure that your changes of course align with the rest of the module, as some access is required to perform basic `psql` operations for example. ##### `pg_hba_conf_path` Specifies the path to your `pg_hba.conf` file. ##### `pg_ident_conf_path` Specifies the path to your `pg_ident.conf` file. Default: "${confdir}/pg_ident.conf". ##### `plperl_package_name` Sets the default package name for the PL/Perl extension. Default: OS dependent. ##### `plpython_package_name` Sets the default package name for the PL/Python extension. Default: OS dependent. ##### `port` Specifies the port for the PostgreSQL server to listen on. **Note:** The same port number is used for all IP addresses the server listens on. Also, for Red Hat systems and early Debian systems, changing the port causes the server to come to a full stop before being able to make the change. Default: `5432`, meaning the Postgres server listens on TCP port 5432. ##### `postgres_password` Sets the password for the `postgres` user to your specified value. Default: undef, meaning the superuser account in the Postgres database is a user called `postgres` and this account does not have a password. ##### `postgresql_conf_path` Specifies the path to your `postgresql.conf` file. Default: "${confdir}/postgresql.conf". ##### `psql_path` Specifies the path to the `psql` command. Default: OS dependent. ##### `service_manage` Defines whether or not Puppet should manage the service. Default: true. ##### `service_name` Overrides the default PostgreSQL service name. Default: OS dependent. ##### `service_provider` Overrides the default PostgreSQL service provider. Default: undef. ##### `service_reload` Overrides the default reload command for your PostgreSQL service. Default: OS dependent. ##### `service_restart_on_change` Overrides the default behavior to restart your PostgreSQL service when a config entry has been changed that requires a service restart to become active. Default: true. ##### `service_status` Overrides the default status check command for your PostgreSQL service. Default: OS dependent. ##### `user` Overrides the default PostgreSQL super user and owner of PostgreSQL related files in the file system. Default: 'postgres'. #### postgresql::server::contrib Installs the PostgreSQL contrib package. ##### `package_ensure` Sets the ensure parameter passed on to PostgreSQL contrib package resource. ##### `package_name` The name of the PostgreSQL contrib package. #### postgresql::server::plperl Installs the PL/Perl procedural language for postgresql. ##### `package_ensure` The ensure parameter passed on to PostgreSQL PL/Perl package resource. ##### `package_name` The name of the PostgreSQL PL/Perl package. #### postgresql::server::postgis Installs the PostgreSQL postgis packages. ### Defined Types #### postgresql::server::config_entry Modifies your `postgresql.conf` configuration file. Each resource maps to a line inside the file, for example: ```puppet postgresql::server::config_entry { 'check_function_bodies': value => 'off', } ``` ##### `ensure` Removes an entry if set to 'absent'. Valid values: 'present', 'absent'. ##### `value` Defines the value for the setting. #### postgresql::server::db -Creates or modifies a local database, user, and assigns necessary permissions. +Creates a local database, user, and assigns necessary permissions. ##### `comment` Defines a comment to be stored about the database using the PostgreSQL COMMENT command. ##### `connect_settings` Specifies a hash of environment variables used when connecting to a remote server. Default: Connects to the local Postgres instance. ##### `dbname` Sets the name of the database to be created. Defaults to the namevar. ##### `encoding` Overrides the character set during creation of the database. Defaults to the default defined during installation. ##### `grant` Specifies the permissions to grant during creation. Default: `ALL`. ##### `istemplate` Specifies that the database is a template, if set to true. Default: false. ##### `locale` Overrides the locale during creation of the database. Defaults to the default defined during installation. ##### `owner` Sets a user as the owner of the database. Default: $user variable set in `postgresql::server` or `postgresql::globals`. ##### `password` **Required** Sets the password for the created user. ##### `tablespace` Defines the name of the tablespace to allocate the created database to. Default: PostgreSQL default. ##### `template` Specifies the name of the template database from which to build this database. Defaults to `template0`. ##### `user` User to create and assign access to the database upon creation. Mandatory. -##### `change_ownership` - -Specifies whether to create a new database or change the owner of an existing one. Default: false. - #### postgresql::server::database -Creates or modifies a database with no users and no permissions. +Creates a database with no users and no permissions. ##### `dbname` Sets the name of the database. Defaults to the namevar. ##### `encoding` Overrides the character set during creation of the database. Default: The default defined during installation. ##### `istemplate` Defines the database as a template if set to true. Default: false. ##### `locale` Overrides the locale during creation of the database. The default defined during installation. ##### `owner` Sets name of the database owner. Default: The $user variable set in `postgresql::server` or `postgresql::globals`. ##### `tablespace` Sets tablespace for where to create this database. Default: The defaults defined during PostgreSQL installation. ##### `template` Specifies the name of the template database from which to build this database. Default: `template0`. -##### `change_ownership` - -Specifies whether to create a new database or change the owner of an existing one. Default: false. - #### postgresql::server::database_grant Manages grant-based access privileges for users, wrapping the `postgresql::server::database_grant` for database specific permissions. Consult the [PostgreSQL documentation for `grant`](http://www.postgresql.org/docs/current/static/sql-grant.html) for more information. #### `connect_settings` Specifies a hash of environment variables used when connecting to a remote server. Default: Connects to the local Postgres instance. ##### `db` Specifies the database to which you are granting access. ##### `privilege` -Specifies which privileges to grant. Valid options: `SELECT`, `TEMPORARY`, `TEMP`, `CONNECT`. `ALL` is used as a synonym for `CREATE`, so if you need to add multiple privileges, you can use a space delimited string. +Specifies comma-separated list of privileges to grant. Valid options: `ALL`, `CREATE`, `CONNECT`, `TEMPORARY`, `TEMP`. ##### `psql_db` Defines the database to execute the grant against. **This should not ordinarily be changed from the default**, which is `postgres`. ##### `psql_user` Specifies the OS user for running `psql`. Default: The default user for the module, usually `postgres`. ##### `role` Specifies the role or user whom you are granting access to. #### postgresql::server::extension Manages a PostgreSQL extension. ##### `database` Specifies the database on which to activate the extension. ##### `ensure` Specifies whether to activate ('present') or deactivate (absent') the extension. #### `extension` Specifies the extension to activate. If left blank, uses the name of the resource. ##### `package_name` Specifies a package to install prior to activating the extension. ##### `package_ensure` Overrides default package deletion behavior. By default, the package specified with `package_name` is installed when the extension is activated and removed when the extension is deactivated. To override this behavior, set the `ensure` value for the package. #### postgresql::server::grant Manages grant-based access privileges for roles. See [PostgreSQL documentation for `grant`](http://www.postgresql.org/docs/current/static/sql-grant.html) for more information. ##### `db` Specifies the database to which you are granting access. ##### `object_type` Specifies the type of object to which you are granting privileges. Valid options: `DATABASE`, `SCHEMA`, `SEQUENCE`, `ALL SEQUENCES IN SCHEMA`, `TABLE` or `ALL TABLES IN SCHEMA`. ##### `object_name` Specifies name of `object_type` to which to grant access. ##### `port` Port to use when connecting. Default: undef, which generally defaults to port 5432 depending on your PostgreSQL packaging. ##### `privilege` Specifies the privilege to grant. Valid options: `ALL`, `ALL PRIVILEGES` or `object_type` dependent string. ##### `psql_db` Specifies the database to execute the grant against. _This should not ordinarily be changed from the default_, which is `postgres`. ##### `psql_user` Sets the OS user to run `psql`. Default: the default user for the module, usually `postgres`. ##### `role` Specifies the role or user whom you are granting access to. #### postgresql::server::grant_role Allows you to assign a role to a (group) role. See [PostgreSQL documentation for `Role Membership`](http://www.postgresql.org/docs/current/static/role-membership.html) for more information. ##### `group` Specifies the group role to which you are assigning a role. ##### `role` Specifies the role you want to assign to a group. ##### `ensure` Specifies whether to grant ('present') or revoke ('absent') the membership. Default: 'present'. ##### `port` Port to use when connecting. Default: undef, which generally defaults to port 5432 depending on your PostgreSQL packaging. ##### `psql_db` Specifies the database to execute the grant against. _This should not ordinarily be changed from the default_, which is `postgres`. ##### `psql_user` Sets the OS user to run `psql`. Default: the default user for the module, usually `postgres`. ##### `connect_settings` Specifies a hash of environment variables used when connecting to a remote server. Default: Connects to the local Postgres instance. #### postgresql::server::pg_hba_rule Allows you to create an access rule for `pg_hba.conf`. For more details see the [usage example](#create-an-access-rule-for-pghba.conf) and the [PostgreSQL documentation](http://www.postgresql.org/docs/current/static/auth-pg-hba-conf.html). ##### `address` Sets a CIDR based address for this rule matching when the type is not 'local'. ##### `auth_method` Provides the method that is used for authentication for the connection that this rule matches. Described further in the PostgreSQL `pg_hba.conf` documentation. ##### `auth_option` For certain `auth_method` settings there are extra options that can be passed. Consult the PostgreSQL `pg_hba.conf` documentation for further details. ##### `database` -Sets a comma separated list of databases that this rule matches. +Sets a comma-separated list of databases that this rule matches. ##### `description` Defines a longer description for this rule, if required. This description is placed in the comments above the rule in `pg_hba.conf`. Defaults: `none`. Specifies a way to uniquely identify this resource, but functionally does nothing. ##### `order` Sets an order for placing the rule in `pg_hba.conf`. Default: `150`. #### `postgresql_version` Manages `pg_hba.conf` without managing the entire PostgreSQL instance. Default: the version set in `postgresql::server`. ##### `target` Provides the target for the rule, and is generally an internal only property. **Use with caution.** ##### `type` Sets the type of rule. Valid options: `local`, `host`, `hostssl` or `hostnossl`. ##### `user` Sets a comma-separated list of users that this rule matches. #### postgresql::server::pg_ident_rule Allows you to create user name maps for `pg_ident.conf`. For more details see the [usage example](#create-user-name-maps-for-pgidentconf) above and the [PostgreSQL documentation](http://www.postgresql.org/docs/current/static/auth-username-maps.html). ##### `database_username` Specifies the user name of the database user. The `system_username` is mapped to this user name. ##### `description` Sets a longer description for this rule if required. This description is placed in the comments above the rule in `pg_ident.conf`. Default: `none`. ##### `map_name` Sets the name of the user map that is used to refer to this mapping in `pg_hba.conf`. ##### `order` Defines an order for placing the mapping in `pg_ident.conf`. Default: 150. ##### `system_username` Specifies the operating system user name (the user name used to connect to the database). ##### `target` Provides the target for the rule and is generally an internal only property. **Use with caution.** #### postgresql::server::recovery 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). Every parameter value is a string set in the template except `recovery_target_inclusive`, `pause_at_recovery_target`, `standby_mode` and `recovery_min_apply_delay`. A detailed description of all listed parameters can be found in the [PostgreSQL documentation](http://www.postgresql.org/docs/current/static/recovery-config.html). The parameters are grouped into these three sections: ##### [Archive Recovery Parameters](http://www.postgresql.org/docs/current/static/archive-recovery-settings.html) * `restore_command` * `archive_cleanup_command` * `recovery_end_command` ##### [Recovery Target Settings](http://www.postgresql.org/docs/current/static/recovery-target-settings.html) * `recovery_target_name` * `recovery_target_time` * `recovery_target_xid` * `recovery_target_inclusive` * `recovery_target` * `recovery_target_timeline` * `pause_at_recovery_target` ##### [Standby Server Settings](http://www.postgresql.org/docs/current/static/standby-settings.html) * `standby_mode`: Can be specified with the string ('on'/'off'), or by using a Boolean value (true/false). * `primary_conninfo` * `primary_slot_name` * `trigger_file` * `recovery_min_apply_delay` ##### `target` Provides the target for the rule, and is generally an internal only property. **Use with caution.** #### postgresql::server::role Creates a role or user in PostgreSQL. ##### `connection_limit` Specifies how many concurrent connections the role can make. Default: `-1`, meaning no limit. ##### `connect_settings` Specifies a hash of environment variables used when connecting to a remote server. Default: Connects to the local Postgres instance. ##### `createdb` Specifies whether to grant the ability to create new databases with this role. Default: false. ##### `createrole` Specifies whether to grant the ability to create new roles with this role. Default: false. ##### `inherit` Specifies whether to grant inherit capability for the new role. Default: true. ##### `login` Specifies whether to grant login capability for the new role. Default: true. ##### `password_hash` Sets the hash to use during password creation. If the password is not already pre-encrypted in a format that PostgreSQL supports, use the `postgresql_password` function to provide an MD5 hash here, for example: ```puppet postgresql::server::role { "myusername": password_hash => postgresql_password('myusername', 'mypassword'), } ``` ##### `replication` Provides provides replication capabilities for this role if set to true. Default: false. ##### `superuser` Specifies whether to grant super user capability for the new role. Default: false. ##### `username` Defines the username of the role to create. Defaults to the namevar. #### postgresql::server::schema -Creates or modifies a schema. +Creates a schema. ##### `connect_settings` Specifies a hash of environment variables used when connecting to a remote server. Default: Connects to the local Postgres instance. ##### `db` **Required**. Sets the name of the database in which to create this schema. ##### `owner` Sets the default owner of the schema. ##### `schema` Sets the name of the schema. Defaults to the namevar. -##### `change_ownership` - -Specifies whether to create a new schema or change the owner of an existing one. Default: false. - #### postgresql::server::table_grant Manages grant-based access privileges for users. Consult the PostgreSQL documentation for `grant` for more information. ##### `connect_settings` Specifies a hash of environment variables used when connecting to a remote server. Default: Connects to the local Postgres instance. ##### `db` Specifies which database the table is in. ##### `privilege` -Valid options: `SELECT`, `INSERT`, `UPDATE`, `REFERENCES`. `ALL` is used as a synonym for `CREATE`, so if you need to add multiple privileges, use a space-delimited string. +Specifies comma-separated list of privileges to grant. Valid options: `ALL`, `SELECT`, `INSERT`, `UPDATE`, `DELETE`, `TRUNCATE`, `REFERENCES`, `TRIGGER`. ##### `psql_db` Specifies the database to execute the grant against. This should not ordinarily be changed from the default, which is `postgres`. ##### `psql_user` Specifies the OS user for running `psql`. Defaults to the default user for the module, usually `postgres`. ##### `role` Specifies the role or user to whom you are granting access. ##### `table` Specifies the table to which you are granting access. #### postgresql::server::tablespace Creates a tablespace. If necessary, also creates the location and assigns the same permissions as the PostgreSQL server. ##### `connect_settings` Specifies a hash of environment variables used when connecting to a remote server. Default: Connects to the local Postgres instance. ##### `location` Specifies the path to locate this tablespace. ##### `owner` Specifies the default owner of the tablespace. ##### `spcname` Specifies the name of the tablespace. Defaults to the namevar. #### postgresql::validate_db_connection Validates client connection with a remote PostgreSQL database. ##### `connect_settings` 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. ##### `create_db_first` Ensures that the database is created before running the test. This only works if your test is local. Default: true. ##### `database_host` Sets the hostname of the database you wish to test. Default: undef, which generally uses the designated local Unix socket. ##### `database_name` Specifies the name of the database you wish to test. Default: 'postgres'. ##### `database_port` Defines the port to use when connecting. Default: undef, which generally defaults to port 5432 depending on your PostgreSQL packaging. ##### `database_password` Specifies the password to connect with. Can be left blank, not recommended. ##### `database_username` Specifies the username to connect with. Default: undef. When using a Unix socket and ident auth, this is the user you are running as. **If the host is remote you must provide a username.** ##### `run_as` 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. ##### `sleep` Sets the number of seconds to sleep for before trying again after a failure. ##### `tries` Sets the number of attempts after failure before giving up and failing the resource. ### Types #### postgresql_psql Enables Puppet to run psql statements. ##### `command` **Required.** Specifies the SQL command to execute via psql. ##### `cwd` Specifies the working directory under which the psql command should be executed. Default: '/tmp'. ##### `db` Specifies the name of the database to execute the SQL command against. ##### `environment` Specifies any additional environment variables you want to set for a SQL command. Multiple environment variables should be specified as an array. ##### `name` Sets an arbitrary tag for your own reference; the name of the message. This is the namevar. ##### `onlyif` Sets an optional SQL command to execute prior to the main command. This is generally intended to be used for idempotency, to check for the existence of an object in the database to determine whether or not the main SQL command needs to be executed at all. ##### `port` Specifies the port of the database server to execute the SQL command against. ##### `psql_group` Specifies the system user group account under which the psql command should be executed. Default: 'postgres'. ##### `psql_path` Specifies the path to psql executable. Default: 'psql'. ##### `psql_user` Specifies the system user account under which the psql command should be executed. Default: 'postgres'. ##### `refreshonly` Specifies whether to execute the SQL only if there is a notify or subscribe event. Valid values: true, false. Default: false. ##### `search_path` Defines the schema search path to use when executing the SQL command. ##### `unless` The inverse of `onlyif`. #### postgresql_conf Allows Puppet to manage `postgresql.conf` parameters. ##### `name` Specifies the PostgreSQL parameter name to manage. This is the namevar. ##### `target` Specifies the path to `postgresql.conf`. Default: '/etc/postgresql.conf'. ##### `value` Specifies the value to set for this parameter. #### postgresql_replication_slot Allows you to create and destroy replication slots to register warm standby replication on a PostgreSQL master server. ##### `name` Specifies the name of the slot to create. Must be a valid replication slot name. This is the namevar. ### Functions #### postgresql_password Generates a PostgreSQL encrypted password, use `postgresql_password`. Call it from the command line and then copy and paste the encrypted password into your manifest: ```puppet puppet apply --execute 'notify { "test": message => postgresql_password("username", "password") }' ``` Alternatively, you can call this from your production manifests, but the manifests will then contain a clear text version of your passwords. #### postgresql_acls_to_resources_hash(acl_array, id, order_offset) This internal function converts a list of `pg_hba.conf` based ACLs (passed in as an array of strings) to a format compatible with the `postgresql::pg_hba_rule` resource. **This function should only be used internally by the module**. ## Limitations Works with versions of PostgreSQL from 8.1 through 9.5. Currently, the postgresql module is tested on the following operating systems: * Debian 6.x, 7.x, 8.x. * CentOS 5.x, 6.x, and 7.x. * Ubuntu 10.04 and 12.04, 14.04. Other systems might be compatible, but are not being actively tested. ### Apt module support While this module supports both 1.x and 2.x versions of the puppetlabs-apt module, it does not support puppetlabs-apt 2.0.0 or 2.0.1. ### PostGIS support PostGIS is currently considered an unsupported feature, as it doesn't work on all platforms correctly. ### All versions of RHEL/CentOS If you have SELinux enabled you must add any custom ports you use to the `postgresql_port_t` context. You can do this as follows: ``` semanage port -a -t postgresql_port_t -p tcp $customport ``` ## Development Puppet Labs modules on the Puppet Forge are open projects, and community contributions are essential for keeping them great. We can’t access the huge number of platforms and myriad hardware, software, and deployment configurations that Puppet is intended to serve. We want to keep it as easy as possible to contribute changes so that our modules work in your environment. There are a few guidelines that we need contributors to follow so that we can have a chance of keeping on top of things. For more information, see our [module contribution guide](https://docs.puppetlabs.com/forge/contributing.html). ### Tests There are two types of tests distributed with this module. Unit tests with `rspec-puppet` and system tests using `rspec-system`. For unit testing, make sure you have: * rake * bundler Install the necessary gems: ``` bundle install --path=vendor ``` And then run the unit tests: ``` bundle exec rake spec ``` The unit tests are run in Travis-CI as well. If you want to see the results of your own tests, register the service hook through Travis-CI via the accounts section for your GitHub clone of this project. To run the system tests, make sure you also have: * Vagrant > 1.2.x * VirtualBox > 4.2.10 Then run the tests using: ``` bundle exec rspec spec/acceptance ``` To run the tests on different operating systems, see the sets available in `.nodeset.yml` and run the specific set with the following syntax: ``` RSPEC_SET=debian-607-x64 bundle exec rspec spec/acceptance ``` ### Contributors View the full list of contributors on [https://github.com/puppetlabs/puppetlabs-postgresql/graphs/contributors](GitHub). diff --git a/Rakefile b/Rakefile index 3e8d4cb..d12d854 100644 --- a/Rakefile +++ b/Rakefile @@ -1,38 +1,37 @@ -require 'puppet_blacksmith/rake_tasks' -require 'puppet-lint/tasks/puppet-lint' require 'puppetlabs_spec_helper/rake_tasks' +require 'puppet-lint/tasks/puppet-lint' +require 'puppet_blacksmith/rake_tasks' if Bundler.rubygems.find_name('puppet-blacksmith').any? +PuppetLint.configuration.fail_on_warnings = true PuppetLint.configuration.send('relative') -PuppetLint.configuration.send('disable_documentation') -PuppetLint.configuration.send('disable_single_quote_string_with_variables') desc 'Generate pooler nodesets' task :gen_nodeset do require 'beaker-hostgenerator' require 'securerandom' require 'fileutils' agent_target = ENV['TEST_TARGET'] if ! agent_target STDERR.puts 'TEST_TARGET environment variable is not set' STDERR.puts 'setting to default value of "redhat-64default."' agent_target = 'redhat-64default.' end master_target = ENV['MASTER_TEST_TARGET'] if ! master_target STDERR.puts 'MASTER_TEST_TARGET environment variable is not set' STDERR.puts 'setting to default value of "redhat7-64mdcl"' master_target = 'redhat7-64mdcl' end targets = "#{master_target}-#{agent_target}" cli = BeakerHostGenerator::CLI.new([targets]) nodeset_dir = "tmp/nodesets" nodeset = "#{nodeset_dir}/#{targets}-#{SecureRandom.uuid}.yaml" FileUtils.mkdir_p(nodeset_dir) File.open(nodeset, 'w') do |fh| fh.print(cli.execute) end puts nodeset end diff --git a/manifests/client.pp b/manifests/client.pp index 8cc6230..b805749 100644 --- a/manifests/client.pp +++ b/manifests/client.pp @@ -1,25 +1,27 @@ # Install client cli tool. See README.md for more details. class postgresql::client ( $file_ensure = 'file', $validcon_script_path = $postgresql::params::validcon_script_path, $package_name = $postgresql::params::client_package_name, $package_ensure = 'present' ) inherits postgresql::params { validate_absolute_path($validcon_script_path) validate_string($package_name) - package { 'postgresql-client': - ensure => $package_ensure, - name => $package_name, - tag => 'postgresql', + if $package_name != 'UNSET' { + package { 'postgresql-client': + ensure => $package_ensure, + name => $package_name, + tag => 'postgresql', + } } file { $validcon_script_path: ensure => $file_ensure, source => 'puppet:///modules/postgresql/validate_postgresql_connection.sh', owner => 0, group => 0, mode => '0755', } } diff --git a/manifests/globals.pp b/manifests/globals.pp index 089fe12..b005c62 100644 --- a/manifests/globals.pp +++ b/manifests/globals.pp @@ -1,155 +1,155 @@ # Class for setting cross-class global overrides. See README.md for more # details. class postgresql::globals ( $client_package_name = undef, $server_package_name = undef, $contrib_package_name = undef, $devel_package_name = undef, $java_package_name = undef, $docs_package_name = undef, $perl_package_name = undef, $plperl_package_name = undef, $plpython_package_name = undef, $python_package_name = undef, $postgis_package_name = undef, $service_name = undef, $service_provider = undef, $service_status = undef, $default_database = undef, $validcon_script_path = undef, $initdb_path = undef, $createdb_path = undef, $psql_path = undef, $pg_hba_conf_path = undef, $pg_ident_conf_path = undef, $postgresql_conf_path = undef, $recovery_conf_path = undef, $default_connect_settings = {}, $pg_hba_conf_defaults = undef, $datadir = undef, $confdir = undef, $bindir = undef, $xlogdir = undef, $logdir = undef, $log_line_prefix = undef, $user = undef, $group = undef, $version = undef, $postgis_version = undef, $repo_proxy = undef, + $repo_baseurl = undef, $needs_initdb = undef, $encoding = undef, $locale = undef, + $timezone = undef, $manage_pg_hba_conf = undef, $manage_pg_ident_conf = undef, $manage_recovery_conf = undef, $manage_package_repo = undef, $module_workdir = undef, ) { # We are determining this here, because it is needed by the package repo # class. $default_version = $::osfamily ? { /^(RedHat|Linux)/ => $::operatingsystem ? { 'Fedora' => $::operatingsystemrelease ? { - /^(24)$/ => '9.5', + /^(24|25)$/ => '9.5', /^(22|23)$/ => '9.4', /^(21)$/ => '9.3', /^(18|19|20)$/ => '9.2', /^(17)$/ => '9.1', default => undef, }, 'Amazon' => '9.2', default => $::operatingsystemrelease ? { /^7\./ => '9.2', /^6\./ => '8.4', /^5\./ => '8.1', default => undef, }, - default => $::operatingsystemrelease ? { - /^7\./ => '9.2', - /^6\./ => '8.4', - /^5\./ => '8.1', - default => undef, - }, }, 'Debian' => $::operatingsystem ? { 'Debian' => $::operatingsystemrelease ? { - /^6\./ => '8.4', - /^(wheezy|7\.)/ => '9.1', - /^(jessie|8\.)/ => '9.4', + /^(squeeze|6\.)/ => '8.4', + /^(wheezy|7\.)/ => '9.1', + /^(jessie|8\.)/ => '9.4', + /^(stretch|9\.)/ => '9.6', default => undef, }, 'Ubuntu' => $::operatingsystemrelease ? { /^(10.04|10.10|11.04)$/ => '8.4', /^(11.10|12.04|12.10|13.04|13.10)$/ => '9.1', /^(14.04)$/ => '9.3', /^(14.10|15.04|15.10)$/ => '9.4', - /^(16.04)$/ => '9.5', + /^(16.04|16.10)$/ => '9.5', default => undef, }, default => undef, }, 'Archlinux' => $::operatingsystem ? { /Archlinux/ => '9.2', default => '9.2', }, + 'Gentoo' => '9.5', 'FreeBSD' => '93', 'OpenBSD' => $::operatingsystemrelease ? { /5\.6/ => '9.3', /5\.[7-9]/ => '9.4', /6\.[0-9]/ => '9.5', }, 'Suse' => $::operatingsystem ? { 'SLES' => $::operatingsystemrelease ? { /11\.[0-4]/ => '91', default => '93', }, 'OpenSuSE' => $::operatingsystemrelease ? { '13.2' => '93', }, default => undef, }, default => undef, } $globals_version = pick($version, $default_version, 'unknown') if($globals_version == 'unknown') { fail('No preferred version defined or automatically detected.') } $default_postgis_version = $globals_version ? { '8.1' => '1.3.6', '8.4' => '1.5', '9.0' => '1.5', '9.1' => '1.5', '91' => '1.5', '9.2' => '2.0', '9.3' => '2.1', '93' => '2.1', '9.4' => '2.1', '9.5' => '2.2', + '9.6' => '2.3', default => undef, } $globals_postgis_version = $postgis_version ? { undef => $default_postgis_version, default => $postgis_version, } # Setup of the repo only makes sense globally, so we are doing this here. if($manage_package_repo) { class { 'postgresql::repo': version => $globals_version, proxy => $repo_proxy, + baseurl => $repo_baseurl, } } } diff --git a/manifests/lib/devel.pp b/manifests/lib/devel.pp index 5f1ad1c..bbc5272 100644 --- a/manifests/lib/devel.pp +++ b/manifests/lib/devel.pp @@ -1,26 +1,30 @@ # This class installs postgresql development libraries. See README.md for more # details. class postgresql::lib::devel( $package_name = $postgresql::params::devel_package_name, $package_ensure = 'present', $link_pg_config = $postgresql::params::link_pg_config ) inherits postgresql::params { validate_string($package_name) + if $::osfamily == 'Gentoo' { + fail('osfamily Gentoo does not have a separate "devel" package, postgresql::lib::devel is not supported') + } + package { 'postgresql-devel': ensure => $package_ensure, name => $package_name, tag => 'postgresql', } if $link_pg_config { if ( $postgresql::params::bindir != '/usr/bin' and $postgresql::params::bindir != '/usr/local/bin') { file { '/usr/bin/pg_config': ensure => link, target => "${postgresql::params::bindir}/pg_config", } } } } diff --git a/manifests/params.pp b/manifests/params.pp index bc12c99..b07f8f2 100644 --- a/manifests/params.pp +++ b/manifests/params.pp @@ -1,274 +1,314 @@ # PRIVATE CLASS: do not use directly class postgresql::params inherits postgresql::globals { $version = $postgresql::globals::globals_version $postgis_version = $postgresql::globals::globals_postgis_version $listen_addresses = 'localhost' $port = 5432 $log_line_prefix = '%t ' $ip_mask_deny_postgres_user = '0.0.0.0/0' $ip_mask_allow_all_users = '127.0.0.1/32' $ipv4acls = [] $ipv6acls = [] $encoding = $postgresql::globals::encoding $locale = $postgresql::globals::locale + $timezone = $postgresql::globals::timezone $service_ensure = 'running' $service_enable = true $service_manage = true $service_restart_on_change = true $service_provider = $postgresql::globals::service_provider $manage_pg_hba_conf = pick($manage_pg_hba_conf, true) $manage_pg_ident_conf = pick($manage_pg_ident_conf, true) $manage_recovery_conf = pick($manage_recovery_conf, false) $package_ensure = 'present' $module_workdir = pick($module_workdir,'/tmp') # Amazon Linux's OS Family is 'Linux', operating system 'Amazon'. case $::osfamily { 'RedHat', 'Linux': { $link_pg_config = true $user = pick($user, 'postgres') $group = pick($group, 'postgres') $needs_initdb = pick($needs_initdb, true) $version_parts = split($version, '[.]') $package_version = "${version_parts[0]}${version_parts[1]}" if $version == $postgresql::globals::default_version and $::operatingsystem != 'Amazon' { $client_package_name = pick($client_package_name, 'postgresql') $server_package_name = pick($server_package_name, 'postgresql-server') $contrib_package_name = pick($contrib_package_name,'postgresql-contrib') $devel_package_name = pick($devel_package_name, 'postgresql-devel') $java_package_name = pick($java_package_name, 'postgresql-jdbc') $docs_package_name = pick($docs_package_name, 'postgresql-docs') $plperl_package_name = pick($plperl_package_name, 'postgresql-plperl') $plpython_package_name = pick($plpython_package_name, 'postgresql-plpython') $service_name = pick($service_name, 'postgresql') $bindir = pick($bindir, '/usr/bin') $datadir = $::operatingsystem ? { 'Amazon' => pick($datadir, "/var/lib/pgsql${package_version}/data"), default => pick($datadir, '/var/lib/pgsql/data'), } $confdir = pick($confdir, $datadir) } else { $client_package_name = pick($client_package_name, "postgresql${package_version}") $server_package_name = pick($server_package_name, "postgresql${package_version}-server") $contrib_package_name = pick($contrib_package_name,"postgresql${package_version}-contrib") $devel_package_name = pick($devel_package_name, "postgresql${package_version}-devel") $java_package_name = pick($java_package_name, "postgresql${package_version}-jdbc") $docs_package_name = pick($docs_package_name, "postgresql${package_version}-docs") $plperl_package_name = pick($plperl_package_name, "postgresql${package_version}-plperl") $plpython_package_name = pick($plpython_package_name, "postgresql${package_version}-plpython") $service_name = $::operatingsystem ? { 'Amazon' => pick($service_name, "postgresql${version_parts[0]}${version_parts[1]}"), default => pick($service_name, "postgresql-${version}"), } $bindir = $::operatingsystem ? { 'Amazon' => pick($bindir, '/usr/bin'), default => pick($bindir, "/usr/pgsql-${version}/bin"), } $datadir = $::operatingsystem ? { 'Amazon' => pick($datadir, "/var/lib/pgsql${package_version}/data"), default => pick($datadir, "/var/lib/pgsql/${version}/data"), } $confdir = pick($confdir, $datadir) } $psql_path = pick($psql_path, "${bindir}/psql") $service_status = $service_status $service_reload = "service ${service_name} reload" $perl_package_name = pick($perl_package_name, 'perl-DBD-Pg') $python_package_name = pick($python_package_name, 'python-psycopg2') if $postgresql::globals::postgis_package_name { $postgis_package_name = $postgresql::globals::postgis_package_name } elsif $::operatingsystemrelease =~ /^5\./ { $postgis_package_name = 'postgis' } elsif $postgis_version and versioncmp($postgis_version, '2') < 0 { $postgis_package_name = "postgis${package_version}" } else { $postgis_package_name = "postgis2_${package_version}" } } 'Archlinux': { $link_pg_config = true $needs_initdb = pick($needs_initdb, true) $user = pick($user, 'postgres') $group = pick($group, 'postgres') # Archlinux doesn't have a client-package but has a libs package which # pulls in postgresql server $client_package_name = pick($client_package_name, 'postgresql') $server_package_name = pick($server_package_name, 'postgresql-libs') $java_package_name = pick($java_package_name, 'postgresql-jdbc') # Archlinux doesn't have develop packages $devel_package_name = pick($devel_package_name, 'postgresql-devel') # Archlinux does have postgresql-contrib but it isn't maintained $contrib_package_name = pick($contrib_package_name,'undef') # Archlinux postgresql package provides plperl $plperl_package_name = pick($plperl_package_name, 'undef') $plpython_package_name = pick($plpython_package_name, 'undef') $service_name = pick($service_name, 'postgresql') $bindir = pick($bindir, '/usr/bin') $datadir = pick($datadir, '/var/lib/postgres/data') $confdir = pick($confdir, $datadir) $psql_path = pick($psql_path, "${bindir}/psql") $service_status = $service_status $service_reload = "systemctl reload ${service_name}" $python_package_name = pick($python_package_name, 'python-psycopg2') # Archlinux does not have a perl::DBD::Pg package $perl_package_name = pick($perl_package_name, 'undef') } 'Debian': { $link_pg_config = false $user = pick($user, 'postgres') $group = pick($group, 'postgres') if $postgresql::globals::manage_package_repo == true { $needs_initdb = pick($needs_initdb, true) $service_name = pick($service_name, 'postgresql') } else { $needs_initdb = pick($needs_initdb, false) $service_name = $::operatingsystem ? { 'Debian' => pick($service_name, 'postgresql'), 'Ubuntu' => $::lsbmajdistrelease ? { /^10/ => pick($service_name, "postgresql-${version}"), default => pick($service_name, 'postgresql'), }, default => undef } } $client_package_name = pick($client_package_name, "postgresql-client-${version}") $server_package_name = pick($server_package_name, "postgresql-${version}") $contrib_package_name = pick($contrib_package_name, "postgresql-contrib-${version}") if $postgis_version and versioncmp($postgis_version, '2') < 0 { $postgis_package_name = pick($postgis_package_name, "postgresql-${version}-postgis") } else { $postgis_package_name = pick($postgis_package_name, "postgresql-${version}-postgis-${postgis_version}") } $devel_package_name = pick($devel_package_name, 'libpq-dev') - $java_package_name = pick($java_package_name, 'libpostgresql-jdbc-java') + $java_package_name = $::operatingsystem ? { + 'Debian' => $::operatingsystemrelease ? { + /^6/ => pick($java_package_name, 'libpg-java'), + default => pick($java_package_name, 'libpostgresql-jdbc-java'), + }, + default => pick($java_package_name, 'libpostgresql-jdbc-java'), + } $perl_package_name = pick($perl_package_name, 'libdbd-pg-perl') $plperl_package_name = pick($plperl_package_name, "postgresql-plperl-${version}") $plpython_package_name = pick($plpython_package_name, "postgresql-plpython-${version}") $python_package_name = pick($python_package_name, 'python-psycopg2') $bindir = pick($bindir, "/usr/lib/postgresql/${version}/bin") $datadir = pick($datadir, "/var/lib/postgresql/${version}/main") $confdir = pick($confdir, "/etc/postgresql/${version}/main") if $::operatingsystem == 'Debian' and versioncmp($::operatingsystemrelease, '8.0') >= 0 { # Jessie uses systemd $service_status = pick($service_status, "/usr/sbin/service ${service_name}@*-main status") } elsif $::operatingsystem == 'Ubuntu' and versioncmp($::operatingsystemrelease, '15.04') >= 0 { # Ubuntu releases since vivid use systemd $service_status = pick($service_status, "/usr/sbin/service ${service_name} status") } else { $service_status = pick($service_status, "/etc/init.d/${service_name} status | /bin/egrep -q 'Running clusters: .+|online'") } $service_reload = "service ${service_name} reload" $psql_path = pick($psql_path, '/usr/bin/psql') } + 'Gentoo': { + $user = pick($user, 'postgres') + $group = pick($group, 'postgres') + + $client_package_name = pick($client_package_name, 'UNSET') + $server_package_name = pick($server_package_name, 'postgresql') + $contrib_package_name = pick_default($contrib_package_name, undef) + $devel_package_name = pick_default($devel_package_name, undef) + $java_package_name = pick($java_package_name, 'jdbc-postgresql') + $perl_package_name = pick($perl_package_name, 'DBD-Pg') + $plperl_package_name = undef + $python_package_name = pick($python_package_name, 'psycopg') + + $service_name = pick($service_name, "postgresql-${version}") + $bindir = pick($bindir, "/usr/lib/postgresql-${version}/bin") + $datadir = pick($datadir, "/var/lib/postgresql/${version}_data") + $confdir = pick($confdir, "/etc/postgresql-${version}") + $service_status = pick($service_status, "systemctl status ${service_name}") + $service_reload = "systemctl reload ${service_name}" + $psql_path = pick($psql_path, "${bindir}/psql") + + $needs_initdb = pick($needs_initdb, true) + } + 'FreeBSD': { - $link_pg_config = true - $user = pick($user, 'pgsql') - $group = pick($group, 'pgsql') + case $version { + '96': { + $user = pick($user, 'postgres') + $group = pick($group, 'postgres') + $datadir = pick($datadir, "/var/db/postgres/data${version}") + } + default: { + $user = pick($user, 'pgsql') + $group = pick($group, 'pgsql') + $datadir = pick($datadir, '/usr/local/pgsql/data') + } + } + $link_pg_config = true $client_package_name = pick($client_package_name, "databases/postgresql${version}-client") $server_package_name = pick($server_package_name, "databases/postgresql${version}-server") $contrib_package_name = pick($contrib_package_name, "databases/postgresql${version}-contrib") $devel_package_name = pick($devel_package_name, 'databases/postgresql-libpqxx3') $java_package_name = pick($java_package_name, 'databases/postgresql-jdbc') $perl_package_name = pick($plperl_package_name, 'databases/p5-DBD-Pg') $plperl_package_name = pick($plperl_package_name, "databases/postgresql${version}-plperl") $python_package_name = pick($python_package_name, 'databases/py-psycopg2') $service_name = pick($service_name, 'postgresql') $bindir = pick($bindir, '/usr/local/bin') - $datadir = pick($datadir, '/usr/local/pgsql/data') $confdir = pick($confdir, $datadir) $service_status = pick($service_status, "/usr/local/etc/rc.d/${service_name} onestatus") $service_reload = "service ${service_name} reload" $psql_path = pick($psql_path, "${bindir}/psql") $needs_initdb = pick($needs_initdb, true) } 'OpenBSD': { $user = pick($user, '_postgresql') $group = pick($group, '_postgresql') $client_package_name = pick($client_package_name, 'postgresql-client') $server_package_name = pick($server_package_name, 'postgresql-server') $contrib_package_name = pick($contrib_package_name, 'postgresql-contrib') $devel_package_name = pick($devel_package_name, 'postgresql-client') $java_package_name = pick($java_package_name, 'postgresql-jdbc') $perl_package_name = pick($perl_package_name, 'databases/p5-DBD-Pg') $plperl_package_name = undef $python_package_name = pick($python_package_name, 'py-psycopg2') $service_name = pick($service_name, 'postgresql') $bindir = pick($bindir, '/usr/local/bin') $datadir = pick($datadir, '/var/postgresql/data') $confdir = pick($confdir, $datadir) $service_status = pick($service_status, "/etc/rc.d/${service_name} check") $service_reload = "/etc/rc.d/${service_name} reload" $psql_path = pick($psql_path, "${bindir}/psql") $needs_initdb = pick($needs_initdb, true) } 'Suse': { $link_pg_config = true $user = pick($user, 'postgres') $group = pick($group, 'postgres') $client_package_name = pick($client_package_name, "postgresql${version}") $server_package_name = pick($server_package_name, "postgresql${version}-server") $contrib_package_name = pick($contrib_package_name, "postgresql${version}-contrib") $devel_package_name = pick($devel_package_name, "postgresql${version}-devel") $java_package_name = pick($java_package_name, "postgresql${version}-jdbc") $perl_package_name = pick($plperl_package_name, 'perl-DBD-Pg') $plperl_package_name = pick($plperl_package_name, "postgresql${version}-plperl") $python_package_name = pick($python_package_name, 'python-psycopg2') $service_name = pick($service_name, 'postgresql') $bindir = pick($bindir, "/usr/lib/postgresql${version}/bin") $datadir = pick($datadir, '/var/lib/pgsql/data') $confdir = pick($confdir, $datadir) $service_status = pick($service_status, "/etc/init.d/${service_name} status") $service_reload = "/etc/init.d/${service_name} reload" $psql_path = pick($psql_path, "${bindir}/psql") $needs_initdb = pick($needs_initdb, true) } default: { $link_pg_config = true $psql_path = pick($psql_path, "${bindir}/psql") # Since we can't determine defaults on our own, we rely on users setting # parameters with the postgresql::globals class. Here we are checking # that the mandatory minimum is set for the module to operate. $err_prefix = "Module ${module_name} does not provide defaults for osfamily: ${::osfamily} operatingsystem: ${::operatingsystem}; please specify a value for ${module_name}::globals::" if ($needs_initdb == undef) { fail("${err_prefix}needs_initdb") } if ($service_name == undef) { fail("${err_prefix}service_name") } if ($client_package_name == undef) { fail("${err_prefix}client_package_name") } if ($server_package_name == undef) { fail("${err_prefix}server_package_name") } if ($bindir == undef) { fail("${err_prefix}bindir") } if ($datadir == undef) { fail("${err_prefix}datadir") } if ($confdir == undef) { fail("${err_prefix}confdir") } } } $validcon_script_path = pick($validcon_script_path, '/usr/local/bin/validate_postgresql_connection.sh') $initdb_path = pick($initdb_path, "${bindir}/initdb") $pg_hba_conf_path = pick($pg_hba_conf_path, "${confdir}/pg_hba.conf") $pg_hba_conf_defaults = pick($pg_hba_conf_defaults, true) $pg_ident_conf_path = pick($pg_ident_conf_path, "${confdir}/pg_ident.conf") $postgresql_conf_path = pick($postgresql_conf_path, "${confdir}/postgresql.conf") $recovery_conf_path = pick($recovery_conf_path, "${datadir}/recovery.conf") $default_database = pick($default_database, 'postgres') } diff --git a/manifests/repo.pp b/manifests/repo.pp index 58d859f..5ec63c7 100644 --- a/manifests/repo.pp +++ b/manifests/repo.pp @@ -1,22 +1,23 @@ # PRIVATE CLASS: do not use directly class postgresql::repo ( $version = undef, $proxy = undef, + $baseurl = undef, ) { case $::osfamily { 'RedHat', 'Linux': { if $version == undef { fail("The parameter 'version' for 'postgresql::repo' is undefined. You must always define it when osfamily == Redhat or Linux") } class { 'postgresql::repo::yum_postgresql_org': } } 'Debian': { class { 'postgresql::repo::apt_postgresql_org': } } default: { fail("Unsupported managed repository for osfamily: ${::osfamily}, operatingsystem: ${::operatingsystem}, module ${module_name} currently only supports managing repos for osfamily RedHat and Debian") } } } diff --git a/manifests/repo/apt_postgresql_org.pp b/manifests/repo/apt_postgresql_org.pp index 3a3f03c..8815811 100644 --- a/manifests/repo/apt_postgresql_org.pp +++ b/manifests/repo/apt_postgresql_org.pp @@ -1,27 +1,32 @@ # PRIVATE CLASS: do not use directly class postgresql::repo::apt_postgresql_org inherits postgresql::repo { -include ::apt + include ::apt + # Here we have tried to replicate the instructions on the PostgreSQL site: # # http://www.postgresql.org/download/linux/debian/ # + $default_baseurl = 'http://apt.postgresql.org/pub/repos/apt/' + + $_baseurl = pick($postgresql::repo::baseurl, $default_baseurl) + apt::pin { 'apt_postgresql_org': originator => 'apt.postgresql.org', priority => 500, }-> apt::source { 'apt.postgresql.org': - location => 'http://apt.postgresql.org/pub/repos/apt/', + location => $_baseurl, release => "${::lsbdistcodename}-pgdg", repos => "main ${postgresql::repo::version}", key => { id => 'B97B0AFCAA1A47F044F244A07FCC7D46ACCC4CF8', source => 'https://www.postgresql.org/media/keys/ACCC4CF8.asc', }, include => { src => false, }, } Apt::Source['apt.postgresql.org']->Package<|tag == 'postgresql'|> Class['Apt::Update'] -> Package<|tag == 'postgresql'|> } diff --git a/manifests/repo/yum_postgresql_org.pp b/manifests/repo/yum_postgresql_org.pp index 5cfaf4b..1ee8c9a 100644 --- a/manifests/repo/yum_postgresql_org.pp +++ b/manifests/repo/yum_postgresql_org.pp @@ -1,30 +1,36 @@ # PRIVATE CLASS: do not use directly class postgresql::repo::yum_postgresql_org inherits postgresql::repo { $version_parts = split($postgresql::repo::version, '[.]') $package_version = "${version_parts[0]}${version_parts[1]}" $gpg_key_path = "/etc/pki/rpm-gpg/RPM-GPG-KEY-PGDG-${package_version}" file { $gpg_key_path: source => 'puppet:///modules/postgresql/RPM-GPG-KEY-PGDG', + owner => 'root', + group => 'root', + mode => '0644', before => Yumrepo['yum.postgresql.org'] } if($::operatingsystem == 'Fedora') { $label1 = 'fedora' $label2 = $label1 } else { $label1 = 'redhat' $label2 = 'rhel' } + $default_baseurl = "https://download.postgresql.org/pub/repos/yum/${postgresql::repo::version}/${label1}/${label2}-\$releasever-\$basearch" + + $_baseurl = pick($postgresql::repo::baseurl, $default_baseurl) yumrepo { 'yum.postgresql.org': descr => "PostgreSQL ${postgresql::repo::version} \$releasever - \$basearch", - baseurl => "http://yum.postgresql.org/${postgresql::repo::version}/${label1}/${label2}-\$releasever-\$basearch", + baseurl => $_baseurl, enabled => 1, gpgcheck => 1, gpgkey => "file:///etc/pki/rpm-gpg/RPM-GPG-KEY-PGDG-${package_version}", proxy => $postgresql::repo::proxy, } Yumrepo['yum.postgresql.org'] -> Package<|tag == 'postgresql'|> } diff --git a/manifests/server.pp b/manifests/server.pp index a7a448d..2e90178 100644 --- a/manifests/server.pp +++ b/manifests/server.pp @@ -1,83 +1,83 @@ # This installs a PostgreSQL server. See README.md for more details. class postgresql::server ( $postgres_password = undef, $package_name = $postgresql::params::server_package_name, - $client_package_name = $postgresql::params::client_package_name, $package_ensure = $postgresql::params::package_ensure, $plperl_package_name = $postgresql::params::plperl_package_name, $plpython_package_name = $postgresql::params::plpython_package_name, $service_ensure = $postgresql::params::service_ensure, $service_enable = $postgresql::params::service_enable, $service_manage = $postgresql::params::service_manage, $service_name = $postgresql::params::service_name, $service_restart_on_change = $postgresql::params::service_restart_on_change, $service_provider = $postgresql::params::service_provider, $service_reload = $postgresql::params::service_reload, $service_status = $postgresql::params::service_status, $default_database = $postgresql::params::default_database, $default_connect_settings = $postgresql::globals::default_connect_settings, $listen_addresses = $postgresql::params::listen_addresses, $port = $postgresql::params::port, $ip_mask_deny_postgres_user = $postgresql::params::ip_mask_deny_postgres_user, $ip_mask_allow_all_users = $postgresql::params::ip_mask_allow_all_users, $ipv4acls = $postgresql::params::ipv4acls, $ipv6acls = $postgresql::params::ipv6acls, $initdb_path = $postgresql::params::initdb_path, $createdb_path = $postgresql::params::createdb_path, $psql_path = $postgresql::params::psql_path, $pg_hba_conf_path = $postgresql::params::pg_hba_conf_path, $pg_ident_conf_path = $postgresql::params::pg_ident_conf_path, $postgresql_conf_path = $postgresql::params::postgresql_conf_path, $recovery_conf_path = $postgresql::params::recovery_conf_path, $datadir = $postgresql::params::datadir, $xlogdir = $postgresql::params::xlogdir, $logdir = $postgresql::params::logdir, $log_line_prefix = $postgresql::params::log_line_prefix, $pg_hba_conf_defaults = $postgresql::params::pg_hba_conf_defaults, $user = $postgresql::params::user, $group = $postgresql::params::group, $needs_initdb = $postgresql::params::needs_initdb, $encoding = $postgresql::params::encoding, $locale = $postgresql::params::locale, + $timezone = $postgresql::params::timezone, $manage_pg_hba_conf = $postgresql::params::manage_pg_hba_conf, $manage_pg_ident_conf = $postgresql::params::manage_pg_ident_conf, $manage_recovery_conf = $postgresql::params::manage_recovery_conf, $module_workdir = $postgresql::params::module_workdir, #Deprecated $version = undef, ) inherits postgresql::params { $pg = 'postgresql::server' if $version != undef { warning('Passing "version" to postgresql::server is deprecated; please use postgresql::globals instead.') $_version = $version } else { $_version = $postgresql::params::version } if $createdb_path != undef{ warning('Passing "createdb_path" to postgresql::server is deprecated, it can be removed safely for the same behaviour') } # Reload has its own ordering, specified by other defines class { "${pg}::reload": require => Class["${pg}::install"] } anchor { "${pg}::start": }-> class { "${pg}::install": }-> class { "${pg}::initdb": }-> class { "${pg}::config": }-> class { "${pg}::service": }-> class { "${pg}::passwd": }-> anchor { "${pg}::end": } } diff --git a/manifests/server/config.pp b/manifests/server/config.pp index b00a79b..205dd22 100644 --- a/manifests/server/config.pp +++ b/manifests/server/config.pp @@ -1,192 +1,219 @@ # PRIVATE CLASS: do not call directly class postgresql::server::config { $ip_mask_deny_postgres_user = $postgresql::server::ip_mask_deny_postgres_user $ip_mask_allow_all_users = $postgresql::server::ip_mask_allow_all_users $listen_addresses = $postgresql::server::listen_addresses $port = $postgresql::server::port $ipv4acls = $postgresql::server::ipv4acls $ipv6acls = $postgresql::server::ipv6acls $pg_hba_conf_path = $postgresql::server::pg_hba_conf_path $pg_ident_conf_path = $postgresql::server::pg_ident_conf_path $postgresql_conf_path = $postgresql::server::postgresql_conf_path $recovery_conf_path = $postgresql::server::recovery_conf_path $pg_hba_conf_defaults = $postgresql::server::pg_hba_conf_defaults $user = $postgresql::server::user $group = $postgresql::server::group $version = $postgresql::server::_version $manage_pg_hba_conf = $postgresql::server::manage_pg_hba_conf $manage_pg_ident_conf = $postgresql::server::manage_pg_ident_conf $manage_recovery_conf = $postgresql::server::manage_recovery_conf $datadir = $postgresql::server::datadir $logdir = $postgresql::server::logdir $service_name = $postgresql::server::service_name $log_line_prefix = $postgresql::server::log_line_prefix + $timezone = $postgresql::server::timezone if ($manage_pg_hba_conf == true) { # Prepare the main pg_hba file concat { $pg_hba_conf_path: owner => $user, group => $group, mode => '0640', warn => true, notify => Class['postgresql::server::reload'], } if $pg_hba_conf_defaults { Postgresql::Server::Pg_hba_rule { database => 'all', user => 'all', } # Lets setup the base rules $local_auth_option = $version ? { '8.1' => 'sameuser', default => undef, } postgresql::server::pg_hba_rule { 'local access as postgres user': type => 'local', user => $user, auth_method => 'ident', auth_option => $local_auth_option, order => '001', } postgresql::server::pg_hba_rule { 'local access to database with same name': type => 'local', auth_method => 'ident', auth_option => $local_auth_option, order => '002', } postgresql::server::pg_hba_rule { 'allow localhost TCP access to postgresql user': type => 'host', user => $user, address => '127.0.0.1/32', auth_method => 'md5', order => '003', } postgresql::server::pg_hba_rule { 'deny access to postgresql user': type => 'host', user => $user, address => $ip_mask_deny_postgres_user, auth_method => 'reject', order => '004', } postgresql::server::pg_hba_rule { 'allow access to all users': type => 'host', address => $ip_mask_allow_all_users, auth_method => 'md5', order => '100', } postgresql::server::pg_hba_rule { 'allow access to ipv6 localhost': type => 'host', address => '::1/128', auth_method => 'md5', order => '101', } } # ipv4acls are passed as an array of rule strings, here we transform # them into a resources hash, and pass the result to create_resources $ipv4acl_resources = postgresql_acls_to_resources_hash($ipv4acls, 'ipv4acls', 10) create_resources('postgresql::server::pg_hba_rule', $ipv4acl_resources) # ipv6acls are passed as an array of rule strings, here we transform # them into a resources hash, and pass the result to create_resources $ipv6acl_resources = postgresql_acls_to_resources_hash($ipv6acls, 'ipv6acls', 102) create_resources('postgresql::server::pg_hba_rule', $ipv6acl_resources) } # We must set a "listen_addresses" line in the postgresql.conf if we # want to allow any connections from remote hosts. postgresql::server::config_entry { 'listen_addresses': value => $listen_addresses, } postgresql::server::config_entry { 'port': value => $port, } postgresql::server::config_entry { 'data_directory': value => $datadir, } + if $timezone { + postgresql::server::config_entry { 'timezone': + value => $timezone, + } + } if $logdir { postgresql::server::config_entry { 'log_directory': value => $logdir, } } # Allow timestamps in log by default if $log_line_prefix { postgresql::server::config_entry {'log_line_prefix': value => $log_line_prefix, } } # RedHat-based systems hardcode some PG* variables in the init script, and need to be overriden # in /etc/sysconfig/pgsql/postgresql. Create a blank file so we can manage it with augeas later. if ($::osfamily == 'RedHat') and ($::operatingsystemrelease !~ /^7/) and ($::operatingsystem != 'Fedora') { file { '/etc/sysconfig/pgsql/postgresql': ensure => present, replace => false, } # The init script from the packages of the postgresql.org repository # sources an alternate sysconfig file. # I. e. /etc/sysconfig/pgsql/postgresql-9.3 for PostgreSQL 9.3 # Link to the sysconfig file set by this puppet module file { "/etc/sysconfig/pgsql/postgresql-${version}": ensure => link, target => '/etc/sysconfig/pgsql/postgresql', require => File[ '/etc/sysconfig/pgsql/postgresql' ], } } if ($manage_pg_ident_conf == true) { concat { $pg_ident_conf_path: owner => $user, group => $group, force => true, # do not crash if there is no pg_ident_rules mode => '0640', warn => true, notify => Class['postgresql::server::reload'], } } if ($manage_recovery_conf == true) { concat { $recovery_conf_path: owner => $user, group => $group, force => true, # do not crash if there is no recovery conf file mode => '0640', warn => true, notify => Class['postgresql::server::reload'], } } if $::osfamily == 'RedHat' { if $::operatingsystemrelease =~ /^7/ or $::operatingsystem == 'Fedora' { # Template uses: # - $::operatingsystem # - $service_name # - $port # - $datadir file { 'systemd-override': ensure => present, path => "/etc/systemd/system/${service_name}.service", owner => root, group => root, content => template('postgresql/systemd-override.erb'), notify => [ Exec['restart-systemd'], Class['postgresql::server::service'] ], before => Class['postgresql::server::reload'], } exec { 'restart-systemd': command => 'systemctl daemon-reload', refreshonly => true, path => '/bin:/usr/bin:/usr/local/bin' } } } + elsif $::osfamily == 'Gentoo' { + # Template uses: + # - $::operatingsystem + # - $service_name + # - $port + # - $datadir + file { 'systemd-override': + ensure => present, + path => "/etc/systemd/system/${service_name}.service", + owner => root, + group => root, + content => template('postgresql/systemd-override.erb'), + notify => [ Exec['restart-systemd'], Class['postgresql::server::service'] ], + before => Class['postgresql::server::reload'], + } + exec { 'restart-systemd': + command => 'systemctl daemon-reload', + refreshonly => true, + path => '/bin:/usr/bin:/usr/local/bin' + } + } } diff --git a/manifests/server/config_entry.pp b/manifests/server/config_entry.pp index 9ac7bfa..7c34737 100644 --- a/manifests/server/config_entry.pp +++ b/manifests/server/config_entry.pp @@ -1,126 +1,126 @@ # Manage a postgresql.conf entry. See README.md for more details. define postgresql::server::config_entry ( $ensure = 'present', $value = undef, $path = false ) { $postgresql_conf_path = $postgresql::server::postgresql_conf_path $target = $path ? { false => $postgresql_conf_path, default => $path, } Exec { logoutput => 'on_failure', } case $name { - /data_directory|hba_file|ident_file|include|listen_addresses|port|max_connections|superuser_reserved_connections|unix_socket_directory|unix_socket_group|unix_socket_permissions|bonjour|bonjour_name|ssl|ssl_ciphers|shared_buffers|max_prepared_transactions|max_files_per_process|shared_preload_libraries|wal_level|wal_buffers|archive_mode|max_wal_senders|hot_standby|logging_collector|silent_mode|track_activity_query_size|autovacuum_max_workers|autovacuum_freeze_max_age|max_locks_per_transaction|max_pred_locks_per_transaction|restart_after_crash|lc_messages|lc_monetary|lc_numeric|lc_time|log_min_duration_statement/: { + /data_directory|timezone|hba_file|ident_file|include|listen_addresses|port|max_connections|superuser_reserved_connections|unix_socket_director(y|ies)|unix_socket_group|unix_socket_permissions|bonjour|bonjour_name|ssl|ssl_ciphers|shared_buffers|max_prepared_transactions|max_files_per_process|shared_preload_libraries|wal_level|wal_buffers|archive_mode|max_wal_senders|hot_standby|logging_collector|silent_mode|track_activity_query_size|autovacuum_max_workers|autovacuum_freeze_max_age|max_locks_per_transaction|max_pred_locks_per_transaction|restart_after_crash|lc_messages|lc_monetary|lc_numeric|lc_time/: { if $postgresql::server::service_restart_on_change { Postgresql_conf { notify => Class['postgresql::server::service'], before => Class['postgresql::server::reload'], } } else { Postgresql_conf { before => [ Class['postgresql::server::service'], Class['postgresql::server::reload'], ], } } } default: { Postgresql_conf { notify => Class['postgresql::server::reload'], } } } # We have to handle ports and the data directory in a weird and # special way. On early Debian and Ubuntu and RHEL we have to ensure # we stop the service completely. On RHEL 7 we either have to create # a systemd override for the port or update the sysconfig file, but this # is managed for us in postgresql::server::config. if $::operatingsystem == 'Debian' or $::operatingsystem == 'Ubuntu' { if $name == 'port' and ( $::operatingsystemrelease =~ /^6/ or $::operatingsystemrelease =~ /^10\.04/ ) { exec { "postgresql_stop_${name}": command => "service ${::postgresql::server::service_name} stop", onlyif => "service ${::postgresql::server::service_name} status", unless => "grep 'port = ${value}' ${::postgresql::server::postgresql_conf_path}", path => '/usr/sbin:/sbin:/bin:/usr/bin:/usr/local/bin', before => Postgresql_conf[$name], } } elsif $name == 'data_directory' { exec { "postgresql_stop_${name}": command => "service ${::postgresql::server::service_name} stop", onlyif => "service ${::postgresql::server::service_name} status", unless => "grep \"data_directory = '${value}'\" ${::postgresql::server::postgresql_conf_path}", path => '/usr/sbin:/sbin:/bin:/usr/bin:/usr/local/bin', before => Postgresql_conf[$name], } } } if $::osfamily == 'RedHat' { if ! ($::operatingsystemrelease =~ /^7/ or $::operatingsystem == 'Fedora') { if $name == 'port' { # We need to force postgresql to stop before updating the port # because puppet becomes confused and is unable to manage the # service appropriately. exec { "postgresql_stop_${name}": command => "service ${::postgresql::server::service_name} stop", onlyif => "service ${::postgresql::server::service_name} status", unless => "grep 'PGPORT=${value}' /etc/sysconfig/pgsql/postgresql", path => '/sbin:/bin:/usr/bin:/usr/local/bin', require => File['/etc/sysconfig/pgsql/postgresql'], } -> augeas { 'override PGPORT in /etc/sysconfig/pgsql/postgresql': lens => 'Shellvars.lns', incl => '/etc/sysconfig/pgsql/*', context => '/files/etc/sysconfig/pgsql/postgresql', changes => "set PGPORT ${value}", require => File['/etc/sysconfig/pgsql/postgresql'], notify => Class['postgresql::server::service'], before => Class['postgresql::server::reload'], } } elsif $name == 'data_directory' { # We need to force postgresql to stop before updating the data directory # otherwise init script breaks exec { "postgresql_${name}": command => "service ${::postgresql::server::service_name} stop", onlyif => "service ${::postgresql::server::service_name} status", unless => "grep 'PGDATA=${value}' /etc/sysconfig/pgsql/postgresql", path => '/sbin:/bin:/usr/bin:/usr/local/bin', require => File['/etc/sysconfig/pgsql/postgresql'], } -> augeas { 'override PGDATA in /etc/sysconfig/pgsql/postgresql': lens => 'Shellvars.lns', incl => '/etc/sysconfig/pgsql/*', context => '/files/etc/sysconfig/pgsql/postgresql', changes => "set PGDATA ${value}", require => File['/etc/sysconfig/pgsql/postgresql'], notify => Class['postgresql::server::service'], before => Class['postgresql::server::reload'], } } } } case $ensure { /present|absent/: { postgresql_conf { $name: ensure => $ensure, target => $target, value => $value, require => Class['postgresql::server::initdb'], } } default: { fail("Unknown value for ensure '${ensure}'.") } } } diff --git a/manifests/server/contrib.pp b/manifests/server/contrib.pp index e119d9c..4c6cdc1 100644 --- a/manifests/server/contrib.pp +++ b/manifests/server/contrib.pp @@ -1,19 +1,23 @@ # Install the contrib postgresql packaging. See README.md for more details. class postgresql::server::contrib ( $package_name = $postgresql::params::contrib_package_name, $package_ensure = 'present' ) inherits postgresql::params { validate_string($package_name) + if $::osfamily == 'Gentoo' { + fail('osfamily Gentoo does not have a separate "contrib" package, postgresql::server::contrib is not supported.') + } + package { 'postgresql-contrib': ensure => $package_ensure, name => $package_name, tag => 'postgresql', } anchor { 'postgresql::server::contrib::start': }-> Class['postgresql::server::install']-> Package['postgresql-contrib']-> Class['postgresql::server::service']-> anchor { 'postgresql::server::contrib::end': } } diff --git a/manifests/server/database.pp b/manifests/server/database.pp index 0d453bc..b03729c 100644 --- a/manifests/server/database.pp +++ b/manifests/server/database.pp @@ -1,127 +1,128 @@ # Define for creating a database. See README.md for more details. define postgresql::server::database( $comment = undef, $dbname = $title, - $owner = $postgresql::server::user, + $owner = undef, $tablespace = undef, $template = 'template0', $encoding = $postgresql::server::encoding, $locale = $postgresql::server::locale, $istemplate = false, $connect_settings = $postgresql::server::default_connect_settings, - $change_ownership = false, ) { $createdb_path = $postgresql::server::createdb_path $user = $postgresql::server::user $group = $postgresql::server::group $psql_path = $postgresql::server::psql_path $default_db = $postgresql::server::default_database # If possible use the version of the remote database, otherwise # fallback to our local DB version if $connect_settings != undef and has_key( $connect_settings, 'DBVERSION') { $version = $connect_settings['DBVERSION'] } else { $version = $postgresql::server::_version } # If the connection settings do not contain a port, then use the local server port if $connect_settings != undef and has_key( $connect_settings, 'PGPORT') { $port = undef } else { $port = $postgresql::server::port } # Set the defaults for the postgresql_psql resource Postgresql_psql { + db => $default_db, psql_user => $user, psql_group => $group, psql_path => $psql_path, port => $port, connect_settings => $connect_settings, } - if $change_ownership { - # Change owner for existing database - if !$owner { - fail('Must specify an owner to change database ownership.') - } - postgresql_psql { "Change owner of db '${dbname}' to ${owner}": - command => "ALTER DATABASE \"${dbname}\" OWNER TO ${owner}", - onlyif => "SELECT datname FROM pg_database WHERE datname='${dbname}'", - db => $default_db, - require => Class['postgresql::server::service'] + # Optionally set the locale switch. Older versions of createdb may not accept + # --locale, so if the parameter is undefined its safer not to pass it. + if ($version != '8.1') { + $locale_option = $locale ? { + undef => '', + default => "LC_COLLATE = '${locale}' LC_CTYPE = '${locale}'", } + $public_revoke_privilege = 'CONNECT' } else { - # Create a new database - # Optionally set the locale switch. Older versions of createdb may not accept - # --locale, so if the parameter is undefined its safer not to pass it. - if ($version != '8.1') { - $locale_option = $locale ? { - undef => '', - default => "LC_COLLATE='${locale}' LC_CTYPE='${locale}'", - } - $public_revoke_privilege = 'CONNECT' - } else { - $locale_option = '' - $public_revoke_privilege = 'ALL' - } + $locale_option = '' + $public_revoke_privilege = 'ALL' + } - $template_option = $template ? { - undef => '', - default => "TEMPLATE=\"${template}\"", - } + $template_option = $template ? { + undef => '', + default => "TEMPLATE = \"${template}\"", + } - $encoding_option = $encoding ? { - undef => '', - default => "ENCODING='${encoding}'", - } + $encoding_option = $encoding ? { + undef => '', + default => "ENCODING = '${encoding}'", + } - $tablespace_option = $tablespace ? { - undef => '', - default => "TABLESPACE=\"${tablespace}\"", - } + $tablespace_option = $tablespace ? { + undef => '', + default => "TABLESPACE = \"${tablespace}\"", + } + + if $createdb_path != undef { + warning('Passing "createdb_path" to postgresql::database is deprecated, it can be removed safely for the same behaviour') + } + + postgresql_psql { "CREATE DATABASE \"${dbname}\"": + command => "CREATE DATABASE \"${dbname}\" WITH ${template_option} ${encoding_option} ${locale_option} ${tablespace_option}", + unless => "SELECT 1 FROM pg_database WHERE datname = '${dbname}'", + require => Class['postgresql::server::service'] + }~> + + # This will prevent users from connecting to the database unless they've been + # granted privileges. + postgresql_psql { "REVOKE ${public_revoke_privilege} ON DATABASE \"${dbname}\" FROM public": + refreshonly => true, + } - if $createdb_path != undef{ - warning('Passing "createdb_path" to postgresql::database is deprecated, it can be removed safely for the same behaviour') + Postgresql_psql["CREATE DATABASE \"${dbname}\""]-> + postgresql_psql { "UPDATE pg_database SET datistemplate = ${istemplate} WHERE datname = '${dbname}'": + unless => "SELECT 1 FROM pg_database WHERE datname = '${dbname}' AND datistemplate = ${istemplate}", + } + + if $comment { + # The shobj_description function was only introduced with 8.2 + $comment_information_function = $version ? { + '8.1' => 'obj_description', + default => 'shobj_description', + } + Postgresql_psql["CREATE DATABASE \"${dbname}\""]-> + postgresql_psql { "COMMENT ON DATABASE \"${dbname}\" IS '${comment}'": + unless => "SELECT 1 FROM pg_catalog.pg_database d WHERE datname = '${dbname}' AND pg_catalog.${comment_information_function}(d.oid, 'pg_database') = '${comment}'", + db => $dbname, } + } - postgresql_psql { "Create db '${dbname}'": - command => "CREATE DATABASE \"${dbname}\" WITH OWNER=\"${owner}\" ${template_option} ${encoding_option} ${locale_option} ${tablespace_option}", - unless => "SELECT datname FROM pg_database WHERE datname='${dbname}'", - db => $default_db, - require => Class['postgresql::server::service'] - }~> - - # This will prevent users from connecting to the database unless they've been - # granted privileges. - postgresql_psql {"REVOKE ${public_revoke_privilege} ON DATABASE \"${dbname}\" FROM public": - db => $default_db, - refreshonly => true, + if $owner { + postgresql_psql { "ALTER DATABASE \"${dbname}\" OWNER TO \"${owner}\"": + unless => "SELECT 1 FROM pg_database JOIN pg_roles rol ON datdba = rol.oid WHERE datname = '${dbname}' AND rolname = '${owner}'", + require => Postgresql_psql["CREATE DATABASE \"${dbname}\""], } - Postgresql_psql[ "Create db '${dbname}'" ]-> - postgresql_psql {"UPDATE pg_database SET datistemplate = ${istemplate} WHERE datname = '${dbname}'": - unless => "SELECT datname FROM pg_database WHERE datname = '${dbname}' AND datistemplate = ${istemplate}", - db => $default_db, + if defined(Postgresql::Server::Role[$owner]) { + Postgresql::Server::Role[$owner]->Postgresql_psql["ALTER DATABASE \"${dbname}\" OWNER TO \"${owner}\""] } + } - if $comment { - # The shobj_description function was only introduced with 8.2 - $comment_information_function = $version ? { - '8.1' => 'obj_description', - default => 'shobj_description', - } - Postgresql_psql[ "Create db '${dbname}'" ]-> - postgresql_psql {"COMMENT ON DATABASE \"${dbname}\" IS '${comment}'": - unless => "SELECT pg_catalog.${comment_information_function}(d.oid, 'pg_database') as \"Description\" FROM pg_catalog.pg_database d WHERE datname = '${dbname}' AND pg_catalog.${comment_information_function}(d.oid, 'pg_database') = '${comment}'", - db => $dbname, - } + if $tablespace { + postgresql_psql { "ALTER DATABASE \"${dbname}\" SET ${tablespace_option}": + unless => "SELECT 1 FROM pg_database JOIN pg_tablespace spc ON dattablespace = spc.oid WHERE datname = '${dbname}' AND spcname = '${tablespace}'", + require => Postgresql_psql["CREATE DATABASE \"${dbname}\""], } - # Build up dependencies on tablespace - if($tablespace != undef and defined(Postgresql::Server::Tablespace[$tablespace])) { - Postgresql::Server::Tablespace[$tablespace]->Postgresql_psql[ "Create db '${dbname}'" ] + if defined(Postgresql::Server::Tablespace[$tablespace]) { + # The tablespace must be there, before we create the database. + Postgresql::Server::Tablespace[$tablespace]->Postgresql_psql["CREATE DATABASE \"${dbname}\""] } } } diff --git a/manifests/server/db.pp b/manifests/server/db.pp index b170ee5..b4c1232 100644 --- a/manifests/server/db.pp +++ b/manifests/server/db.pp @@ -1,49 +1,47 @@ # Define for conveniently creating a role, database and assigning the correct # permissions. See README.md for more details. define postgresql::server::db ( $user, $password, - $comment = undef, - $dbname = $title, - $encoding = $postgresql::server::encoding, - $locale = $postgresql::server::locale, - $grant = 'ALL', - $tablespace = undef, - $template = 'template0', - $istemplate = false, - $owner = undef, - $change_ownership = false, + $comment = undef, + $dbname = $title, + $encoding = $postgresql::server::encoding, + $locale = $postgresql::server::locale, + $grant = 'ALL', + $tablespace = undef, + $template = 'template0', + $istemplate = false, + $owner = undef ) { if ! defined(Postgresql::Server::Database[$dbname]) { postgresql::server::database { $dbname: - comment => $comment, - encoding => $encoding, - tablespace => $tablespace, - template => $template, - locale => $locale, - istemplate => $istemplate, - owner => $owner, - change_ownership => $change_ownership, + comment => $comment, + encoding => $encoding, + tablespace => $tablespace, + template => $template, + locale => $locale, + istemplate => $istemplate, + owner => $owner, } } if ! defined(Postgresql::Server::Role[$user]) { postgresql::server::role { $user: password_hash => $password, before => Postgresql::Server::Database[$dbname], } } if ! defined(Postgresql::Server::Database_grant["GRANT ${user} - ${grant} - ${dbname}"]) { postgresql::server::database_grant { "GRANT ${user} - ${grant} - ${dbname}": privilege => $grant, db => $dbname, role => $user, } -> Postgresql::Validate_db_connection<| database_name == $dbname |> } if($tablespace != undef and defined(Postgresql::Server::Tablespace[$tablespace])) { Postgresql::Server::Tablespace[$tablespace]->Postgresql::Server::Database[$name] } } diff --git a/manifests/server/grant.pp b/manifests/server/grant.pp index 697313a..2836f17 100644 --- a/manifests/server/grant.pp +++ b/manifests/server/grant.pp @@ -1,252 +1,294 @@ # Define for granting permissions to roles. See README.md for more details. define postgresql::server::grant ( $role, $db, $privilege = undef, $object_type = 'database', $object_name = undef, $psql_db = $postgresql::server::default_database, $psql_user = $postgresql::server::user, $port = $postgresql::server::port, $onlyif_exists = false, $connect_settings = $postgresql::server::default_connect_settings, ) { $group = $postgresql::server::group $psql_path = $postgresql::server::psql_path if ! $object_name { $_object_name = $db } else { $_object_name = $object_name } validate_bool($onlyif_exists) # # Port, order of precedence: $port parameter, $connect_settings[PGPORT], $postgresql::server::port # if $port != undef { $port_override = $port } elsif $connect_settings != undef and has_key( $connect_settings, 'PGPORT') { $port_override = undef } else { $port_override = $postgresql::server::port } ## Munge the input values $_object_type = upcase($object_type) $_privilege = upcase($privilege) ## Validate that the object type is known - validate_string($_object_type, - #'COLUMN', - 'DATABASE', - #'FOREIGN SERVER', - #'FOREIGN DATA WRAPPER', - #'FUNCTION', - #'PROCEDURAL LANGUAGE', - 'SCHEMA', - 'SEQUENCE', - 'ALL SEQUENCES IN SCHEMA', - 'TABLE', - 'ALL TABLES IN SCHEMA', - #'TABLESPACE', - #'VIEW', + validate_re($_object_type,[ + #'^COLUMN$', + '^DATABASE$', + #'^FOREIGN SERVER$', + #'^FOREIGN DATA WRAPPER$', + #'^FUNCTION$', + #'^PROCEDURAL LANGUAGE$', + '^SCHEMA$', + '^SEQUENCE$', + '^ALL SEQUENCES IN SCHEMA$', + '^TABLE$', + '^ALL TABLES IN SCHEMA$', + '^LANGUAGE$', + #'^TABLESPACE$', + #'^VIEW$', + ] ) # You can use ALL TABLES IN SCHEMA by passing schema_name to object_name # You can use ALL SEQUENCES IN SCHEMA by passing schema_name to object_name ## Validate that the object type's privilege is acceptable # TODO: this is a terrible hack; if they pass "ALL" as the desired privilege, # 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!) case $_object_type { 'DATABASE': { $unless_privilege = $_privilege ? { 'ALL' => 'CREATE', 'ALL PRIVILEGES' => 'CREATE', default => $_privilege, } - validate_string($unless_privilege,'CREATE','CONNECT','TEMPORARY','TEMP', - 'ALL','ALL PRIVILEGES') + validate_re($unless_privilege, [ '^$', '^CREATE$','^CONNECT$','^TEMPORARY$','^TEMP$', + '^ALL$','^ALL PRIVILEGES$' ]) $unless_function = 'has_database_privilege' $on_db = $psql_db $onlyif_function = undef } 'SCHEMA': { $unless_privilege = $_privilege ? { 'ALL' => 'CREATE', 'ALL PRIVILEGES' => 'CREATE', default => $_privilege, } - validate_string($_privilege, 'CREATE', 'USAGE', 'ALL', 'ALL PRIVILEGES') + validate_re($_privilege, [ '^$', '^CREATE$', '^USAGE$', '^ALL$', '^ALL PRIVILEGES$' ]) $unless_function = 'has_schema_privilege' $on_db = $db $onlyif_function = undef } 'SEQUENCE': { $unless_privilege = $_privilege ? { 'ALL' => 'USAGE', default => $_privilege, } - validate_string($unless_privilege,'USAGE','ALL','ALL PRIVILEGES') + validate_re($unless_privilege, [ '^$', '^USAGE$', '^SELECT$', '^UPDATE$', '^ALL$', '^ALL PRIVILEGES$' ]) $unless_function = 'has_sequence_privilege' $on_db = $db $onlyif_function = undef } 'ALL SEQUENCES IN SCHEMA': { - validate_string($_privilege,'USAGE','ALL','ALL PRIVILEGES') + validate_re($_privilege, [ '^$', '^USAGE$', '^SELECT$', '^UPDATE$', '^ALL$', '^ALL PRIVILEGES$' ]) $unless_function = 'custom' $on_db = $db $onlyif_function = undef $schema = $object_name $custom_privilege = $_privilege ? { 'ALL' => 'USAGE', 'ALL PRIVILEGES' => 'USAGE', default => $_privilege, } # This checks if there is a difference between the sequences in the # specified schema and the sequences for which the role has the specified # privilege. It uses the EXCEPT clause which computes the set of rows # that are in the result of the first SELECT statement but not in the # result of the second one. It then counts the number of rows from this # operation. If this number is zero then the role has the specified # privilege for all sequences in the schema and the whole query returns a # single row, which satisfies the `unless` parameter of Postgresql_psql. # If this number is not zero then there is at least one sequence for which # the role does not have the specified privilege, making it necessary to # execute the GRANT statement. $custom_unless = "SELECT 1 FROM ( SELECT sequence_name FROM information_schema.sequences WHERE sequence_schema='${schema}' EXCEPT DISTINCT SELECT object_name as sequence_name - FROM information_schema.role_usage_grants - WHERE object_type='SEQUENCE' - AND grantee='${role}' + FROM ( + SELECT object_schema, + object_name, + grantee, + CASE privs_split + WHEN 'r' THEN 'SELECT' + WHEN 'w' THEN 'UPDATE' + WHEN 'U' THEN 'USAGE' + END AS privilege_type + FROM ( + SELECT DISTINCT + object_schema, + object_name, + (regexp_split_to_array(regexp_replace(privs,E'/.*',''),'='))[1] AS grantee, + regexp_split_to_table((regexp_split_to_array(regexp_replace(privs,E'/.*',''),'='))[2],E'\\s*') AS privs_split + FROM ( + SELECT n.nspname as object_schema, + c.relname as object_name, + regexp_split_to_table(array_to_string(c.relacl,','),',') AS privs + FROM pg_catalog.pg_class c + LEFT JOIN pg_catalog.pg_namespace n ON c.relnamespace = n.oid + WHERE c.relkind = 'S' + AND n.nspname NOT IN ( 'pg_catalog', 'information_schema' ) + ) P1 + ) P2 + ) P3 + WHERE grantee='${role}' AND object_schema='${schema}' AND privilege_type='${custom_privilege}' ) P HAVING count(P.sequence_name) = 0" } 'TABLE': { $unless_privilege = $_privilege ? { 'ALL' => 'INSERT', default => $_privilege, } - validate_string($unless_privilege,'SELECT','INSERT','UPDATE','DELETE', - 'TRUNCATE','REFERENCES','TRIGGER','ALL','ALL PRIVILEGES') + validate_re($unless_privilege,[ '^$', '^SELECT$','^INSERT$','^UPDATE$','^DELETE$', + '^TRUNCATE$','^REFERENCES$','^TRIGGER$','^ALL$','^ALL PRIVILEGES$' ]) $unless_function = 'has_table_privilege' $on_db = $db $onlyif_function = $onlyif_exists ? { true => 'table_exists', default => undef, } } 'ALL TABLES IN SCHEMA': { - validate_string($_privilege,'SELECT','INSERT','UPDATE','DELETE', - 'TRUNCATE','REFERENCES','TRIGGER','ALL','ALL PRIVILEGES') + validate_re($_privilege, [ '^$', '^SELECT$','^INSERT$','^UPDATE$','^DELETE$', + '^TRUNCATE$','^REFERENCES$','^TRIGGER$','^ALL$','^ALL PRIVILEGES$' ]) $unless_function = 'custom' $on_db = $db $onlyif_function = undef $schema = $object_name # Again there seems to be no easy way in plain SQL to check if ALL # PRIVILEGES are granted on a table. By convention we use INSERT # here to represent ALL PRIVILEGES (truly terrible). $custom_privilege = $_privilege ? { 'ALL' => 'INSERT', 'ALL PRIVILEGES' => 'INSERT', default => $_privilege, } # This checks if there is a difference between the tables in the # specified schema and the tables for which the role has the specified # privilege. It uses the EXCEPT clause which computes the set of rows # that are in the result of the first SELECT statement but not in the # result of the second one. It then counts the number of rows from this # operation. If this number is zero then the role has the specified # privilege for all tables in the schema and the whole query returns a # single row, which satisfies the `unless` parameter of Postgresql_psql. # If this number is not zero then there is at least one table for which # the role does not have the specified privilege, making it necessary to # execute the GRANT statement. $custom_unless = "SELECT 1 FROM ( SELECT table_name FROM information_schema.tables WHERE table_schema='${schema}' EXCEPT DISTINCT SELECT table_name FROM information_schema.role_table_grants WHERE grantee='${role}' AND table_schema='${schema}' AND privilege_type='${custom_privilege}' ) P HAVING count(P.table_name) = 0" } + 'LANGUAGE': { + $unless_privilege = $_privilege ? { + 'ALL' => 'USAGE', + 'ALL PRIVILEGES' => 'USAGE', + default => $_privilege, + } + validate_re($unless_privilege, [ '^$','^CREATE$','^USAGE$','^ALL$','^ALL PRIVILEGES$' ]) + $unless_function = 'has_language_privilege' + $on_db = $db + $onlyif_function = $onlyif_exists ? { + true => 'language_exists', + default => undef, + } + } + default: { fail("Missing privilege validation for object type ${_object_type}") } } # This is used to give grant to "schemaname"."tablename" # If you need such grant, use: # postgresql::grant { 'table:foo': # role => 'joe', # ... # object_type => 'TABLE', # object_name => [$schema, $table], # } if is_array($_object_name) { $_togrant_object = join($_object_name, '"."') # Never put double quotes into has_*_privilege function $_granted_object = join($_object_name, '.') } else { $_granted_object = $_object_name $_togrant_object = $_object_name } $_unless = $unless_function ? { false => undef, 'custom' => $custom_unless, default => "SELECT 1 WHERE ${unless_function}('${role}', '${_granted_object}', '${unless_privilege}')", } $_onlyif = $onlyif_function ? { - 'table_exists' => "SELECT true FROM pg_tables WHERE tablename = '${_togrant_object}'", - default => undef, + 'table_exists' => "SELECT true FROM pg_tables WHERE tablename = '${_togrant_object}'", + 'language_exists' => "SELECT true from pg_language WHERE lanname = '${_togrant_object}'", + default => undef, } $grant_cmd = "GRANT ${_privilege} ON ${_object_type} \"${_togrant_object}\" TO \"${role}\"" postgresql_psql { "grant:${name}": command => $grant_cmd, db => $on_db, port => $port_override, connect_settings => $connect_settings, psql_user => $psql_user, psql_group => $group, psql_path => $psql_path, unless => $_unless, onlyif => $_onlyif, require => Class['postgresql::server'] } if($role != undef and defined(Postgresql::Server::Role[$role])) { Postgresql::Server::Role[$role]->Postgresql_psql["grant:${name}"] } if($db != undef and defined(Postgresql::Server::Database[$db])) { Postgresql::Server::Database[$db]->Postgresql_psql["grant:${name}"] } } diff --git a/manifests/server/grant_role.pp b/manifests/server/grant_role.pp index 0663559..1696bd5 100644 --- a/manifests/server/grant_role.pp +++ b/manifests/server/grant_role.pp @@ -1,51 +1,51 @@ # Define for granting membership to a role. See README.md for more information define postgresql::server::grant_role ( $group, $role, $ensure = 'present', $psql_db = $postgresql::server::default_database, $psql_user = $postgresql::server::user, $port = $postgresql::server::port, $connect_settings = $postgresql::server::default_connect_settings, ) { validate_string($group) validate_string($role) if empty($group) { fail('$group must be set') } if empty($role) { fail('$role must be set') } case $ensure { 'present': { $command = "GRANT \"${group}\" TO \"${role}\"" $unless_comp = '=' } 'absent': { $command = "REVOKE \"${group}\" FROM \"${role}\"" $unless_comp = '!=' } default: { fail("Unknown value for ensure '${ensure}'.") } } postgresql_psql { "grant_role:${name}": command => $command, - unless => "SELECT 1 WHERE pg_has_role('${role}', '${group}', 'MEMBER') ${unless_comp} true", + unless => "SELECT 1 WHERE EXISTS (SELECT 1 FROM pg_roles AS r_role JOIN pg_auth_members AS am ON r_role.oid = am.member JOIN pg_roles AS r_group ON r_group.oid = am.roleid WHERE r_group.rolname = '${group}' AND r_role.rolname = '${role}') ${unless_comp} true", db => $psql_db, psql_user => $psql_user, port => $port, connect_settings => $connect_settings, } if ! $connect_settings or empty($connect_settings) { Class['postgresql::server']->Postgresql_psql["grant_role:${name}"] } if defined(Postgresql::Server::Role[$role]) { Postgresql::Server::Role[$role]->Postgresql_psql["grant_role:${name}"] } if defined(Postgresql::Server::Role[$group]) { Postgresql::Server::Role[$group]->Postgresql_psql["grant_role:${name}"] } } diff --git a/manifests/server/initdb.pp b/manifests/server/initdb.pp index 04d5aa8..2252a19 100644 --- a/manifests/server/initdb.pp +++ b/manifests/server/initdb.pp @@ -1,129 +1,142 @@ # PRIVATE CLASS: do not call directly class postgresql::server::initdb { $needs_initdb = $postgresql::server::needs_initdb $initdb_path = $postgresql::server::initdb_path $datadir = $postgresql::server::datadir $xlogdir = $postgresql::server::xlogdir $logdir = $postgresql::server::logdir $encoding = $postgresql::server::encoding $locale = $postgresql::server::locale $group = $postgresql::server::group $user = $postgresql::server::user $psql_path = $postgresql::server::psql_path $port = $postgresql::server::port $module_workdir = $postgresql::server::module_workdir # Set the defaults for the postgresql_psql resource Postgresql_psql { psql_user => $user, psql_group => $group, psql_path => $psql_path, port => $port, cwd => $module_workdir, } + if $::osfamily == 'RedHat' and $::selinux == true { + $seltype = 'postgresql_db_t' + $logdir_type = 'postgresql_log_t' + } + + else { + $seltype = undef + $logdir_type = undef + } + # Make sure the data directory exists, and has the correct permissions. file { $datadir: - ensure => directory, - owner => $user, - group => $group, - mode => '0700', + ensure => directory, + owner => $user, + group => $group, + mode => '0700', + seltype => $seltype, } if($xlogdir) { # Make sure the xlog directory exists, and has the correct permissions. file { $xlogdir: - ensure => directory, - owner => $user, - group => $group, - mode => '0700', + ensure => directory, + owner => $user, + group => $group, + mode => '0700', + seltype => $seltype, } } if($logdir) { # Make sure the log directory exists, and has the correct permissions. file { $logdir: - ensure => directory, - owner => $user, - group => $group, + ensure => directory, + owner => $user, + group => $group, + seltype => $logdir_type, } } if($needs_initdb) { # Build up the initdb command. # # We optionally add the locale switch if specified. Older versions of the # initdb command don't accept this switch. So if the user didn't pass the # parameter, lets not pass the switch at all. $ic_base = "${initdb_path} --encoding '${encoding}' --pgdata '${datadir}'" $ic_xlog = $xlogdir ? { undef => $ic_base, default => "${ic_base} --xlogdir '${xlogdir}'" } # The xlogdir need to be present before initdb runs. # If xlogdir is default it's created by package installer if($xlogdir) { $require_before_initdb = [$datadir, $xlogdir] } else { $require_before_initdb = [$datadir] } $initdb_command = $locale ? { undef => $ic_xlog, default => "${ic_xlog} --locale '${locale}'" } # This runs the initdb command, we use the existance of the PG_VERSION # file to ensure we don't keep running this command. exec { 'postgresql_initdb': command => $initdb_command, creates => "${datadir}/PG_VERSION", user => $user, group => $group, logoutput => on_failure, require => File[$require_before_initdb], cwd => $module_workdir, } # The package will take care of this for us the first time, but if we # ever need to init a new db we need to copy these files explicitly if $::operatingsystem == 'Debian' or $::operatingsystem == 'Ubuntu' { if $::operatingsystemrelease =~ /^6/ or $::operatingsystemrelease =~ /^7/ or $::operatingsystemrelease =~ /^10\.04/ or $::operatingsystemrelease =~ /^12\.04/ { file { 'server.crt': ensure => file, path => "${datadir}/server.crt", source => 'file:///etc/ssl/certs/ssl-cert-snakeoil.pem', owner => $::postgresql::server::user, group => $::postgresql::server::group, mode => '0644', require => Exec['postgresql_initdb'], } file { 'server.key': ensure => file, path => "${datadir}/server.key", source => 'file:///etc/ssl/private/ssl-cert-snakeoil.key', owner => $::postgresql::server::user, group => $::postgresql::server::group, mode => '0600', require => Exec['postgresql_initdb'], } } } } elsif $encoding != undef { # [workaround] # by default pg_createcluster encoding derived from locale # but it do does not work by installing postgresql via puppet because puppet # always override LANG to 'C' postgresql_psql { "Set template1 encoding to ${encoding}": command => "UPDATE pg_database SET datistemplate = FALSE WHERE datname = 'template1' ; UPDATE pg_database SET encoding = pg_char_to_encoding('${encoding}'), datistemplate = TRUE WHERE datname = 'template1'", unless => "SELECT datname FROM pg_database WHERE datname = 'template1' AND encoding = pg_char_to_encoding('${encoding}')", } } } diff --git a/manifests/server/install.pp b/manifests/server/install.pp index 8724f9f..57fd0d3 100644 --- a/manifests/server/install.pp +++ b/manifests/server/install.pp @@ -1,23 +1,22 @@ # PRIVATE CLASS: do not call directly class postgresql::server::install { $package_ensure = $postgresql::server::package_ensure $package_name = $postgresql::server::package_name - $client_package_name = $postgresql::server::client_package_name $_package_ensure = $package_ensure ? { true => 'present', false => 'purged', 'absent' => 'purged', default => $package_ensure, } package { 'postgresql-server': ensure => $_package_ensure, name => $package_name, # This is searched for to create relationships with the package repos, be # careful about its removal tag => 'postgresql', } } diff --git a/manifests/server/pg_hba_rule.pp b/manifests/server/pg_hba_rule.pp index 406568f..0eecdc5 100644 --- a/manifests/server/pg_hba_rule.pp +++ b/manifests/server/pg_hba_rule.pp @@ -1,62 +1,64 @@ # This resource manages an individual rule that applies to the file defined in # $target. See README.md for more details. define postgresql::server::pg_hba_rule( $type, $database, $user, $auth_method, $address = undef, $description = 'none', $auth_option = undef, $order = '150', # Needed for testing primarily, support for multiple files is not really # working. $target = $postgresql::server::pg_hba_conf_path, $postgresql_version = $postgresql::server::_version ) { #Allow users to manage pg_hba.conf even if they are not managing the whole PostgreSQL instance if !defined( 'postgresql::server' ) { $manage_pg_hba_conf = true } else { $manage_pg_hba_conf = $postgresql::server::manage_pg_hba_conf } if $manage_pg_hba_conf == false { fail('postgresql::server::manage_pg_hba_conf has been disabled, so this resource is now unused and redundant, either enable that option or remove this resource from your manifests') } else { validate_re($type, '^(local|host|hostssl|hostnossl)$', - "The type you specified [${type}] must be one of: local, host, hostssl, hostnosssl") + "The type you specified [${type}] must be one of: local, host, hostssl, hostnossl") if($type =~ /^host/ and $address == undef) { fail('You must specify an address property when type is host based') } $allowed_auth_methods = $postgresql_version ? { + '9.6' => ['trust', 'reject', 'md5', 'password', 'gss', 'sspi', 'ident', 'peer', 'ldap', 'radius', 'cert', 'pam', 'bsd'], + '9.5' => ['trust', 'reject', 'md5', 'password', 'gss', 'sspi', 'ident', 'peer', 'ldap', 'radius', 'cert', 'pam'], '9.4' => ['trust', 'reject', 'md5', 'password', 'gss', 'sspi', 'ident', 'peer', 'ldap', 'radius', 'cert', 'pam'], '9.3' => ['trust', 'reject', 'md5', 'password', 'gss', 'sspi', 'krb5', 'ident', 'peer', 'ldap', 'radius', 'cert', 'pam'], '9.2' => ['trust', 'reject', 'md5', 'password', 'gss', 'sspi', 'krb5', 'ident', 'peer', 'ldap', 'radius', 'cert', 'pam'], '9.1' => ['trust', 'reject', 'md5', 'password', 'gss', 'sspi', 'krb5', 'ident', 'peer', 'ldap', 'radius', 'cert', 'pam'], '9.0' => ['trust', 'reject', 'md5', 'password', 'gss', 'sspi', 'krb5', 'ident', 'ldap', 'radius', 'cert', 'pam'], '8.4' => ['trust', 'reject', 'md5', 'password', 'gss', 'sspi', 'krb5', 'ident', 'ldap', 'cert', 'pam'], '8.3' => ['trust', 'reject', 'md5', 'crypt', 'password', 'gss', 'sspi', 'krb5', 'ident', 'ldap', 'pam'], '8.2' => ['trust', 'reject', 'md5', 'crypt', 'password', 'krb5', 'ident', 'ldap', 'pam'], '8.1' => ['trust', 'reject', 'md5', 'crypt', 'password', 'krb5', 'ident', 'pam'], - default => ['trust', 'reject', 'md5', 'password', 'gss', 'sspi', 'krb5', 'ident', 'peer', 'ldap', 'radius', 'cert', 'pam', 'crypt'] + default => ['trust', 'reject', 'md5', 'password', 'gss', 'sspi', 'krb5', 'ident', 'peer', 'ldap', 'radius', 'cert', 'pam', 'crypt', 'bsd'] } $auth_method_regex = join(['^(', join($allowed_auth_methods, '|'), ')$'],'') validate_re($auth_method, $auth_method_regex, join(["The auth_method you specified [${auth_method}] must be one of: ", join($allowed_auth_methods, ', ')],'')) # Create a rule fragment $fragname = "pg_hba_rule_${name}" concat::fragment { $fragname: target => $target, content => template('postgresql/pg_hba_rule.conf'), order => $order, } } } diff --git a/manifests/server/role.pp b/manifests/server/role.pp index b7f2be8..c4a8f10 100644 --- a/manifests/server/role.pp +++ b/manifests/server/role.pp @@ -1,124 +1,124 @@ # Define for creating a database role. See README.md for more information define postgresql::server::role( $password_hash = false, $createdb = false, $createrole = false, $db = $postgresql::server::default_database, $port = undef, $login = true, $inherit = true, $superuser = false, $replication = false, $connection_limit = '-1', $username = $title, $connect_settings = $postgresql::server::default_connect_settings, ) { $psql_user = $postgresql::server::user $psql_group = $postgresql::server::group $psql_path = $postgresql::server::psql_path $module_workdir = $postgresql::server::module_workdir # # Port, order of precedence: $port parameter, $connect_settings[PGPORT], $postgresql::server::port # if $port != undef { $port_override = $port } elsif $connect_settings != undef and has_key( $connect_settings, 'PGPORT') { $port_override = undef } else { $port_override = $postgresql::server::port } # If possible use the version of the remote database, otherwise # fallback to our local DB version if $connect_settings != undef and has_key( $connect_settings, 'DBVERSION') { $version = $connect_settings['DBVERSION'] } else { $version = $postgresql::server::_version } $login_sql = $login ? { true => 'LOGIN', default => 'NOLOGIN' } $inherit_sql = $inherit ? { true => 'INHERIT', default => 'NOINHERIT' } $createrole_sql = $createrole ? { true => 'CREATEROLE', default => 'NOCREATEROLE' } $createdb_sql = $createdb ? { true => 'CREATEDB', default => 'NOCREATEDB' } $superuser_sql = $superuser ? { true => 'SUPERUSER', default => 'NOSUPERUSER' } $replication_sql = $replication ? { true => 'REPLICATION', default => '' } if ($password_hash != false) { $environment = "NEWPGPASSWD=${password_hash}" $password_sql = "ENCRYPTED PASSWORD '\$NEWPGPASSWD'" } else { $password_sql = '' $environment = [] } Postgresql_psql { db => $db, port => $port_override, psql_user => $psql_user, psql_group => $psql_group, psql_path => $psql_path, connect_settings => $connect_settings, cwd => $module_workdir, require => [ Postgresql_psql["CREATE ROLE ${username} ENCRYPTED PASSWORD ****"], Class['postgresql::server'], ], } postgresql_psql { "CREATE ROLE ${username} ENCRYPTED PASSWORD ****": command => "CREATE ROLE \"${username}\" ${password_sql} ${login_sql} ${createrole_sql} ${createdb_sql} ${superuser_sql} ${replication_sql} CONNECTION LIMIT ${connection_limit}", - unless => "SELECT rolname FROM pg_roles WHERE rolname='${username}'", + unless => "SELECT 1 FROM pg_roles WHERE rolname = '${username}'", environment => $environment, require => Class['Postgresql::Server'], } postgresql_psql {"ALTER ROLE \"${username}\" ${superuser_sql}": - unless => "SELECT rolname FROM pg_roles WHERE rolname='${username}' and rolsuper=${superuser}", + unless => "SELECT 1 FROM pg_roles WHERE rolname = '${username}' AND rolsuper = ${superuser}", } postgresql_psql {"ALTER ROLE \"${username}\" ${createdb_sql}": - unless => "SELECT rolname FROM pg_roles WHERE rolname='${username}' and rolcreatedb=${createdb}", + unless => "SELECT 1 FROM pg_roles WHERE rolname = '${username}' AND rolcreatedb = ${createdb}", } postgresql_psql {"ALTER ROLE \"${username}\" ${createrole_sql}": - unless => "SELECT rolname FROM pg_roles WHERE rolname='${username}' and rolcreaterole=${createrole}", + unless => "SELECT 1 FROM pg_roles WHERE rolname = '${username}' AND rolcreaterole = ${createrole}", } postgresql_psql {"ALTER ROLE \"${username}\" ${login_sql}": - unless => "SELECT rolname FROM pg_roles WHERE rolname='${username}' and rolcanlogin=${login}", + unless => "SELECT 1 FROM pg_roles WHERE rolname = '${username}' AND rolcanlogin = ${login}", } postgresql_psql {"ALTER ROLE \"${username}\" ${inherit_sql}": - unless => "SELECT rolname FROM pg_roles WHERE rolname='${username}' and rolinherit=${inherit}", + unless => "SELECT 1 FROM pg_roles WHERE rolname = '${username}' AND rolinherit = ${inherit}", } if(versioncmp($version, '9.1') >= 0) { if $replication_sql == '' { postgresql_psql {"ALTER ROLE \"${username}\" NOREPLICATION": - unless => "SELECT rolname FROM pg_roles WHERE rolname='${username}' and rolreplication=${replication}", + unless => "SELECT 1 FROM pg_roles WHERE rolname = '${username}' AND rolreplication = ${replication}", } } else { postgresql_psql {"ALTER ROLE \"${username}\" ${replication_sql}": - unless => "SELECT rolname FROM pg_roles WHERE rolname='${username}' and rolreplication=${replication}", + unless => "SELECT 1 FROM pg_roles WHERE rolname = '${username}' AND rolreplication = ${replication}", } } } postgresql_psql {"ALTER ROLE \"${username}\" CONNECTION LIMIT ${connection_limit}": - unless => "SELECT rolname FROM pg_roles WHERE rolname='${username}' and rolconnlimit=${connection_limit}", + unless => "SELECT 1 FROM pg_roles WHERE rolname = '${username}' AND rolconnlimit = ${connection_limit}", } if $password_hash { if($password_hash =~ /^md5.+/) { $pwd_hash_sql = $password_hash } else { $pwd_md5 = md5("${password_hash}${username}") $pwd_hash_sql = "md5${pwd_md5}" } postgresql_psql { "ALTER ROLE ${username} ENCRYPTED PASSWORD ****": command => "ALTER ROLE \"${username}\" ${password_sql}", - unless => "SELECT usename FROM pg_shadow WHERE usename='${username}' and passwd='${pwd_hash_sql}'", + unless => "SELECT 1 FROM pg_shadow WHERE usename = '${username}' AND passwd = '${pwd_hash_sql}'", environment => $environment, } } } diff --git a/manifests/server/schema.pp b/manifests/server/schema.pp index 00eb5ab..f0e762e 100644 --- a/manifests/server/schema.pp +++ b/manifests/server/schema.pp @@ -1,77 +1,63 @@ # = Type: postgresql::server::schema # # Create a new schema. See README.md for more details. # # == Requires: # # The database must exist and the PostgreSQL user should have enough privileges # # == Sample Usage: # # postgresql::server::schema {'private': # db => 'template1', # } # define postgresql::server::schema( - $db = $postgresql::server::default_database, - $owner = undef, - $schema = $title, + $db = $postgresql::server::default_database, + $owner = undef, + $schema = $title, $connect_settings = $postgresql::server::default_connect_settings, - $change_ownership = false, ) { $user = $postgresql::server::user $group = $postgresql::server::group $psql_path = $postgresql::server::psql_path $version = $postgresql::server::_version $module_workdir = $postgresql::server::module_workdir + Postgresql::Server::Db <| dbname == $db |> -> Postgresql::Server::Schema[$name] + # If the connection settings do not contain a port, then use the local server port if $connect_settings != undef and has_key( $connect_settings, 'PGPORT') { $port = undef } else { $port = $postgresql::server::port } Postgresql_psql { db => $db, psql_user => $user, psql_group => $group, psql_path => $psql_path, port => $port, cwd => $module_workdir, connect_settings => $connect_settings, } - $schema_exists = "SELECT nspname FROM pg_namespace WHERE nspname='${schema}'" - $authorization = $owner? { - undef => '', - default => "AUTHORIZATION \"${owner}\"", + postgresql_psql { "${db}: CREATE SCHEMA \"${schema}\"": + command => "CREATE SCHEMA \"${schema}\"", + unless => "SELECT 1 FROM pg_namespace WHERE nspname = '${schema}'", + require => Class['postgresql::server'], } - if $change_ownership { - # Change owner for existing schema - if !$owner { - fail('Must specify an owner to change schema ownership.') - } - $schema_title = "Change owner of schema '${schema}' to ${owner}" - $schema_command = "ALTER SCHEMA \"${schema}\" OWNER TO ${owner}" - postgresql_psql { $schema_title: - command => $schema_command, - onlyif => $schema_exists, - require => Class['postgresql::server'], - } - } else { - # Create a new schema - $schema_title = "Create Schema '${title}'" - $schema_command = "CREATE SCHEMA \"${schema}\" ${authorization}" - postgresql_psql { $schema_title: - command => $schema_command, - unless => $schema_exists, - require => Class['postgresql::server'], + if $owner { + postgresql_psql { "${db}: ALTER SCHEMA \"${schema}\" OWNER TO \"${owner}\"": + command => "ALTER SCHEMA \"${schema}\" OWNER TO ${owner}", + unless => "SELECT 1 FROM pg_namespace JOIN pg_roles rol ON nspowner = rol.oid WHERE nspname = '${schema}' AND rolname = '${owner}'", + require => Postgresql_psql["${db}: CREATE SCHEMA \"${schema}\""], } - } - if($owner != undef and defined(Postgresql::Server::Role[$owner])) { - Postgresql::Server::Role[$owner]->Postgresql_psql[$schema_title] + if defined(Postgresql::Server::Role[$owner]) { + Postgresql::Server::Role[$owner]->Postgresql_psql["${db}: ALTER SCHEMA \"${schema}\" OWNER TO \"${owner}\""] + } } } diff --git a/manifests/server/tablespace.pp b/manifests/server/tablespace.pp index 23ab919..cf0b65d 100644 --- a/manifests/server/tablespace.pp +++ b/manifests/server/tablespace.pp @@ -1,58 +1,56 @@ # This module creates tablespace. See README.md for more details. define postgresql::server::tablespace( $location, $owner = undef, $spcname = $title, $connect_settings = $postgresql::server::default_connect_settings, ) { $user = $postgresql::server::user $group = $postgresql::server::group $psql_path = $postgresql::server::psql_path $module_workdir = $postgresql::server::module_workdir # If the connection settings do not contain a port, then use the local server port if $connect_settings != undef and has_key( $connect_settings, 'PGPORT') { $port = undef } else { $port = $postgresql::server::port } Postgresql_psql { psql_user => $user, psql_group => $group, psql_path => $psql_path, port => $port, connect_settings => $connect_settings, cwd => $module_workdir, } - if ($owner == undef) { - $owner_section = '' - } else { - $owner_section = "OWNER \"${owner}\"" - } - - $create_tablespace_command = "CREATE TABLESPACE \"${spcname}\" ${owner_section} LOCATION '${location}'" - file { $location: ensure => directory, owner => $user, group => $group, mode => '0700', seluser => 'system_u', selrole => 'object_r', seltype => 'postgresql_db_t', require => Class['postgresql::server'], } - $create_ts = "Create tablespace '${spcname}'" - postgresql_psql { "Create tablespace '${spcname}'": - command => $create_tablespace_command, - unless => "SELECT spcname FROM pg_tablespace WHERE spcname='${spcname}'", + postgresql_psql { "CREATE TABLESPACE \"${spcname}\"": + command => "CREATE TABLESPACE \"${spcname}\" LOCATION '${location}'", + unless => "SELECT 1 FROM pg_tablespace WHERE spcname = '${spcname}'", require => [Class['postgresql::server'], File[$location]], } - if($owner != undef and defined(Postgresql::Server::Role[$owner])) { - Postgresql::Server::Role[$owner]->Postgresql_psql[$create_ts] + if $owner { + postgresql_psql { "ALTER TABLESPACE \"${spcname}\" OWNER TO \"${owner}\"": + unless => "SELECT 1 FROM pg_tablespace JOIN pg_roles rol ON spcowner = rol.oid WHERE spcname = '${spcname}' AND rolname = '${owner}'", + require => Postgresql_psql["CREATE TABLESPACE \"${spcname}\""], + } + + if defined(Postgresql::Server::Role[$owner]) { + Postgresql::Server::Role[$owner]->Postgresql_psql["ALTER TABLESPACE \"${spcname}\" OWNER TO \"${owner}\""] + } } } diff --git a/spec/acceptance/server/config_entry_spec.rb b/spec/acceptance/server/config_entry_spec.rb new file mode 100644 index 0000000..6e56259 --- /dev/null +++ b/spec/acceptance/server/config_entry_spec.rb @@ -0,0 +1,38 @@ +require 'spec_helper_acceptance' + +describe 'postgresql::server::config_entry' do + + let(:pp_setup) { <<-EOS + class { 'postgresql::server': + postgresql_conf_path => '/tmp/postgresql.conf', + } + EOS + } + + context 'unix_socket_directories' do + let(:pp_test) { pp_setup + <<-EOS + postgresql::server::config_entry { 'unix_socket_directories': + value => '/var/socket/, /root/' + } + EOS + } + + #get postgresql version + apply_manifest("class { 'postgresql::server': }") + result = shell('psql --version') + version = result.stdout.match(%r{\s(\d\.\d)})[1] + + if version >= '9.3' + it 'is expected to run idempotently' do + apply_manifest(pp_test, :catch_failures => true) + apply_manifest(pp_test, :catch_changes => true) + end + + it 'is expected to contain directories' do + shell('cat /tmp/postgresql.conf') do |output| + expect(output.stdout).to contain("unix_socket_directories = '/var/socket/, /root/'") + end + end + end + end +end diff --git a/spec/acceptance/server/grant_role_spec.rb b/spec/acceptance/server/grant_role_spec.rb index f24a8d1..e802a41 100644 --- a/spec/acceptance/server/grant_role_spec.rb +++ b/spec/acceptance/server/grant_role_spec.rb @@ -1,172 +1,230 @@ require 'spec_helper_acceptance' describe 'postgresql::server::grant_role:', :unless => UNSUPPORTED_PLATFORMS.include?(fact('osfamily')) do db = 'grant_role_test' user = 'psql_grant_role_tester' group = 'test_group' password = 'psql_grant_role_pw' it 'should grant a role to a user' do begin pp = <<-EOS.unindent $db = #{db} $user = #{user} $group = #{group} $password = #{password} class { '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::server::role { $user: password_hash => postgresql_password($user, $password), } postgresql::server::database { $db: owner => $user, require => Postgresql::Server::Role[$user], } # Create a rule for the user postgresql::server::pg_hba_rule { "allow ${user}": type => 'local', database => $db, user => $user, auth_method => 'ident', order => 1, } # Create a role to grant to the user postgresql::server::role { $group: db => $db, login => false, require => Postgresql::Server::Database[$db], } # Grant the role to the user postgresql::server::grant_role { "grant_role ${group} to ${user}": role => $user, group => $group, } EOS apply_manifest(pp, :catch_failures => true) apply_manifest(pp, :catch_changes => true) ## Check that the role was granted to the user psql('--command="SELECT 1 WHERE pg_has_role(\'psql_grant_role_tester\', \'test_group\', \'MEMBER\') = true" grant_role_test', 'psql_grant_role_tester') do |r| expect(r.stdout).to match(/\(1 row\)/) expect(r.stderr).to eq('') end end end + it 'should grant a role to a superuser' do + begin + pp = <<-EOS.unindent + $db = "#{db}" + $user = "#{user}" + $group = "#{group}" + $password = #{password} + + class { '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::server::role { $user: + password_hash => postgresql_password($user, $password), + superuser => true, + } + + postgresql::server::database { $db: + owner => $user, + require => Postgresql::Server::Role[$user], + } + + # Create a rule for the user + postgresql::server::pg_hba_rule { "allow ${user}": + type => 'local', + database => $db, + user => $user, + auth_method => 'ident', + order => 1, + } + + # Create a role to grant to the user + postgresql::server::role { $group: + db => $db, + login => false, + require => Postgresql::Server::Database[$db], + } + + # Grant the role to the user + postgresql::server::grant_role { "grant_role ${group} to ${user}": + role => $user, + group => $group, + } + EOS + + apply_manifest(pp, :catch_failures => true) + apply_manifest(pp, :catch_changes => true) + + ## Check that the role was granted to the user + psql('--command="SELECT 1 FROM pg_roles AS r_role JOIN pg_auth_members AS am ON r_role.oid = am.member JOIN pg_roles AS r_group ON r_group.oid = am.roleid WHERE r_group.rolname = \'test_group\' AND r_role.rolname = \'psql_grant_role_tester\'" grant_role_test', 'psql_grant_role_tester') do |r| + expect(r.stdout).to match(/\(1 row\)/) + expect(r.stderr).to eq('') + end + end + end + it 'should revoke a role from a user' do begin pp = <<-EOS $db = "#{db}" $user = "#{user}" $group = "#{group}" $password = #{password} class { '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::server::role { $user: password_hash => postgresql_password($user, $password), } postgresql::server::database { $db: owner => $user, require => Postgresql::Server::Role[$user], } # Create a rule for the user postgresql::server::pg_hba_rule { "allow ${user}": type => 'local', database => $db, user => $user, auth_method => 'ident', order => 1, } # Create a role to grant to the user postgresql::server::role { $group: db => $db, login => false, require => Postgresql::Server::Database[$db], } # Grant the role to the user postgresql::server::grant_role { "grant_role ${group} to ${user}": role => $user, group => $group, } postgresql::server::grant_role {"revoke ${group} from ${user}": ensure => absent, role => $user, group => $group, } EOS apply_manifest(pp, :catch_failures => true) apply_manifest(pp, :expect_changes => true) psql('--command="SELECT 1 WHERE pg_has_role(\'psql_grant_role_tester\', \'test_group\', \'MEMBER\') = true" grant_role_test', 'psql_grant_role_tester') do |r| expect(r.stdout).to match(/\(0 rows\)/) expect(r.stderr).to eq('') end end end it 'should not grant permission to a nonexistent user' do begin pp = <<-EOS $db = "#{db}" $user = "#{user}" $group = "#{group}" $password = #{password} class { 'postgresql::server': } # Since we are not testing pg_hba or any of that, make a local user for ident auth user { $user: ensure => absent, } postgresql::server::database { $db: } # Create a role to grant to the nonexistent user postgresql::server::role { $group: db => $db, login => false, require => Postgresql::Server::Database[$db], } # Grant the role to the nonexistent user postgresql::server::grant_role { "grant_role ${group} to ${user}": role => $user group => $group, } EOS apply_manifest(pp, :expect_failures => true) psql('--command="SELECT 1 WHERE pg_has_role(\'psql_grant_role_tester\', \'test_group\', \'MEMBER\') = true" grant_role_test', 'psql_grant_role_tester') do |r| expect(r.stdout).to match(/\(0 rows\)/) expect(r.stderr).to eq('') end end end - end diff --git a/spec/acceptance/server/grant_spec.rb b/spec/acceptance/server/grant_spec.rb new file mode 100644 index 0000000..63f2d7e --- /dev/null +++ b/spec/acceptance/server/grant_spec.rb @@ -0,0 +1,306 @@ +require 'spec_helper_acceptance' + +describe 'postgresql::server::grant:', :unless => UNSUPPORTED_PLATFORMS.include?(fact('osfamily')) do + + let(:db) { 'grant_priv_test' } + let(:owner) { 'psql_grant_priv_owner' } + let(:user) { 'psql_grant_priv_tester' } + let(:password) { 'psql_grant_role_pw' } + let(:pp_install) { "class {'postgresql::server': }"} + + let(:pp_setup) { pp_setup = <<-EOS.unindent + $db = #{db} + $owner = #{owner} + $user = #{user} + $password = #{password} + + class { 'postgresql::server': } + + postgresql::server::role { $owner: + password_hash => postgresql_password($owner, $password), + } + + # Since we are not testing pg_hba or any of that, make a local user for ident auth + user { $owner: + ensure => present, + } + + postgresql::server::database { $db: + owner => $owner, + require => Postgresql::Server::Role[$owner], + } + + # Create a user to grant privileges to + postgresql::server::role { $user: + db => $db, + require => Postgresql::Server::Database[$db], + } + + # Make a local user for ident auth + user { $user: + ensure => present, + } + + # Grant them connect to the database + postgresql::server::database_grant { "allow connect for ${user}": + privilege => 'CONNECT', + db => $db, + role => $user, + } + EOS + } + + context 'LANGUAGE' do + describe 'GRANT * ON LANGUAGE' do + #testing grants on language requires a superuser + let(:superuser) { 'postgres' } + let(:pp_lang) { pp_setup + <<-EOS.unindent + + postgresql_psql { 'make sure plpgsql exists': + command => 'CREATE LANGUAGE plpgsql', + db => $db, + psql_user => '#{superuser}', + unless => "SELECT 1 from pg_language where lanname = 'plpgsql'", + require => Postgresql::Server::Database[$db], + } + + postgresql::server::grant { 'grant usage on plpgsql': + psql_user => '#{superuser}', + privilege => 'USAGE', + object_type => 'LANGUAGE', + object_name => 'plpgsql', + role => $user, + db => $db, + require => [ Postgresql_psql['make sure plpgsql exists'], + Postgresql::Server::Role[$user], ] + } + EOS + } + + it 'is expected to run idempotently' do + apply_manifest(pp_install) + + #postgres version + result = shell('psql --version') + version = result.stdout.match(%r{\s(\d\.\d)})[1] + + if version >= '8.4.0' + apply_manifest(pp_lang, :catch_failures => true) + apply_manifest(pp_lang, :catch_changes => true) + end + end + + it 'is expected to GRANT USAGE ON LANGUAGE plpgsql to ROLE' do + result = shell('psql --version') + version = result.stdout.match(%r{\s(\d\.\d)})[1] + + if version >= '8.4.0' + ## Check that the privilege was granted to the user + psql("-d #{db} --command=\"SELECT 1 WHERE has_language_privilege('#{user}', 'plpgsql', 'USAGE')\"", superuser) do |r| + expect(r.stdout).to match(/\(1 row\)/) + expect(r.stderr).to eq('') + end + end + end + + let(:pp_onlyif) { pp_setup + <<-EOS.unindent + postgresql::server::grant { 'grant usage on BSql': + psql_user => '#{superuser}', + privilege => 'USAGE', + object_type => 'LANGUAGE', + object_name => 'bsql', + role => $user, + db => $db, + onlyif_exists => true, + } + EOS + } + + #test onlyif_exists function + it 'is expected to not GRANT USAGE ON (dummy)LANGUAGE BSql to ROLE' do + apply_manifest(pp_install) + + #postgres version + result = shell('psql --version') + version = result.stdout.match(%r{\s(\d\.\d)})[1] + + if version >= '8.4.0' + apply_manifest(pp_onlyif, :catch_failures => true) + apply_manifest(pp_onlyif, :catch_changes => true) + end + end + end + end + + context 'sequence' do + it 'should grant usage on a sequence to a user' do + begin + pp = pp_setup + <<-EOS.unindent + + postgresql_psql { 'create test sequence': + command => 'CREATE SEQUENCE test_seq', + db => $db, + psql_user => $owner, + unless => "SELECT 1 FROM information_schema.sequences WHERE sequence_name = 'test_seq'", + require => Postgresql::Server::Database[$db], + } + + postgresql::server::grant { 'grant usage on test_seq': + privilege => 'USAGE', + object_type => 'SEQUENCE', + object_name => 'test_seq', + db => $db, + role => $user, + require => [ Postgresql_psql['create test sequence'], + Postgresql::Server::Role[$user], ] + } + EOS + + apply_manifest(pp_install, :catch_failures => true) + + #postgres version + result = shell('psql --version') + version = result.stdout.match(%r{\s(\d\.\d)})[1] + + if version >= '9.0' + apply_manifest(pp, :catch_failures => true) + apply_manifest(pp, :catch_changes => true) + + ## Check that the privilege was granted to the user + psql("-d #{db} --command=\"SELECT 1 WHERE has_sequence_privilege('#{user}', 'test_seq', 'USAGE')\"", user) do |r| + expect(r.stdout).to match(/\(1 row\)/) + expect(r.stderr).to eq('') + end + end + end + end + + it 'should grant update on a sequence to a user' do + begin + pp = pp_setup + <<-EOS.unindent + + postgresql_psql { 'create test sequence': + command => 'CREATE SEQUENCE test_seq', + db => $db, + psql_user => $owner, + unless => "SELECT 1 FROM information_schema.sequences WHERE sequence_name = 'test_seq'", + require => Postgresql::Server::Database[$db], + } + + postgresql::server::grant { 'grant update on test_seq': + privilege => 'UPDATE', + object_type => 'SEQUENCE', + object_name => 'test_seq', + db => $db, + role => $user, + require => [ Postgresql_psql['create test sequence'], + Postgresql::Server::Role[$user], ] + } + EOS + + apply_manifest(pp_install, :catch_failures => true) + + #postgres version + result = shell('psql --version') + version = result.stdout.match(%r{\s(\d\.\d)})[1] + + if version >= '9.0' + apply_manifest(pp, :catch_failures => true) + apply_manifest(pp, :catch_changes => true) + + ## Check that the privilege was granted to the user + psql("-d #{db} --command=\"SELECT 1 WHERE has_sequence_privilege('#{user}', 'test_seq', 'UPDATE')\"", user) do |r| + expect(r.stdout).to match(/\(1 row\)/) + expect(r.stderr).to eq('') + end + end + end + end + end + + context 'all sequences' do + it 'should grant usage on all sequences to a user' do + begin + pp = pp_setup + <<-EOS.unindent + + postgresql_psql { 'create test sequences': + command => 'CREATE SEQUENCE test_seq2; CREATE SEQUENCE test_seq3;', + db => $db, + psql_user => $owner, + unless => "SELECT 1 FROM information_schema.sequences WHERE sequence_name = 'test_seq2'", + require => Postgresql::Server::Database[$db], + } + + postgresql::server::grant { 'grant usage on all sequences': + privilege => 'USAGE', + object_type => 'ALL SEQUENCES IN SCHEMA', + object_name => 'public', + db => $db, + role => $user, + require => [ Postgresql_psql['create test sequences'], + Postgresql::Server::Role[$user], ] + } + EOS + + apply_manifest(pp_install, :catch_failures => true) + + #postgres version + result = shell('psql --version') + version = result.stdout.match(%r{\s(\d\.\d)})[1] + + if version >= '9.0' + apply_manifest(pp, :catch_failures => true) + apply_manifest(pp, :catch_changes => true) + + ## Check that the privileges were granted to the user, this check is not available on version < 9.0 + psql("-d #{db} --command=\"SELECT 1 WHERE has_sequence_privilege('#{user}', 'test_seq2', 'USAGE') AND has_sequence_privilege('#{user}', 'test_seq3', 'USAGE')\"", user) do |r| + expect(r.stdout).to match(/\(1 row\)/) + expect(r.stderr).to eq('') + end + end + end + end + + it 'should grant update on all sequences to a user' do + begin + pp = pp_setup + <<-EOS.unindent + + postgresql_psql { 'create test sequences': + command => 'CREATE SEQUENCE test_seq2; CREATE SEQUENCE test_seq3;', + db => $db, + psql_user => $owner, + unless => "SELECT 1 FROM information_schema.sequences WHERE sequence_name = 'test_seq2'", + require => Postgresql::Server::Database[$db], + } + + postgresql::server::grant { 'grant usage on all sequences': + privilege => 'UPDATE', + object_type => 'ALL SEQUENCES IN SCHEMA', + object_name => 'public', + db => $db, + role => $user, + require => [ Postgresql_psql['create test sequences'], + Postgresql::Server::Role[$user], ] + } + EOS + + apply_manifest(pp_install, :catch_failures => true) + + #postgres version + result = shell('psql --version') + version = result.stdout.match(%r{\s(\d\.\d)})[1] + + if version >= '9.0' + apply_manifest(pp, :catch_failures => true) + apply_manifest(pp, :catch_changes => true) + + ## Check that the privileges were granted to the user + psql("-d #{db} --command=\"SELECT 1 WHERE has_sequence_privilege('#{user}', 'test_seq2', 'UPDATE') AND has_sequence_privilege('#{user}', 'test_seq3', 'UPDATE')\"", user) do |r| + expect(r.stdout).to match(/\(1 row\)/) + expect(r.stderr).to eq('') + end + end + end + end + end +end diff --git a/spec/spec.opts b/spec/spec.opts deleted file mode 100644 index 91cd642..0000000 --- a/spec/spec.opts +++ /dev/null @@ -1,6 +0,0 @@ ---format -s ---colour ---loadby -mtime ---backtrace diff --git a/spec/spec_helper_acceptance.rb b/spec/spec_helper_acceptance.rb index 2525ec3..050660d 100644 --- a/spec/spec_helper_acceptance.rb +++ b/spec/spec_helper_acceptance.rb @@ -1,101 +1,92 @@ require 'beaker-rspec/spec_helper' require 'beaker-rspec/helpers/serverspec' require 'beaker/puppet_install_helper' +require 'beaker/module_install_helper' run_puppet_install_helper +install_ca_certs unless ENV['PUPPET_INSTALL_TYPE'] =~ /pe/i +install_module_on(hosts) +install_module_dependencies_on(hosts) UNSUPPORTED_PLATFORMS = ['AIX','windows','Solaris','Suse'] class String # Provide ability to remove indentation from strings, for the purpose of # left justifying heredoc blocks. def unindent gsub(/^#{scan(/^\s*/).min_by{|l|l.length}}/, "") end end def shellescape(str) str = str.to_s # An empty argument will be skipped, so return empty quotes. return "''" if str.empty? str = str.dup # Treat multibyte characters as is. It is caller's responsibility # to encode the string in the right encoding for the shell # environment. str.gsub!(/([^A-Za-z0-9_\-.,:\/@\n])/, "\\\\\\1") # A LF cannot be escaped with a backslash because a backslash + LF # combo is regarded as line continuation and simply ignored. str.gsub!(/\n/, "'\n'") return str end def psql(psql_cmd, user = 'postgres', exit_codes = [0,1], &block) psql = "psql #{psql_cmd}" shell("su #{shellescape(user)} -c #{shellescape(psql)}", :acceptable_exit_codes => exit_codes, &block) end - RSpec.configure do |c| - # Project root - proj_root = File.expand_path(File.join(File.dirname(__FILE__), '..')) - # Readable test descriptions c.formatter = :documentation # Configure all nodes in nodeset c.before :suite do - # Install module and dependencies - puppet_module_install(:source => proj_root, :module_name => 'postgresql') - # Set up selinux if appropriate. if fact('osfamily') == 'RedHat' && fact('selinux') == 'true' pp = <<-EOS if $::osfamily == 'RedHat' and $::selinux == 'true' { $semanage_package = $::operatingsystemmajrelease ? { '5' => 'policycoreutils', default => 'policycoreutils-python', } package { $semanage_package: ensure => installed } exec { 'set_postgres': command => 'semanage port -a -t postgresql_port_t -p tcp 5433', path => '/bin:/usr/bin/:/sbin:/usr/sbin', subscribe => Package[$semanage_package], } } EOS apply_manifest_on(agents, pp, :catch_failures => false) end # net-tools required for netstat utility being used by be_listening if fact('osfamily') == 'RedHat' && fact('operatingsystemmajrelease') == '7' pp = <<-EOS package { 'net-tools': ensure => installed } EOS apply_manifest_on(agents, pp, :catch_failures => false) end hosts.each do |host| - on host, "/bin/touch #{default['puppetpath']}/hiera.yaml" + on host, "/bin/touch #{host['puppetpath']}/hiera.yaml" on host, 'chmod 755 /root' if fact_on(host, 'osfamily') == 'Debian' on host, "echo \"en_US ISO-8859-1\nen_NG.UTF-8 UTF-8\nen_US.UTF-8 UTF-8\n\" > /etc/locale.gen" on host, '/usr/sbin/locale-gen' on host, '/usr/sbin/update-locale' end - - on host, puppet('module','install','puppetlabs-stdlib'), { :acceptable_exit_codes => [0,1] } - on host, puppet('module','install','puppetlabs-apt'), { :acceptable_exit_codes => [0,1] } - on host, puppet('module','install','--force','puppetlabs-concat'), { :acceptable_exit_codes => [0,1] } end - - end end diff --git a/spec/unit/classes/client_spec.rb b/spec/unit/classes/client_spec.rb index 3d63b46..3f2e58f 100644 --- a/spec/unit/classes/client_spec.rb +++ b/spec/unit/classes/client_spec.rb @@ -1,47 +1,58 @@ require 'spec_helper' describe 'postgresql::client', :type => :class do let :facts do { :osfamily => 'Debian', :operatingsystem => 'Debian', :operatingsystemrelease => '6.0', } end describe 'with parameters' do let :params do { :validcon_script_path => '/opt/bin/my-validate-con.sh', :package_ensure => 'absent', :package_name => 'mypackage', :file_ensure => 'file' } end it 'should modify package' do is_expected.to contain_package("postgresql-client").with({ :ensure => 'absent', :name => 'mypackage', :tag => 'postgresql', }) end it 'should have specified validate connexion' do should contain_file('/opt/bin/my-validate-con.sh').with({ :ensure => 'file', :owner => 0, :group => 0, :mode => '0755' }) end end describe 'with no parameters' do it 'should create package with postgresql tag' do is_expected.to contain_package('postgresql-client').with({ :tag => 'postgresql', }) end end + + describe 'with client package name explicitly set undef' do + let :params do + { + :package_name => 'UNSET' + } + end + it 'should not manage postgresql-client package' do + is_expected.not_to contain_package('postgresql-client') + end + end end diff --git a/spec/unit/classes/globals_spec.rb b/spec/unit/classes/globals_spec.rb index ce79336..ea3ff9d 100644 --- a/spec/unit/classes/globals_spec.rb +++ b/spec/unit/classes/globals_spec.rb @@ -1,67 +1,87 @@ require 'spec_helper' -describe 'postgresql::globals', :type => :class do - context "on a debian 6" do +describe 'postgresql::globals', type: :class do + context 'on a debian 6' do let (:facts) do { :osfamily => 'Debian', :operatingsystem => 'Debian', :operatingsystemrelease => '6.0', :lsbdistid => 'Debian', - :lsbdistcodename => 'squeeze', + :lsbdistcodename => 'squeeze' } end describe 'with no parameters' do it 'should work' do - is_expected.to contain_class("postgresql::globals") + is_expected.to contain_class('postgresql::globals') end end describe 'manage_package_repo => true' do let(:params) do { - :manage_package_repo => true, + manage_package_repo: true } end it 'should pull in class postgresql::repo' do - is_expected.to contain_class("postgresql::repo") + is_expected.to contain_class('postgresql::repo') end end end context 'on redhat family systems' do let (:facts) do { - :osfamily => 'RedHat', - :operatingsystem => 'RedHat', - :operatingsystemrelease => '7.1', + osfamily: 'RedHat', + operatingsystem: 'RedHat', + operatingsystemrelease: '7.1' } end describe 'with no parameters' do it 'should work' do - is_expected.to contain_class("postgresql::globals") + is_expected.to contain_class('postgresql::globals') end end - + describe 'manage_package_repo on RHEL => true' do let(:params) do { - :manage_package_repo => true, - :repo_proxy => 'http://proxy-server:8080', + manage_package_repo: true, + repo_proxy: 'http://proxy-server:8080' } end - + it 'should pull in class postgresql::repo' do - is_expected.to contain_class("postgresql::repo") + is_expected.to contain_class('postgresql::repo') end it do should contain_yumrepo('yum.postgresql.org').with( 'enabled' => '1', 'proxy' => 'http://proxy-server:8080' ) end end + + describe 'repo_baseurl on RHEL => mirror.localrepo.com' do + let(:params) do + { + manage_package_repo: true, + repo_baseurl: 'http://mirror.localrepo.com' + } + end + + it 'should pull in class postgresql::repo' do + is_expected.to contain_class('postgresql::repo') + end + + it do + should contain_yumrepo('yum.postgresql.org').with( + 'enabled' => '1', + 'baseurl' => 'http://mirror.localrepo.com' + ) + end + end end end diff --git a/spec/unit/classes/lib/devel_spec.rb b/spec/unit/classes/lib/devel_spec.rb index 17aa7f2..ca0ebb3 100644 --- a/spec/unit/classes/lib/devel_spec.rb +++ b/spec/unit/classes/lib/devel_spec.rb @@ -1,54 +1,73 @@ require 'spec_helper' describe 'postgresql::lib::devel', :type => :class do let :facts do { :osfamily => 'Debian', :operatingsystem => 'Debian', :operatingsystemrelease => '6.0', } end it { is_expected.to contain_class("postgresql::lib::devel") } describe 'link pg_config to /usr/bin' do it { should_not contain_file('/usr/bin/pg_config') \ .with_ensure('link') \ .with_target('/usr/lib/postgresql/8.4/bin/pg_config') } end describe 'disable link_pg_config' do let(:params) {{ :link_pg_config => false, }} it { should_not contain_file('/usr/bin/pg_config') } end describe 'should not link pg_config on RedHat with default version' do let(:facts) {{ :osfamily => 'RedHat', :operatingsystem => 'CentOS', :operatingsystemrelease => '6.3', :operatingsystemmajrelease => '6', }} it { should_not contain_file('/usr/bin/pg_config') } end describe 'link pg_config on RedHat with non-default version' do let(:facts) {{ :osfamily => 'RedHat', :operatingsystem => 'CentOS', :operatingsystemrelease => '6.3', :operatingsystemmajrelease => '6', }} let :pre_condition do "class { '::postgresql::globals': version => '9.3' }" end it { should contain_file('/usr/bin/pg_config') \ .with_ensure('link') \ .with_target('/usr/pgsql-9.3/bin/pg_config') } end + describe 'on Gentoo' do + let :facts do + { + :osfamily => 'Gentoo', + :operatingsystem => 'Gentoo', + } + end + let :params do + { + :link_pg_config => false, + } + end + + it 'should fail to compile' do + expect { + is_expected.to compile + }.to raise_error(/is not supported/) + end + end end diff --git a/spec/unit/classes/lib/java_spec.rb b/spec/unit/classes/lib/java_spec.rb index f31c3f0..76dbbd9 100644 --- a/spec/unit/classes/lib/java_spec.rb +++ b/spec/unit/classes/lib/java_spec.rb @@ -1,43 +1,43 @@ require 'spec_helper' describe 'postgresql::lib::java', :type => :class do describe 'on a debian based os' do let :facts do { :osfamily => 'Debian', :operatingsystem => 'Debian', :operatingsystemrelease => '6.0', } end it { is_expected.to contain_package('postgresql-jdbc').with( - :name => 'libpostgresql-jdbc-java', + :name => 'libpg-java', :ensure => 'present', :tag => 'postgresql' )} end describe 'on a redhat based os' do let :facts do { :osfamily => 'RedHat', :operatingsystem => 'RedHat', :operatingsystemrelease => '6.4', } end it { is_expected.to contain_package('postgresql-jdbc').with( :name => 'postgresql-jdbc', :ensure => 'present', :tag => 'postgresql' )} describe 'when parameters are supplied' do let :params do {:package_ensure => 'latest', :package_name => 'somepackage'} end it { is_expected.to contain_package('postgresql-jdbc').with( :name => 'somepackage', :ensure => 'latest', :tag => 'postgresql' )} end end end diff --git a/spec/unit/classes/server/config_spec.rb b/spec/unit/classes/server/config_spec.rb index c03032d..16e1aef 100644 --- a/spec/unit/classes/server/config_spec.rb +++ b/spec/unit/classes/server/config_spec.rb @@ -1,101 +1,136 @@ require 'spec_helper' describe 'postgresql::server::config', :type => :class do let (:pre_condition) do "include postgresql::server" end describe 'on RedHat 7' do let :facts do { :osfamily => 'RedHat', :operatingsystem => 'CentOS', :operatingsystemrelease => '7.0', :concat_basedir => tmpfilename('server'), :kernel => 'Linux', :id => 'root', :path => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin', + :selinux => true, } end it 'should have the correct systemd-override file' do is_expected.to contain_file('systemd-override').with ({ :ensure => 'present', :path => '/etc/systemd/system/postgresql.service', :owner => 'root', :group => 'root', }) is_expected.to contain_file('systemd-override') \ .with_content(/.include \/usr\/lib\/systemd\/system\/postgresql.service/) end describe 'with manage_package_repo => true and a version' do let (:pre_condition) do <<-EOS class { 'postgresql::globals': manage_package_repo => true, version => '9.4', }-> class { 'postgresql::server': } EOS end it 'should have the correct systemd-override file' do is_expected.to contain_file('systemd-override').with ({ :ensure => 'present', :path => '/etc/systemd/system/postgresql-9.4.service', :owner => 'root', :group => 'root', }) is_expected.to contain_file('systemd-override') \ .with_content(/.include \/usr\/lib\/systemd\/system\/postgresql-9.4.service/) end end end describe 'on Fedora 21' do let :facts do { :osfamily => 'RedHat', :operatingsystem => 'Fedora', :operatingsystemrelease => '21', :concat_basedir => tmpfilename('server'), :kernel => 'Linux', :id => 'root', :path => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin', + :selinux => true, } end it 'should have the correct systemd-override file' do is_expected.to contain_file('systemd-override').with ({ :ensure => 'present', :path => '/etc/systemd/system/postgresql.service', :owner => 'root', :group => 'root', }) is_expected.to contain_file('systemd-override') \ .with_content(/.include \/lib\/systemd\/system\/postgresql.service/) end describe 'with manage_package_repo => true and a version' do let (:pre_condition) do <<-EOS class { 'postgresql::globals': manage_package_repo => true, version => '9.4', }-> class { 'postgresql::server': } EOS end it 'should have the correct systemd-override file' do is_expected.to contain_file('systemd-override').with ({ :ensure => 'present', :path => '/etc/systemd/system/postgresql-9.4.service', :owner => 'root', :group => 'root', }) is_expected.to contain_file('systemd-override') \ .with_content(/.include \/lib\/systemd\/system\/postgresql-9.4.service/) end end end + + describe 'on Gentoo' do + let (:pre_condition) do + <<-EOS + class { 'postgresql::globals': + version => '9.5', + }-> + class { 'postgresql::server': } + EOS + end + let :facts do + { + :osfamily => 'Gentoo', + :operatingsystem => 'Gentoo', + :operatingsystemrelease => 'unused', + :concat_basedir => tmpfilename('server'), + :kernel => 'Linux', + :id => 'root', + :path => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin', + :selinux => false, + } + end + it 'should have the correct systemd-override file' do + is_expected.to contain_file('systemd-override').with ({ + :ensure => 'present', + :path => '/etc/systemd/system/postgresql-9.5.service', + :owner => 'root', + :group => 'root', + }) + is_expected.to contain_file('systemd-override') \ + .with_content(/.include \/usr\/lib64\/systemd\/system\/postgresql-9.5.service/) + end + end end diff --git a/spec/unit/classes/server/contrib_spec.rb b/spec/unit/classes/server/contrib_spec.rb index b84f764..e268436 100644 --- a/spec/unit/classes/server/contrib_spec.rb +++ b/spec/unit/classes/server/contrib_spec.rb @@ -1,44 +1,59 @@ require 'spec_helper' describe 'postgresql::server::contrib', :type => :class do let :pre_condition do "class { 'postgresql::server': }" end let :facts do { :osfamily => 'Debian', :operatingsystem => 'Debian', :operatingsystemrelease => '6.0', :kernel => 'Linux', :concat_basedir => tmpfilename('contrib'), :id => 'root', :path => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin', } end describe 'with parameters' do let(:params) do { :package_name => 'mypackage', :package_ensure => 'absent', } end it 'should create package with correct params' do is_expected.to contain_package('postgresql-contrib').with({ :ensure => 'absent', :name => 'mypackage', :tag => 'postgresql', }) end end describe 'with no parameters' do it 'should create package with postgresql tag' do is_expected.to contain_package('postgresql-contrib').with({ :tag => 'postgresql', }) end end + + describe 'on Gentoo' do + let :facts do + { + :osfamily => 'Gentoo', + :operatingsystem => 'Gentoo', + } + end + + it 'should fail to compile' do + expect { + is_expected.to compile + }.to raise_error(/is not supported/) + end + end end diff --git a/spec/unit/classes/server/initdb_spec.rb b/spec/unit/classes/server/initdb_spec.rb index 54044fb..3482970 100644 --- a/spec/unit/classes/server/initdb_spec.rb +++ b/spec/unit/classes/server/initdb_spec.rb @@ -1,122 +1,127 @@ require 'spec_helper' describe 'postgresql::server::initdb', :type => :class do let (:pre_condition) do "include postgresql::server" end describe 'on RedHat' do let :facts do { :osfamily => 'RedHat', :operatingsystem => 'CentOS', :operatingsystemrelease => '6.0', :concat_basedir => tmpfilename('server'), :kernel => 'Linux', :id => 'root', :path => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin', + :selinux => true, } end it { is_expected.to contain_file('/var/lib/pgsql/data').with_ensure('directory') } end describe 'on Amazon' do let :facts do { :osfamily => 'RedHat', :operatingsystem => 'Amazon', :operatingsystemrelease => '1.0', :concat_basedir => tmpfilename('server'), :kernel => 'Linux', :id => 'root', :path => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin', + :selinux => true, } end it { is_expected.to contain_file('/var/lib/pgsql92/data').with_ensure('directory') } end describe 'exec with module_workdir => /var/tmp' do let :facts do { :osfamily => 'RedHat', :operatingsystem => 'CentOS', :operatingsystemrelease => '6.0', :concat_basedir => tmpfilename('server'), :kernel => 'Linux', :id => 'root', :path => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin', + :selinux => true, } end let (:pre_condition) do <<-EOS class { 'postgresql::globals': module_workdir => '/var/tmp', }-> class { 'postgresql::server': } EOS end it 'should contain exec with specified working directory' do is_expected.to contain_exec('postgresql_initdb').with ({ :cwd => '/var/tmp', }) end end describe 'exec with module_workdir => undef' do let :facts do { :osfamily => 'RedHat', :operatingsystem => 'CentOS', :operatingsystemrelease => '6.0', :concat_basedir => tmpfilename('server'), :kernel => 'Linux', :id => 'root', :path => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin', + :selinux => true, } end let (:pre_condition) do <<-EOS class { 'postgresql::globals': }-> class { 'postgresql::server': } EOS end it 'should contain exec with default working directory' do is_expected.to contain_exec('postgresql_initdb').with ({ :cwd => '/tmp', }) end end describe 'postgresql_psql with module_workdir => /var/tmp' do let :facts do { :osfamily => 'RedHat', :operatingsystem => 'CentOS', :operatingsystemrelease => '6.0', :concat_basedir => tmpfilename('server'), :kernel => 'Linux', :id => 'root', :path => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin', + :selinux => true, } end let (:pre_condition) do <<-EOS class { 'postgresql::globals': module_workdir => '/var/tmp', encoding => 'test', needs_initdb => false, }-> class { 'postgresql::server': } EOS end it 'should contain postgresql_psql with specified working directory' do is_expected.to contain_postgresql_psql('Set template1 encoding to test').with({ :cwd => '/var/tmp', }) end end end diff --git a/spec/unit/classes/server/plpython_spec.rb b/spec/unit/classes/server/plpython_spec.rb index f2e1654..29a1440 100644 --- a/spec/unit/classes/server/plpython_spec.rb +++ b/spec/unit/classes/server/plpython_spec.rb @@ -1,47 +1,48 @@ require 'spec_helper' describe 'postgresql::server::plpython', :type => :class do let :facts do { :osfamily => 'RedHat', :operatingsystem => 'CentOS', :operatingsystemrelease => '6.0', :concat_basedir => tmpfilename('plpython'), :kernel => 'Linux', :id => 'root', :path => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin', + :selinux => true, } end let :pre_condition do "class { 'postgresql::server': }" end describe 'on RedHat with no parameters' do it { is_expected.to contain_class("postgresql::server::plpython") } it 'should create package' do is_expected.to contain_package('postgresql-plpython').with({ :ensure => 'present', :tag => 'postgresql', }) end end describe 'with parameters' do let :params do { :package_ensure => 'absent', :package_name => 'mypackage', } end it { is_expected.to contain_class("postgresql::server::plpython") } it 'should create package with correct params' do is_expected.to contain_package('postgresql-plpython').with({ :ensure => 'absent', :name => 'mypackage', :tag => 'postgresql', }) end end end diff --git a/spec/unit/defines/server/config_entry_spec.rb b/spec/unit/defines/server/config_entry_spec.rb index 34963b8..34f0c70 100644 --- a/spec/unit/defines/server/config_entry_spec.rb +++ b/spec/unit/defines/server/config_entry_spec.rb @@ -1,109 +1,136 @@ require 'spec_helper' describe 'postgresql::server::config_entry', :type => :define do let :facts do { :osfamily => 'RedHat', :operatingsystem => 'RedHat', :operatingsystemrelease => '6.4', :kernel => 'Linux', :concat_basedir => tmpfilename('contrib'), :id => 'root', :path => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin', + :selinux => true, } end let(:title) { 'config_entry'} let :target do tmpfilename('postgresql_conf') end let :pre_condition do "class {'postgresql::server':}" end context "syntax check" do let(:params) { { :ensure => 'present'} } it { is_expected.to contain_postgresql__server__config_entry('config_entry') } end context 'ports' do context 'redhat 6' do let :facts do { :osfamily => 'RedHat', :operatingsystem => 'RedHat', :operatingsystemrelease => '6.4', :kernel => 'Linux', :concat_basedir => tmpfilename('contrib'), :id => 'root', :path => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin', + :selinux => true, } end let(:params) {{ :ensure => 'present', :name => 'port_spec', :value => '5432' }} it 'stops postgresql and changes the port' do is_expected.to contain_exec('postgresql_stop_port') is_expected.to contain_augeas('override PGPORT in /etc/sysconfig/pgsql/postgresql') end end context 'redhat 7' do let :facts do { :osfamily => 'RedHat', :operatingsystem => 'RedHat', :operatingsystemrelease => '7.0', :kernel => 'Linux', :concat_basedir => tmpfilename('contrib'), :id => 'root', :path => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin', + :selinux => true, } end let(:params) {{ :ensure => 'present', :name => 'port_spec', :value => '5432' }} it 'stops postgresql and changes the port' do is_expected.to contain_file('systemd-override') is_expected.to contain_exec('restart-systemd') end end context 'fedora 19' do let :facts do { :osfamily => 'RedHat', :operatingsystem => 'Fedora', :operatingsystemrelease => '19', :kernel => 'Linux', :concat_basedir => tmpfilename('contrib'), :id => 'root', :path => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin', + :selinux => true, } end let(:params) {{ :ensure => 'present', :name => 'port_spec', :value => '5432' }} it 'stops postgresql and changes the port' do is_expected.to contain_file('systemd-override') is_expected.to contain_exec('restart-systemd') end end end context "data_directory" do let(:params) {{ :ensure => 'present', :name => 'data_directory_spec', :value => '/var/pgsql' }} it 'stops postgresql and changes the data directory' do is_expected.to contain_exec('postgresql_data_directory') is_expected.to contain_augeas('override PGDATA in /etc/sysconfig/pgsql/postgresql') end end context "passes values through appropriately" do let(:params) {{ :ensure => 'present', :name => 'check_function_bodies', :value => 'off' }} it 'with no quotes' do is_expected.to contain_postgresql_conf('check_function_bodies').with({ :name => 'check_function_bodies', :value => 'off' }) end end + + context 'unix_socket_directories' do + let :facts do + { + :osfamily => 'RedHat', + :operatingsystem => 'RedHat', + :operatingsystemrelease => '7.0', + :kernel => 'Linux', + :concat_basedir => tmpfilename('contrib'), + :id => 'root', + :path => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin', + :selinux => true, + } + end + let(:params) {{ :ensure => 'present', :name => 'unix_socket_directories', :value => '/var/pgsql, /opt/postgresql, /root/' }} + + it 'should restart the server and change unix_socket_directories to the provided list' do + is_expected.to contain_postgresql_conf('unix_socket_directories') + .with({ :name => 'unix_socket_directories', + :value => '/var/pgsql, /opt/postgresql, /root/'}) + .that_notifies('Class[postgresql::server::service]') + end + end end diff --git a/spec/unit/defines/server/database_spec.rb b/spec/unit/defines/server/database_spec.rb index 1148cc7..c9993f6 100644 --- a/spec/unit/defines/server/database_spec.rb +++ b/spec/unit/defines/server/database_spec.rb @@ -1,79 +1,78 @@ require 'spec_helper' describe 'postgresql::server::database', :type => :define do let :facts do { :osfamily => 'Debian', :operatingsystem => 'Debian', :operatingsystemrelease => '6.0', :kernel => 'Linux', :concat_basedir => tmpfilename('contrib'), :id => 'root', :path => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin', } end let :title do 'test' end let :pre_condition do "class {'postgresql::server':}" end it { is_expected.to contain_postgresql__server__database('test') } - it { is_expected.to contain_postgresql_psql("Create db 'test'") } + it { is_expected.to contain_postgresql_psql('CREATE DATABASE "test"') } context "with comment set to 'test comment'" do let (:params) {{ :comment => 'test comment' }} it { is_expected.to contain_postgresql_psql("COMMENT ON DATABASE \"test\" IS 'test comment'").with_connect_settings( {} ) } end context "with specific db connection settings - default port" do let :pre_condition do "class {'postgresql::server':}" end let (:params) {{ :connect_settings => { 'PGHOST' => 'postgres-db-server', 'DBVERSION' => '9.1', }}} - it { is_expected.to contain_postgresql_psql("Create db 'test'").with_connect_settings( { 'PGHOST' => 'postgres-db-server','DBVERSION' => '9.1' } ).with_port( 5432 ) } + it { is_expected.to contain_postgresql_psql('CREATE DATABASE "test"').with_connect_settings( { 'PGHOST' => 'postgres-db-server','DBVERSION' => '9.1' } ).with_port( 5432 ) } end context "with specific db connection settings - including port" do let :pre_condition do "class {'postgresql::globals':} class {'postgresql::server':}" end let (:params) {{ :connect_settings => { 'PGHOST' => 'postgres-db-server', 'DBVERSION' => '9.1', 'PGPORT' => '1234' }}} - it { is_expected.to contain_postgresql_psql("Create db 'test'").with_connect_settings( { 'PGHOST' => 'postgres-db-server','DBVERSION' => '9.1','PGPORT' => '1234' } ).with_port( nil ) } + it { is_expected.to contain_postgresql_psql('CREATE DATABASE "test"').with_connect_settings( { 'PGHOST' => 'postgres-db-server','DBVERSION' => '9.1','PGPORT' => '1234' } ).with_port( nil ) } end context "with global db connection settings - including port" do let :pre_condition do "class {'postgresql::globals': default_connect_settings => { 'PGHOST' => 'postgres-db-server', 'DBVERSION' => '9.2', 'PGPORT' => '1234' } } class {'postgresql::server':}" end - it { is_expected.to contain_postgresql_psql("Create db 'test'").with_connect_settings( { 'PGHOST' => 'postgres-db-server','DBVERSION' => '9.2','PGPORT' => '1234' } ).with_port( nil ) } + it { is_expected.to contain_postgresql_psql('CREATE DATABASE "test"').with_connect_settings( { 'PGHOST' => 'postgres-db-server','DBVERSION' => '9.2','PGPORT' => '1234' } ).with_port( nil ) } end - context "with change_ownership set to true" do - let (:params) {{ :change_ownership => true, - :owner => 'test_owner' }} + context "with different owner" do + let (:params) {{ :owner => 'test_owner' }} - it { is_expected.to contain_postgresql_psql("Change owner of db 'test' to test_owner") } + it { is_expected.to contain_postgresql_psql('ALTER DATABASE "test" OWNER TO "test_owner"') } end end diff --git a/spec/unit/defines/server/grant_role_spec.rb b/spec/unit/defines/server/grant_role_spec.rb index 2a04bef..6df6ade 100644 --- a/spec/unit/defines/server/grant_role_spec.rb +++ b/spec/unit/defines/server/grant_role_spec.rb @@ -1,161 +1,161 @@ require 'spec_helper' describe 'postgresql::server::grant_role', :type => :define do let :pre_condition do "class { 'postgresql::server': }" end let :facts do {:osfamily => 'Debian', :operatingsystem => 'Debian', :operatingsystemrelease => '6.0', :kernel => 'Linux', :concat_basedir => tmpfilename('postgis'), :id => 'root', :path => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin', } end let (:title) { 'test' } let (:params) { { :group => 'my_group', :role => 'my_role', } } context "with mandatory arguments only" do it { is_expected.to contain_postgresql_psql("grant_role:#{title}").with({ :command => "GRANT \"#{params[:group]}\" TO \"#{params[:role]}\"", - :unless => "SELECT 1 WHERE pg_has_role('#{params[:role]}', '#{params[:group]}', 'MEMBER') = true", + :unless => "SELECT 1 WHERE EXISTS (SELECT 1 FROM pg_roles AS r_role JOIN pg_auth_members AS am ON r_role.oid = am.member JOIN pg_roles AS r_group ON r_group.oid = am.roleid WHERE r_group.rolname = '#{params[:group]}' AND r_role.rolname = '#{params[:role]}') = true", }).that_requires('Class[postgresql::server]') } end context "validation" do context "group invalid type" do let (:params) { { :group => ['a', 'b'], :role => 'r', } } it { expect { catalogue }.to raise_error(Puppet::Error, /is not a string/) } end context "role invalid type" do let (:params) { { :group => 'g', :role => true, } } it { expect { catalogue }.to raise_error(Puppet::Error, /is not a string/) } end context "group empty" do let (:params) { { :group => '', :role => 'r', } } it { expect { catalogue }.to raise_error(/\$group must be set/) } end context "role empty" do let (:params) { { :group => 'g', :role => :undef, } } it { expect { catalogue }.to raise_error(/\$role must be set/) } end end context "with db arguments" do let (:params) { super().merge({ :psql_db => 'postgres', :psql_user => 'postgres', :port => '5432', }) } it { is_expected.to contain_postgresql_psql("grant_role:#{title}").with({ :command => "GRANT \"#{params[:group]}\" TO \"#{params[:role]}\"", - :unless => "SELECT 1 WHERE pg_has_role('#{params[:role]}', '#{params[:group]}', 'MEMBER') = true", + :unless => "SELECT 1 WHERE EXISTS (SELECT 1 FROM pg_roles AS r_role JOIN pg_auth_members AS am ON r_role.oid = am.member JOIN pg_roles AS r_group ON r_group.oid = am.roleid WHERE r_group.rolname = '#{params[:group]}' AND r_role.rolname = '#{params[:role]}') = true", :db => params[:psql_db], :psql_user => params[:psql_user], :port => params[:port], }).that_requires('Class[postgresql::server]') } end context "with ensure => absent" do let (:params) { super().merge({ :ensure => 'absent', }) } it { is_expected.to contain_postgresql_psql("grant_role:#{title}").with({ :command => "REVOKE \"#{params[:group]}\" FROM \"#{params[:role]}\"", - :unless => "SELECT 1 WHERE pg_has_role('#{params[:role]}', '#{params[:group]}', 'MEMBER') != true", + :unless => "SELECT 1 WHERE EXISTS (SELECT 1 FROM pg_roles AS r_role JOIN pg_auth_members AS am ON r_role.oid = am.member JOIN pg_roles AS r_group ON r_group.oid = am.roleid WHERE r_group.rolname = '#{params[:group]}' AND r_role.rolname = '#{params[:role]}') != true", }).that_requires('Class[postgresql::server]') } end context "with ensure => invalid" do let (:params) { super().merge({ :ensure => 'invalid', }) } it { expect { catalogue }.to raise_error(Puppet::Error, /Unknown value for ensure/) } end context "with user defined" do let :pre_condition do "class { 'postgresql::server': } postgresql::server::role { '#{params[:role]}': }" end it { is_expected.to contain_postgresql_psql("grant_role:#{title}").that_requires("Postgresql::Server::Role[#{params[:role]}]") } it { is_expected.not_to contain_postgresql_psql("grant_role:#{title}").that_requires("Postgresql::Server::Role[#{params[:group]}]") } end context "with group defined" do let :pre_condition do "class { 'postgresql::server': } postgresql::server::role { '#{params[:group]}': }" end it { is_expected.to contain_postgresql_psql("grant_role:#{title}").that_requires("Postgresql::Server::Role[#{params[:group]}]") } it { is_expected.not_to contain_postgresql_psql("grant_role:#{title}").that_requires("Postgresql::Server::Role[#{params[:role]}]") } end context "with connect_settings" do let (:params) { super().merge({ :connect_settings => { 'PGHOST' => 'postgres-db-server' }, }) } it { is_expected.to contain_postgresql_psql("grant_role:#{title}").with_connect_settings( { 'PGHOST' => 'postgres-db-server' } ) } it { is_expected.not_to contain_postgresql_psql("grant_role:#{title}").that_requires('Class[postgresql::server]') } end end diff --git a/spec/unit/defines/server/grant_spec.rb b/spec/unit/defines/server/grant_spec.rb index 45d9cce..fe79636 100644 --- a/spec/unit/defines/server/grant_spec.rb +++ b/spec/unit/defines/server/grant_spec.rb @@ -1,136 +1,155 @@ require 'spec_helper' describe 'postgresql::server::grant', :type => :define do let :facts do { :osfamily => 'Debian', :operatingsystem => 'Debian', :operatingsystemrelease => '6.0', :kernel => 'Linux', :concat_basedir => tmpfilename('contrib'), :id => 'root', :path => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin', } end let :title do 'test' end context 'plain' do let :params do { :db => 'test', :role => 'test', } end let :pre_condition do "class {'postgresql::server':}" end it { is_expected.to contain_postgresql__server__grant('test') } end context 'sequence' do let :params do { :db => 'test', :role => 'test', :privilege => 'usage', :object_type => 'sequence', } end let :pre_condition do "class {'postgresql::server':}" end it { is_expected.to contain_postgresql__server__grant('test') } it { is_expected.to contain_postgresql_psql('grant:test').with( - { - 'command' => "GRANT USAGE ON SEQUENCE \"test\" TO\n \"test\"", - 'unless' => "SELECT 1 WHERE has_sequence_privilege('test',\n 'test', 'USAGE')", - }) } + { + 'command' => /GRANT USAGE ON SEQUENCE "test" TO\s* "test"/m, + 'unless' => /SELECT 1 WHERE has_sequence_privilege\('test',\s* 'test', 'USAGE'\)/m, + } + ) } end context 'all sequences' do let :params do { :db => 'test', :role => 'test', :privilege => 'usage', :object_type => 'all sequences in schema', :object_name => 'public', } end let :pre_condition do "class {'postgresql::server':}" end it { is_expected.to contain_postgresql__server__grant('test') } it { is_expected.to contain_postgresql_psql('grant:test').with( - { - 'command' => "GRANT USAGE ON ALL SEQUENCES IN SCHEMA \"public\" TO\n \"test\"", - 'unless' => "SELECT 1 FROM (\n SELECT sequence_name\n FROM information_schema.sequences\n WHERE sequence_schema='public'\n EXCEPT DISTINCT\n SELECT object_name as sequence_name\n FROM information_schema.role_usage_grants\n WHERE object_type='SEQUENCE'\n AND grantee='test'\n AND object_schema='public'\n AND privilege_type='USAGE'\n ) P\n HAVING count(P.sequence_name) = 0", - }) } + { + 'command' => /GRANT USAGE ON ALL SEQUENCES IN SCHEMA "public" TO\s* "test"/m, + 'unless' => /SELECT 1 FROM \(\s*SELECT sequence_name\s* FROM information_schema\.sequences\s* WHERE sequence_schema='public'\s* EXCEPT DISTINCT\s* SELECT object_name as sequence_name\s* FROM .* WHERE .*grantee='test'\s* AND object_schema='public'\s* AND privilege_type='USAGE'\s*\) P\s* HAVING count\(P\.sequence_name\) = 0/m, + } + ) } end context "with specific db connection settings - default port" do let :params do { :db => 'test', :role => 'test', :connect_settings => { 'PGHOST' => 'postgres-db-server', 'DBVERSION' => '9.1', }, } end let :pre_condition do "class {'postgresql::server':}" end it { is_expected.to contain_postgresql__server__grant('test') } it { is_expected.to contain_postgresql_psql("grant:test").with_connect_settings( { 'PGHOST' => 'postgres-db-server','DBVERSION' => '9.1' } ).with_port( 5432 ) } end context "with specific db connection settings - including port" do let :params do { :db => 'test', :role => 'test', :connect_settings => { 'PGHOST' => 'postgres-db-server', 'DBVERSION' => '9.1', 'PGPORT' => '1234', }, } end let :pre_condition do "class {'postgresql::server':}" end it { is_expected.to contain_postgresql__server__grant('test') } it { is_expected.to contain_postgresql_psql("grant:test").with_connect_settings( { 'PGHOST' => 'postgres-db-server','DBVERSION' => '9.1','PGPORT' => '1234' } ) } end context "with specific db connection settings - port overriden by explicit parameter" do let :params do { :db => 'test', :role => 'test', :connect_settings => { 'PGHOST' => 'postgres-db-server', 'DBVERSION' => '9.1', 'PGPORT' => '1234', }, :port => '5678', } end let :pre_condition do "class {'postgresql::server':}" end it { is_expected.to contain_postgresql__server__grant('test') } it { is_expected.to contain_postgresql_psql("grant:test").with_connect_settings( { 'PGHOST' => 'postgres-db-server','DBVERSION' => '9.1','PGPORT' => '1234' } ).with_port( '5678' ) } end -end \ No newline at end of file + + context 'invalid objectype' do + let :params do + { + :db => 'test', + :role => 'test', + :privilege => 'usage', + :object_type => 'invalid', + } + end + + let :pre_condition do + "class {'postgresql::server':}" + end + + it { is_expected.to compile.and_raise_error(/"INVALID" does not match/) } + end +end diff --git a/spec/unit/defines/server/role_spec.rb b/spec/unit/defines/server/role_spec.rb index 88833a1..5c608cf 100644 --- a/spec/unit/defines/server/role_spec.rb +++ b/spec/unit/defines/server/role_spec.rb @@ -1,135 +1,135 @@ require 'spec_helper' describe 'postgresql::server::role', :type => :define do let :facts do { :osfamily => 'Debian', :operatingsystem => 'Debian', :operatingsystemrelease => '6.0', :kernel => 'Linux', :concat_basedir => tmpfilename('contrib'), :id => 'root', :path => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin', } end let :title do 'test' end let :params do { :password_hash => 'new-pa$s', } end let :pre_condition do "class {'postgresql::server':}" end it { is_expected.to contain_postgresql__server__role('test') } it 'should have create role for "test" user with password as ****' do is_expected.to contain_postgresql_psql('CREATE ROLE test ENCRYPTED PASSWORD ****').with({ 'command' => "CREATE ROLE \"test\" ENCRYPTED PASSWORD '$NEWPGPASSWD' LOGIN NOCREATEROLE NOCREATEDB NOSUPERUSER CONNECTION LIMIT -1", 'environment' => "NEWPGPASSWD=new-pa$s", - 'unless' => "SELECT rolname FROM pg_roles WHERE rolname='test'", + 'unless' => "SELECT 1 FROM pg_roles WHERE rolname = 'test'", 'port' => "5432", }) end it 'should have alter role for "test" user with password as ****' do is_expected.to contain_postgresql_psql('ALTER ROLE test ENCRYPTED PASSWORD ****').with({ 'command' => "ALTER ROLE \"test\" ENCRYPTED PASSWORD '$NEWPGPASSWD'", 'environment' => "NEWPGPASSWD=new-pa$s", - 'unless' => "SELECT usename FROM pg_shadow WHERE usename='test' and passwd='md5b6f7fcbbabb4befde4588a26c1cfd2fa'", + 'unless' => "SELECT 1 FROM pg_shadow WHERE usename = 'test' AND passwd = 'md5b6f7fcbbabb4befde4588a26c1cfd2fa'", 'port' => "5432", }) end context "with specific db connection settings - default port" do let :params do { :password_hash => 'new-pa$s', :connect_settings => { 'PGHOST' => 'postgres-db-server', 'DBVERSION' => '9.1', 'PGUSER' => 'login-user', 'PGPASSWORD' => 'login-pass' }, } end let :pre_condition do "class {'postgresql::server':}" end it { is_expected.to contain_postgresql__server__role('test') } it 'should have create role for "test" user with password as ****' do is_expected.to contain_postgresql_psql('CREATE ROLE test ENCRYPTED PASSWORD ****').with({ 'command' => "CREATE ROLE \"test\" ENCRYPTED PASSWORD '$NEWPGPASSWD' LOGIN NOCREATEROLE NOCREATEDB NOSUPERUSER CONNECTION LIMIT -1", 'environment' => "NEWPGPASSWD=new-pa$s", - 'unless' => "SELECT rolname FROM pg_roles WHERE rolname='test'", + 'unless' => "SELECT 1 FROM pg_roles WHERE rolname = 'test'", 'port' => "5432", 'connect_settings' => { 'PGHOST' => 'postgres-db-server', 'DBVERSION' => '9.1', 'PGUSER' => 'login-user', 'PGPASSWORD' => 'login-pass' }, }) end it 'should have alter role for "test" user with password as ****' do is_expected.to contain_postgresql_psql('ALTER ROLE test ENCRYPTED PASSWORD ****').with({ 'command' => "ALTER ROLE \"test\" ENCRYPTED PASSWORD '$NEWPGPASSWD'", 'environment' => "NEWPGPASSWD=new-pa$s", - 'unless' => "SELECT usename FROM pg_shadow WHERE usename='test' and passwd='md5b6f7fcbbabb4befde4588a26c1cfd2fa'", + 'unless' => "SELECT 1 FROM pg_shadow WHERE usename = 'test' AND passwd = 'md5b6f7fcbbabb4befde4588a26c1cfd2fa'", 'port' => "5432", 'connect_settings' => { 'PGHOST' => 'postgres-db-server', 'DBVERSION' => '9.1', 'PGUSER' => 'login-user', 'PGPASSWORD' => 'login-pass' }, }) end end context "with specific db connection settings - including port" do let :params do { :password_hash => 'new-pa$s', :connect_settings => { 'PGHOST' => 'postgres-db-server', 'DBVERSION' => '9.1', 'PGPORT' => '1234', 'PGUSER' => 'login-user', 'PGPASSWORD' => 'login-pass' }, } end let :pre_condition do "class {'postgresql::server':}" end it { is_expected.to contain_postgresql__server__role('test') } it 'should have create role for "test" user with password as ****' do is_expected.to contain_postgresql_psql('CREATE ROLE test ENCRYPTED PASSWORD ****').with({ 'command' => "CREATE ROLE \"test\" ENCRYPTED PASSWORD '$NEWPGPASSWD' LOGIN NOCREATEROLE NOCREATEDB NOSUPERUSER CONNECTION LIMIT -1", 'environment' => "NEWPGPASSWD=new-pa$s", - 'unless' => "SELECT rolname FROM pg_roles WHERE rolname='test'", + 'unless' => "SELECT 1 FROM pg_roles WHERE rolname = 'test'", 'connect_settings' => { 'PGHOST' => 'postgres-db-server', 'DBVERSION' => '9.1', 'PGPORT' => '1234', 'PGUSER' => 'login-user', 'PGPASSWORD' => 'login-pass' }, }) end it 'should have alter role for "test" user with password as ****' do is_expected.to contain_postgresql_psql('ALTER ROLE test ENCRYPTED PASSWORD ****').with({ 'command' => "ALTER ROLE \"test\" ENCRYPTED PASSWORD '$NEWPGPASSWD'", 'environment' => "NEWPGPASSWD=new-pa$s", - 'unless' => "SELECT usename FROM pg_shadow WHERE usename='test' and passwd='md5b6f7fcbbabb4befde4588a26c1cfd2fa'", + 'unless' => "SELECT 1 FROM pg_shadow WHERE usename = 'test' AND passwd = 'md5b6f7fcbbabb4befde4588a26c1cfd2fa'", 'connect_settings' => { 'PGHOST' => 'postgres-db-server', 'DBVERSION' => '9.1', 'PGPORT' => '1234', 'PGUSER' => 'login-user', 'PGPASSWORD' => 'login-pass' }, }) end end end diff --git a/spec/unit/defines/server/schema_spec.rb b/spec/unit/defines/server/schema_spec.rb index 4589f74..c8fa3d9 100644 --- a/spec/unit/defines/server/schema_spec.rb +++ b/spec/unit/defines/server/schema_spec.rb @@ -1,44 +1,43 @@ require 'spec_helper' describe 'postgresql::server::schema', :type => :define do let :facts do { :osfamily => 'Debian', :operatingsystem => 'Debian', :operatingsystemrelease => '6.0', :kernel => 'Linux', :concat_basedir => tmpfilename('schema'), :id => 'root', :path => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin', } end let :title do 'test' end let :params do { :owner => 'jane', :db => 'janedb', } end let :pre_condition do "class {'postgresql::server':}" end it { should contain_postgresql__server__schema('test') } - context "with change_ownership set to true" do + context "with different owner" do let :params do { - :owner => 'nate', - :db => 'natedb', - :change_ownership => true, + :owner => 'nate', + :db => 'natedb', } end - it { is_expected.to contain_postgresql_psql("Change owner of schema 'test' to nate") } + it { is_expected.to contain_postgresql_psql('natedb: ALTER SCHEMA "test" OWNER TO "nate"') } end end diff --git a/spec/unit/defines/server/tablespace_spec.rb b/spec/unit/defines/server/tablespace_spec.rb index 560a50e..50a93e2 100644 --- a/spec/unit/defines/server/tablespace_spec.rb +++ b/spec/unit/defines/server/tablespace_spec.rb @@ -1,31 +1,42 @@ require 'spec_helper' describe 'postgresql::server::tablespace', :type => :define do let :facts do { :osfamily => 'Debian', :operatingsystem => 'Debian', :operatingsystemrelease => '6.0', :kernel => 'Linux', :concat_basedir => tmpfilename('tablespace'), :id => 'root', :path => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin', } end let :title do 'test' end let :params do { :location => '/srv/data/foo', } end let :pre_condition do "class {'postgresql::server':}" end it { is_expected.to contain_postgresql__server__tablespace('test') } + + context "with different owner" do + let :params do + { + :location => '/srv/data/foo', + :owner => 'test_owner', + } + end + + it { is_expected.to contain_postgresql_psql('ALTER TABLESPACE "test" OWNER TO "test_owner"') } + end end diff --git a/templates/systemd-override.erb b/templates/systemd-override.erb index eb4f787..5a2a31c 100644 --- a/templates/systemd-override.erb +++ b/templates/systemd-override.erb @@ -1,8 +1,14 @@ -<%- if scope.lookupvar('::operatingsystem') == 'Fedora' -%> +<%- if scope.lookupvar('::osfamily') == 'Gentoo' -%> +.include /usr/lib64/systemd/system/<%= @service_name %>.service +<%- elsif scope.lookupvar('::operatingsystem') == 'Fedora' -%> .include /lib/systemd/system/<%= @service_name %>.service <% else -%> .include /usr/lib/systemd/system/<%= @service_name %>.service <% end -%> [Service] Environment=PGPORT=<%= @port %> +<%- if scope.lookupvar('::osfamily') == 'Gentoo' -%> +Environment=DATA_DIR=<%= @datadir %> +<%- else -%> Environment=PGDATA=<%= @datadir %> +<%- end -%>