diff --git a/manifests/client.pp b/manifests/client.pp index b805749..7e6da1c 100644 --- a/manifests/client.pp +++ b/manifests/client.pp @@ -1,27 +1,25 @@ # 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' + Enum['file', 'absent'] $file_ensure = 'file', + Stdlib::Absolutepath $validcon_script_path = $postgresql::params::validcon_script_path, + String[1] $package_name = $postgresql::params::client_package_name, + String[1] $package_ensure = 'present' ) inherits postgresql::params { - validate_absolute_path($validcon_script_path) - validate_string($package_name) 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/lib/devel.pp b/manifests/lib/devel.pp index bbc5272..e6ff183 100644 --- a/manifests/lib/devel.pp +++ b/manifests/lib/devel.pp @@ -1,30 +1,28 @@ # 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 + String $package_name = $postgresql::params::devel_package_name, + String[1] $package_ensure = 'present', + Boolean $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/lib/docs.pp b/manifests/lib/docs.pp index 55825d1..f3c31ff 100644 --- a/manifests/lib/docs.pp +++ b/manifests/lib/docs.pp @@ -1,16 +1,14 @@ # This class installs the postgresql-docs See README.md for more # details. class postgresql::lib::docs ( - $package_name = $postgresql::params::docs_package_name, - $package_ensure = 'present', + String $package_name = $postgresql::params::docs_package_name, + String[1] $package_ensure = 'present', ) inherits postgresql::params { - validate_string($package_name) - package { 'postgresql-docs': ensure => $package_ensure, name => $package_name, tag => 'postgresql', } } diff --git a/manifests/lib/java.pp b/manifests/lib/java.pp index 0a2d45f..dc131d5 100644 --- a/manifests/lib/java.pp +++ b/manifests/lib/java.pp @@ -1,16 +1,14 @@ # This class installs the postgresql jdbc connector. See README.md for more # details. class postgresql::lib::java ( - $package_name = $postgresql::params::java_package_name, - $package_ensure = 'present' + String $package_name = $postgresql::params::java_package_name, + String[1] $package_ensure = 'present' ) inherits postgresql::params { - validate_string($package_name) - package { 'postgresql-jdbc': ensure => $package_ensure, name => $package_name, tag => 'postgresql', } } diff --git a/manifests/lib/perl.pp b/manifests/lib/perl.pp index 6ed2853..67fd4a2 100644 --- a/manifests/lib/perl.pp +++ b/manifests/lib/perl.pp @@ -1,13 +1,13 @@ # This class installs the perl libs for postgresql. See README.md for more # details. class postgresql::lib::perl( - $package_name = $postgresql::params::perl_package_name, - $package_ensure = 'present' + String $package_name = $postgresql::params::perl_package_name, + String[1] $package_ensure = 'present' ) inherits postgresql::params { package { 'perl-DBD-Pg': ensure => $package_ensure, name => $package_name, } } diff --git a/manifests/lib/python.pp b/manifests/lib/python.pp index bfe0585..590727d 100644 --- a/manifests/lib/python.pp +++ b/manifests/lib/python.pp @@ -1,13 +1,13 @@ # This class installs the python libs for postgresql. See README.md for more # details. class postgresql::lib::python( - $package_name = $postgresql::params::python_package_name, - $package_ensure = 'present' + String[1] $package_name = $postgresql::params::python_package_name, + String[1] $package_ensure = 'present' ) inherits postgresql::params { package { 'python-psycopg2': ensure => $package_ensure, name => $package_name, } } diff --git a/manifests/server/config.pp b/manifests/server/config.pp index 0272bc6..616fc34 100644 --- a/manifests/server/config.pp +++ b/manifests/server/config.pp @@ -1,218 +1,221 @@ # 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, + order => 'numeric', 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', + order => 1, } postgresql::server::pg_hba_rule { 'local access to database with same name': type => 'local', auth_method => 'ident', auth_option => $local_auth_option, - order => '002', + order => 2, } 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', + order => 3, } 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', + order => 4, } postgresql::server::pg_hba_rule { 'allow access to all users': type => 'host', address => $ip_mask_allow_all_users, auth_method => 'md5', - order => '100', + order => 100, } postgresql::server::pg_hba_rule { 'allow access to ipv6 localhost': type => 'host', address => '::1/128', auth_method => 'md5', - order => '101', + 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) } if $listen_addresses { 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, mode => '0640', warn => true, + order => 'numeric', notify => Class['postgresql::server::reload'], } } if ($manage_recovery_conf == true) { concat { $recovery_conf_path: owner => $user, group => $group, mode => '0640', warn => true, + order => 'numeric', 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/contrib.pp b/manifests/server/contrib.pp index a896ffd..7e3426b 100644 --- a/manifests/server/contrib.pp +++ b/manifests/server/contrib.pp @@ -1,23 +1,22 @@ # 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' + String $package_name = $postgresql::params::contrib_package_name, + String[1] $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/extension.pp b/manifests/server/extension.pp index 1c9b684..6d28783 100644 --- a/manifests/server/extension.pp +++ b/manifests/server/extension.pp @@ -1,61 +1,61 @@ # Activate an extension on a postgresql database define postgresql::server::extension ( $database, - $extension = $name, - $ensure = 'present', - $package_name = undef, - $package_ensure = undef, + $extension = $name, + String[1] $ensure = 'present', + $package_name = undef, + $package_ensure = undef, $connect_settings = $postgresql::server::default_connect_settings, ) { - $user = $postgresql::server::user - $group = $postgresql::server::group - $psql_path = $postgresql::server::psql_path + $user = $postgresql::server::user + $group = $postgresql::server::group + $psql_path = $postgresql::server::psql_path case $ensure { 'present': { $command = "CREATE EXTENSION \"${extension}\"" $unless_comp = '=' $package_require = [] $package_before = Postgresql_psql["Add ${extension} extension to ${database}"] } 'absent': { $command = "DROP EXTENSION \"${extension}\"" $unless_comp = '!=' $package_require = Postgresql_psql["Add ${extension} extension to ${database}"] $package_before = [] } default: { fail("Unknown value for ensure '${ensure}'.") } } postgresql_psql {"Add ${extension} extension to ${database}": psql_user => $user, psql_group => $group, psql_path => $psql_path, connect_settings => $connect_settings, db => $database, command => $command, unless => "SELECT t.count FROM (SELECT count(extname) FROM pg_extension WHERE extname = '${extension}') as t WHERE t.count ${unless_comp} 1", require => Postgresql::Server::Database[$database], } if $package_name { $_package_ensure = $package_ensure ? { undef => $ensure, default => $package_ensure, } ensure_packages($package_name, { ensure => $_package_ensure, tag => 'postgresql', require => $package_require, before => $package_before, }) } } diff --git a/manifests/server/grant.pp b/manifests/server/grant.pp index 2836f17..f030019 100644 --- a/manifests/server/grant.pp +++ b/manifests/server/grant.pp @@ -1,294 +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, + String $role, + String $db, + Optional[String] $privilege = undef, + String $object_type = 'database', + Optional[String[1]] $object_name = undef, + String $psql_db = $postgresql::server::default_database, + String $psql_user = $postgresql::server::user, + Integer $port = $postgresql::server::port, + Boolean $onlyif_exists = false, + Hash $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_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_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_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_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_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 ( 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_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_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}'", '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 04729d4..601fd69 100644 --- a/manifests/server/grant_role.pp +++ b/manifests/server/grant_role.pp @@ -1,51 +1,43 @@ # Define for granting membership to a role. See README.md for more information define postgresql::server::grant_role ( - $group, - $role = $name, - $ensure = 'present', - $psql_db = $postgresql::server::default_database, - $psql_user = $postgresql::server::user, - $port = $postgresql::server::port, - $connect_settings = $postgresql::server::default_connect_settings, + String[1] $group, + String[1] $role = $name, + Enum['present', 'absent'] $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 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/pg_hba_rule.pp b/manifests/server/pg_hba_rule.pp index 0eecdc5..97a7aaa 100644 --- a/manifests/server/pg_hba_rule.pp +++ b/manifests/server/pg_hba_rule.pp @@ -1,64 +1,60 @@ # 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', + Enum['local', 'host', 'hostssl', 'hostnossl'] $type, + String $database, + String $user, + String $auth_method, + Optional[String] $address = undef, + String $description = 'none', + Optional[String] $auth_option = undef, + Integer $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 + Stdlib::Absolutepath $target = $postgresql::server::pg_hba_conf_path, + String $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, 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', '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, ', ')],'')) + assert_type(Enum[$allowed_auth_methods], $auth_method) # 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/postgis.pp b/manifests/server/postgis.pp index a43e4c1..a4e4321 100644 --- a/manifests/server/postgis.pp +++ b/manifests/server/postgis.pp @@ -1,24 +1,23 @@ # Install the postgis postgresql packaging. See README.md for more details. class postgresql::server::postgis ( - $package_name = $postgresql::params::postgis_package_name, - $package_ensure = 'present' + String $package_name = $postgresql::params::postgis_package_name, + String[1] $package_ensure = 'present' ) inherits postgresql::params { - validate_string($package_name) package { 'postgresql-postgis': ensure => $package_ensure, name => $package_name, tag => 'postgresql', } anchor { 'postgresql::server::postgis::start': } -> Class['postgresql::server::install'] -> Package['postgresql-postgis'] -> Class['postgresql::server::service'] -> anchor { 'postgresql::server::postgis::end': } if $postgresql::globals::manage_package_repo { Class['postgresql::repo'] -> Package['postgresql-postgis'] } } diff --git a/metadata.json b/metadata.json index 756bfa2..b062f61 100644 --- a/metadata.json +++ b/metadata.json @@ -1,73 +1,73 @@ { "name": "puppetlabs-postgresql", "version": "4.9.0", "author": "Inkling/Puppet Labs", "summary": "Offers support for basic management of PostgreSQL databases.", "license": "Apache-2.0", "source": "git://github.com/puppetlabs/puppetlabs-postgresql.git", "project_page": "https://github.com/puppetlabs/puppetlabs-postgresql", "issues_url": "https://tickets.puppetlabs.com/browse/MODULES", "dependencies": [ - {"name":"puppetlabs/stdlib","version_requirement":"4.x"}, + {"name":"puppetlabs/stdlib","version_requirement":">= 4.13.1 < 5.0.0"}, {"name":"puppetlabs/apt","version_requirement":">= 2.0.0 < 5.0.0"}, {"name":"puppetlabs/concat","version_requirement":">= 1.1.0 < 5.0.0"} ], "data_provider": null, "operatingsystem_support": [ { "operatingsystem": "RedHat", "operatingsystemrelease": [ "5", "6", "7" ] }, { "operatingsystem": "CentOS", "operatingsystemrelease": [ "5", "6", "7" ] }, { "operatingsystem": "OracleLinux", "operatingsystemrelease": [ "5", "6", "7" ] }, { "operatingsystem": "Scientific", "operatingsystemrelease": [ "5", "6", "7" ] }, { "operatingsystem": "Debian", "operatingsystemrelease": [ "6", "7", "8" ] }, { "operatingsystem": "Ubuntu", "operatingsystemrelease": [ "10.04", "12.04", "14.04", "16.04" ] } ], "requirements": [ { "name": "puppet", "version_requirement": ">= 4.7.0 < 5.0.0" } ] } diff --git a/spec/unit/defines/server/grant_role_spec.rb b/spec/unit/defines/server/grant_role_spec.rb index d93b1e4..12a41e2 100644 --- a/spec/unit/defines/server/grant_role_spec.rb +++ b/spec/unit/defines/server/grant_role_spec.rb @@ -1,161 +1,105 @@ 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 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 => '', - } } - - 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 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 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 fe79636..79d569d 100644 --- a/spec/unit/defines/server/grant_spec.rb +++ b/spec/unit/defines/server/grant_spec.rb @@ -1,155 +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\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\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', + :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 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/pg_hba_rule_spec.rb b/spec/unit/defines/server/pg_hba_rule_spec.rb index f36d27d..f657589 100644 --- a/spec/unit/defines/server/pg_hba_rule_spec.rb +++ b/spec/unit/defines/server/pg_hba_rule_spec.rb @@ -1,198 +1,126 @@ require 'spec_helper' describe 'postgresql::server::pg_hba_rule', :type => :define do let :facts do { :osfamily => 'Debian', :operatingsystem => 'Debian', :operatingsystemrelease => '6.0', :kernel => 'Linux', :concat_basedir => tmpfilename('pg_hba'), :id => 'root', :path => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin', } end let :title do 'test' end let :target do tmpfilename('pg_hba_rule') end context 'test template 1' do let :pre_condition do <<-EOS class { 'postgresql::server': } EOS end let :params do { :type => 'host', :database => 'all', :user => 'all', :address => '1.1.1.1/24', :auth_method => 'md5', :target => target, } end it do is_expected.to contain_concat__fragment('pg_hba_rule_test').with({ :content => /host\s+all\s+all\s+1\.1\.1\.1\/24\s+md5/ }) end end context 'test template 2' do let :pre_condition do <<-EOS class { 'postgresql::server': } EOS end let :params do { :type => 'local', :database => 'all', :user => 'all', :auth_method => 'ident', :target => target, } end it do is_expected.to contain_concat__fragment('pg_hba_rule_test').with({ :content => /local\s+all\s+all\s+ident/ }) end end context 'test template 3' do let :pre_condition do <<-EOS class { 'postgresql::server': } EOS end let :params do { :type => 'host', :database => 'all', :user => 'all', :address => '0.0.0.0/0', :auth_method => 'ldap', :auth_option => 'foo=bar', :target => target, } end it do is_expected.to contain_concat__fragment('pg_hba_rule_test').with({ :content => /host\s+all\s+all\s+0\.0\.0\.0\/0\s+ldap\s+foo=bar/ }) end end context 'validation' do - context 'validate type test 1' do - let :pre_condition do - <<-EOS - class { 'postgresql::server': } - EOS - end - - let :params do - { - :type => 'invalid', - :database => 'all', - :user => 'all', - :address => '0.0.0.0/0', - :auth_method => 'ldap', - :target => target, - } - end - it 'should fail parsing when type is not valid' do - expect { catalogue }.to raise_error(Puppet::Error, - /The type you specified \[invalid\] must be one of/) - end - end - - context 'validate auth_method' do - let :pre_condition do - <<-EOS - class { 'postgresql::server': } - EOS - end - - let :params do - { - :type => 'local', - :database => 'all', - :user => 'all', - :address => '0.0.0.0/0', - :auth_method => 'invalid', - :target => target, - } - end - - it 'should fail parsing when auth_method is not valid' do - expect { catalogue }.to raise_error(Puppet::Error, - /The auth_method you specified \[invalid\] must be one of/) - end - end - - context 'validate unsupported auth_method' do - let :pre_condition do - <<-EOS - class { 'postgresql::globals': - version => '9.0', - } - class { 'postgresql::server': } - EOS - end - - let :params do - { - :type => 'local', - :database => 'all', - :user => 'all', - :address => '0.0.0.0/0', - :auth_method => 'peer', - :target => target, - } - end - - it 'should fail parsing when auth_method is not valid' do - expect { catalogue }.to raise_error(Puppet::Error, - /The auth_method you specified \[peer\] must be one of: trust, reject, md5, password, gss, sspi, krb5, ident, ldap, radius, cert, pam/) - end - end - context 'validate supported auth_method' do let :pre_condition do <<-EOS class { 'postgresql::globals': version => '9.2', } class { 'postgresql::server': } EOS end let :params do { :type => 'local', :database => 'all', :user => 'all', :address => '0.0.0.0/0', :auth_method => 'peer', :target => target, } end it do - is_expected.to contain_concat__fragment('pg_hba_rule_test').with({ - :content => /local\s+all\s+all\s+0\.0\.0\.0\/0\s+peer/ - }) + is_expected.to contain_concat__fragment('pg_hba_rule_test').with( + { + :content => /local\s+all\s+all\s+0\.0\.0\.0\/0\s+peer/ + } + ) end end end end