diff --git a/lib/puppet/type/postgresql_psql.rb b/lib/puppet/type/postgresql_psql.rb index 1e7b2c4..a96ea78 100644 --- a/lib/puppet/type/postgresql_psql.rb +++ b/lib/puppet/type/postgresql_psql.rb @@ -1,135 +1,137 @@ Puppet::Type.newtype(:postgresql_psql) do newparam(:name) do desc 'An arbitrary tag for your own reference; the name of the message.' isnamevar end newproperty(:command) do desc 'The SQL command to execute via psql.' defaultto { @resource[:name] } # If needing to run the SQL command, return a fake value that will trigger # a sync, else return the expected SQL command so no sync takes place def retrieve if @resource.should_run_sql :notrun else should end end def sync output, status = provider.run_sql_command(value) raise("Error executing SQL; psql returned #{status}: '#{output}'") unless status == 0 # rubocop:disable Style/NumericPredicate end end newparam(:unless) do desc '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.' # Return true if a matching row is found def matches(value) output, status = provider.run_unless_sql_command(value) # rubocop:disable Style/NumericPredicate fail("Error evaluating 'unless' clause, returned #{status}: '#{output}'") unless status == 0 # rubocop:disable Style/SignalException # rubocop:enable Style/NumericPredicate result_count = output.strip.to_i debug("Found #{result_count} row(s) executing 'unless' clause") result_count > 0 end end newparam(:onlyif) do desc '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.' # Return true if a matching row is found def matches(value) output, status = provider.run_unless_sql_command(value) status = output.exitcode if status.nil? raise("Error evaluating 'onlyif' clause, returned #{status}: '#{output}'") unless status == 0 # rubocop:disable Style/NumericPredicate result_count = output.strip.to_i debug("Found #{result_count} row(s) executing 'onlyif' clause") result_count > 0 end end newparam(:connect_settings) do desc 'Connection settings that will be used when connecting to postgres' end newparam(:db) do desc 'The name of the database to execute the SQL command against, this overrides any PGDATABASE value in connect_settings' end newparam(:port) do desc 'The port of the database server to execute the SQL command against, this overrides any PGPORT value in connect_settings.' end newparam(:search_path) do desc 'The schema search path to use when executing the SQL command' end newparam(:psql_path) do desc 'The path to psql executable.' defaultto('psql') end newparam(:psql_user) do desc 'The system user account under which the psql command should be executed.' defaultto('postgres') end newparam(:psql_group) do desc 'The system user group account under which the psql command should be executed.' defaultto('postgres') end newparam(:cwd, parent: Puppet::Parameter::Path) do desc 'The working directory under which the psql command should be executed.' defaultto('/tmp') end newparam(:environment) do desc "Any additional environment variables you want to set for a SQL command. Multiple environment variables should be specified as an array." validate do |values| Array(values).each do |value| unless value =~ %r{\w+=} raise ArgumentError, "Invalid environment setting '#{value}'" end end end end newparam(:refreshonly, boolean: true) do desc "If 'true', then the SQL will only be executed via a notify/subscribe event." defaultto(:false) newvalues(:true, :false) end + autorequire(:class) { ['Postgresql::Server::Service'] } + def should_run_sql(refreshing = false) onlyif_param = @parameters[:onlyif] unless_param = @parameters[:unless] return false if !onlyif_param.nil? && !onlyif_param.value.nil? && !onlyif_param.matches(onlyif_param.value) return false if !unless_param.nil? && !unless_param.value.nil? && unless_param.matches(unless_param.value) return false if !refreshing && @parameters[:refreshonly].value == :true true end def refresh property(:command).sync if should_run_sql(true) end end diff --git a/manifests/server.pp b/manifests/server.pp index 7509ec9..2f2fe15 100644 --- a/manifests/server.pp +++ b/manifests/server.pp @@ -1,84 +1,111 @@ # This installs a PostgreSQL server. See README.md for more details. class postgresql::server ( $postgres_password = undef, $package_name = $postgresql::params::server_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, $data_checksums = $postgresql::params::data_checksums, $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, + + Hash[String, Hash] $roles = {}, + Hash[String, Any] $config_entries = {}, + Hash[String, Hash] $pg_hba_rules = {}, + #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": } + contain postgresql::server::install + contain postgresql::server::initdb + contain postgresql::server::config + contain postgresql::server::service + contain postgresql::server::passwd + + Class['postgresql::server::install'] + -> Class['postgresql::server::initdb'] + -> Class['postgresql::server::config'] + -> Class['postgresql::server::service'] + -> Class['postgresql::server::passwd'] + + $roles.each |$rolename, $role| { + postgresql::server::role { $rolename: + * => $role, + } + } + + $config_entries.each |$entry, $value| { + postgresql::server::config_entry { $entry: + value => $value, + } + } + + $pg_hba_rules.each |$rule_name, $rule| { + postgresql::server::pg_hba_rule { $rule_name: + * => $rule, + } + } } diff --git a/manifests/server/grant.pp b/manifests/server/grant.pp index 4817326..22e1040 100644 --- a/manifests/server/grant.pp +++ b/manifests/server/grant.pp @@ -1,426 +1,425 @@ # Define for granting permissions to roles. See README.md for more details. define postgresql::server::grant ( String $role, String $db, Optional[String] $privilege = undef, Pattern[#/(?i:^COLUMN$)/, /(?i:^ALL SEQUENCES IN SCHEMA$)/, /(?i:^ALL TABLES IN SCHEMA$)/, /(?i:^DATABASE$)/, #/(?i:^FOREIGN DATA WRAPPER$)/, #/(?i:^FOREIGN SERVER$)/, #/(?i:^FUNCTION$)/, /(?i:^LANGUAGE$)/, #/(?i:^PROCEDURAL LANGUAGE$)/, /(?i:^TABLE$)/, #/(?i:^TABLESPACE$)/, /(?i:^SCHEMA$)/, /(?i:^SEQUENCE$)/ #/(?i:^VIEW$)/ ] $object_type = 'database', Optional[Variant[ Array[String,2,2], 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, Enum['present', 'absent' ] $ensure = 'present', ) { case $ensure { default: { # default is 'present' $sql_command = 'GRANT %s ON %s "%s" TO "%s"' $unless_is = true } 'absent': { $sql_command = 'REVOKE %s ON %s "%s" FROM "%s"' $unless_is = false } } $group = $postgresql::server::group $psql_path = $postgresql::server::psql_path if ! $object_name { $_object_name = $db } else { $_object_name = $object_name } # # 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) # 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', Pattern[ /^$/, /^CONNECT$/, /^CREATE$/, /^TEMP$/, /^TEMPORARY$/ ] => $_privilege, default => fail('Illegal value for $privilege parameter'), } $unless_function = 'has_database_privilege' $on_db = $psql_db $onlyif_function = $ensure ? { default => undef, 'absent' => 'role_exists', } } 'SCHEMA': { $unless_privilege = $_privilege ? { 'ALL' => 'CREATE', 'ALL PRIVILEGES' => 'CREATE', Pattern[ /^$/, /^CREATE$/, /^USAGE$/ ] => $_privilege, default => fail('Illegal value for $privilege parameter'), } $unless_function = 'has_schema_privilege' $on_db = $db $onlyif_function = undef } 'SEQUENCE': { $unless_privilege = $_privilege ? { 'ALL' => 'USAGE', Pattern[ /^$/, /^ALL PRIVILEGES$/, /^SELECT$/, /^UPDATE$/, /^USAGE$/ ] => $_privilege, default => fail('Illegal value for $privilege parameter'), } $unless_function = 'has_sequence_privilege' $on_db = $db $onlyif_function = undef } 'ALL SEQUENCES IN SCHEMA': { case $_privilege { Pattern[ /^$/, /^ALL$/, /^ALL PRIVILEGES$/, /^SELECT$/, /^UPDATE$/, /^USAGE$/ ]: { } default: { fail('Illegal value for $privilege parameter') } } $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. if $ensure == 'present' { $custom_unless = "SELECT 1 WHERE NOT EXISTS ( 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}' )" } else { # ensure == absent $custom_unless = "SELECT 1 WHERE NOT EXISTS ( 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}' )" } } 'TABLE': { $unless_privilege = $_privilege ? { 'ALL' => 'INSERT', Pattern[ /^$/, /^ALL$/, /^ALL PRIVILEGES$/, /^DELETE$/, /^REFERENCES$/, /^SELECT$/, /^TRIGGER$/, /^TRUNCATE$/, /^UPDATE$/ ] => $_privilege, default => fail('Illegal value for $privilege parameter'), } $unless_function = 'has_table_privilege' $on_db = $db $onlyif_function = $onlyif_exists ? { true => 'table_exists', default => undef, } } 'ALL TABLES IN SCHEMA': { case $_privilege { Pattern[ /^$/, /^ALL$/, /^ALL PRIVILEGES$/, /^DELETE$/, /^INSERT$/, /^REFERENCES$/, /^SELECT$/, /^TRIGGER$/, /^TRUNCATE$/, /^UPDATE$/ ]: { } default: { fail('Illegal value for $privilege parameter') } } $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. # There are currently 7 possible priviliges: # ('SELECT','UPDATE','INSERT','DELETE','TRIGGER','REFERENCES','TRUNCATE') # This list is consistant from Postgresql 8.0 # # There are 4 cases to cover, each with it's own distinct unless clause: # grant ALL # grant SELECT (or INSERT or DELETE ...) # revoke ALL # revoke SELECT (or INSERT or DELETE ...) if $ensure == 'present' { if $_privilege == 'ALL' or $_privilege == 'ALL PRIVILEGES' { # GRANT ALL $custom_unless = "SELECT 1 WHERE NOT EXISTS ( SELECT 1 FROM pg_catalog.pg_tables AS t, (VALUES ('SELECT'), ('UPDATE'), ('INSERT'), ('DELETE'), ('TRIGGER'), ('REFERENCES'), ('TRUNCATE')) AS p(privilege_type) WHERE t.schemaname = '${schema}' AND NOT EXISTS ( SELECT 1 FROM information_schema.role_table_grants AS g WHERE g.grantee = '${role}' AND g.table_schema = '${schema}' AND g.privilege_type = p.privilege_type ) )" } else { # GRANT $_privilege $custom_unless = "SELECT 1 WHERE NOT EXISTS ( SELECT 1 FROM pg_catalog.pg_tables AS t WHERE t.schemaname = '${schema}' AND NOT EXISTS ( SELECT 1 FROM information_schema.role_table_grants AS g WHERE g.grantee = '${role}' AND g.table_schema = '${schema}' AND g.privilege_type = '${_privilege}' ) )" } } else { if $_privilege == 'ALL' or $_privilege == 'ALL PRIVILEGES' { # REVOKE ALL $custom_unless = "SELECT 1 WHERE NOT EXISTS ( SELECT table_name FROM information_schema.role_table_grants WHERE grantee = '${role}' AND table_schema ='${schema}' )" } else { # REVOKE $_privilege $custom_unless = "SELECT 1 WHERE NOT EXISTS ( SELECT table_name FROM information_schema.role_table_grants WHERE grantee = '${role}' AND table_schema ='${schema}' AND privilege_type = '${_privilege}' )" } } } 'LANGUAGE': { $unless_privilege = $_privilege ? { 'ALL' => 'USAGE', 'ALL PRIVILEGES' => 'USAGE', Pattern[ /^$/, /^CREATE$/, /^USAGE$/ ] => $_privilege, default => fail('Illegal value for $privilege parameter'), } $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], # } case $_object_name { Array: { $_togrant_object = join($_object_name, '"."') # Never put double quotes into has_*_privilege function $_granted_object = join($_object_name, '.') } default: { $_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}') = ${unless_is}", } $_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}'", 'role_exists' => "SELECT 1 FROM pg_roles WHERE rolname = '${role}'", default => undef, } $grant_cmd = sprintf($sql_command, $_privilege, $_object_type, $_togrant_object, $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/reassign_owned_by.pp b/manifests/server/reassign_owned_by.pp index 812c7e2..d4d6f5b 100644 --- a/manifests/server/reassign_owned_by.pp +++ b/manifests/server/reassign_owned_by.pp @@ -1,61 +1,60 @@ # Define for reassigning the ownership of objects within a database. See README.md for more details. # This enables us to force the a particular ownership for objects within a database define postgresql::server::reassign_owned_by ( String $old_role, String $new_role, String $db, String $psql_user = $postgresql::server::user, Integer $port = $postgresql::server::port, Hash $connect_settings = $postgresql::server::default_connect_settings, ) { $sql_command = "REASSIGN OWNED BY \"${old_role}\" TO \"${new_role}\"" $group = $postgresql::server::group $psql_path = $postgresql::server::psql_path # # 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 } $onlyif = "SELECT tablename FROM pg_catalog.pg_tables WHERE schemaname NOT IN ('pg_catalog', 'information_schema') AND tableowner = '${old_role}' UNION ALL SELECT proname FROM pg_catalog.pg_proc WHERE pg_get_userbyid(proowner) = '${old_role}' UNION ALL SELECT viewname FROM pg_catalog.pg_views WHERE pg_views.schemaname NOT IN ('pg_catalog', 'information_schema') AND viewowner = '${old_role}' UNION ALL SELECT relname FROM pg_catalog.pg_class WHERE relkind='S' AND pg_get_userbyid(relowner) = '${old_role}'" postgresql_psql { "reassign_owned_by:${db}:${sql_command}": command => $sql_command, db => $db, port => $port_override, connect_settings => $connect_settings, psql_user => $psql_user, psql_group => $group, psql_path => $psql_path, onlyif => $onlyif, - require => Class['postgresql::server'] } if($old_role != undef and defined(Postgresql::Server::Role[$old_role])) { Postgresql::Server::Role[$old_role]->Postgresql_psql["reassign_owned_by:${db}:${sql_command}"] } if($new_role != undef and defined(Postgresql::Server::Role[$new_role])) { Postgresql::Server::Role[$new_role]->Postgresql_psql["reassign_owned_by:${db}:${sql_command}"] } if($db != undef and defined(Postgresql::Server::Database[$db])) { Postgresql::Server::Database[$db]->Postgresql_psql["reassign_owned_by:${db}:${sql_command}"] } } diff --git a/manifests/server/role.pp b/manifests/server/role.pp index daef482..c8db8b3 100644 --- a/manifests/server/role.pp +++ b/manifests/server/role.pp @@ -1,134 +1,131 @@ # Define for creating a database role. See README.md for more information define postgresql::server::role( $update_password = true, $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, Enum['present', 'absent'] $ensure = 'present', ) { $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 } 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'], - ], + require => Postgresql_psql["CREATE ROLE ${username} ENCRYPTED PASSWORD ****"], } if $ensure == 'present' { $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 { "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 1 FROM pg_roles WHERE rolname = '${username}'", environment => $environment, - require => Class['Postgresql::Server'], + require => undef, } postgresql_psql {"ALTER ROLE \"${username}\" ${superuser_sql}": unless => "SELECT 1 FROM pg_roles WHERE rolname = '${username}' AND rolsuper = ${superuser}", } postgresql_psql {"ALTER ROLE \"${username}\" ${createdb_sql}": unless => "SELECT 1 FROM pg_roles WHERE rolname = '${username}' AND rolcreatedb = ${createdb}", } postgresql_psql {"ALTER ROLE \"${username}\" ${createrole_sql}": unless => "SELECT 1 FROM pg_roles WHERE rolname = '${username}' AND rolcreaterole = ${createrole}", } postgresql_psql {"ALTER ROLE \"${username}\" ${login_sql}": unless => "SELECT 1 FROM pg_roles WHERE rolname = '${username}' AND rolcanlogin = ${login}", } postgresql_psql {"ALTER ROLE \"${username}\" ${inherit_sql}": 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 1 FROM pg_roles WHERE rolname = '${username}' AND rolreplication = ${replication}", } } else { postgresql_psql {"ALTER ROLE \"${username}\" ${replication_sql}": unless => "SELECT 1 FROM pg_roles WHERE rolname = '${username}' AND rolreplication = ${replication}", } } } postgresql_psql {"ALTER ROLE \"${username}\" CONNECTION LIMIT ${connection_limit}": unless => "SELECT 1 FROM pg_roles WHERE rolname = '${username}' AND rolconnlimit = ${connection_limit}", } if $password_hash and $update_password { 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 1 FROM pg_shadow WHERE usename = '${username}' AND passwd = '${pwd_hash_sql}'", environment => $environment, } } } else { # ensure == absent postgresql_psql { "DROP ROLE \"${username}\"": onlyif => "SELECT 1 FROM pg_roles WHERE rolname = '${username}'", - require => Class['Postgresql::Server'], + require => undef, } } } diff --git a/manifests/server/tablespace.pp b/manifests/server/tablespace.pp index cf0b65d..35dd8b7 100644 --- a/manifests/server/tablespace.pp +++ b/manifests/server/tablespace.pp @@ -1,56 +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, } file { $location: ensure => directory, owner => $user, group => $group, mode => '0700', seluser => 'system_u', selrole => 'object_r', seltype => 'postgresql_db_t', require => Class['postgresql::server'], } 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]], + require => File[$location], } 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/overridden_settings_spec.rb b/spec/acceptance/overridden_settings_spec.rb new file mode 100644 index 0000000..b956bf1 --- /dev/null +++ b/spec/acceptance/overridden_settings_spec.rb @@ -0,0 +1,53 @@ +require 'spec_helper_acceptance' + +# These tests are designed to ensure that the module, when ran overrides, +# sets up everything correctly and allows us to connect to Postgres. +describe 'postgresql::server', unless: UNSUPPORTED_PLATFORMS.include?(fact('osfamily')) do + pp = <<-MANIFEST + class { 'postgresql::server': + roles => { + 'testusername' => { + password_hash => postgresql_password('testusername', 'supersecret'), + createdb => true, + }, + }, + config_entries => { + max_connections => 200, + }, + pg_hba_rules => { + 'from_remote_host' => { + type => 'host', + database => 'mydb', + user => 'myuser', + auth_method => 'md5', + address => '192.0.2.100/32', + }, + }, + } + + postgresql::server::database { 'testusername': + owner => 'testusername', + } + MANIFEST + + it 'with additional hiera entries' do + apply_manifest(pp, catch_failures: true) + apply_manifest(pp, catch_changes: true) + end + + describe port(5432) do + it { is_expected.to be_listening } + end + + it 'can connect with psql' do + psql('--command="\l" postgres', 'postgres') do |r| + expect(r.stdout).to match(%r{List of databases}) + end + end + + it 'can connect with psql as testusername' do + shell('PGPASSWORD=supersecret psql -U testusername -h localhost --command="\l"') do |r| + expect(r.stdout).to match(%r{List of databases}) + end + end +end diff --git a/spec/unit/classes/server_spec.rb b/spec/unit/classes/server_spec.rb index 02d5a95..0667567 100644 --- a/spec/unit/classes/server_spec.rb +++ b/spec/unit/classes/server_spec.rb @@ -1,166 +1,220 @@ require 'spec_helper' describe 'postgresql::server', type: :class do let :facts do { os: { family: 'Debian', name: 'Debian', release: { full: '6.0', major: '6', }, }, osfamily: 'Debian', operatingsystem: 'Debian', lsbdistid: 'Debian', lsbdistcodename: 'jessie', operatingsystemrelease: '8.0', concat_basedir: tmpfilename('server'), kernel: 'Linux', id: 'root', path: '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin', } end describe 'with no parameters' do it { is_expected.to contain_class('postgresql::params') } it { is_expected.to contain_class('postgresql::server') } it { is_expected.to contain_exec('postgresql_reload').with('command' => 'service postgresql reload') } it 'validates connection' do is_expected.to contain_postgresql_conn_validator('validate_service_is_running') end end describe 'service_ensure => running' do let(:params) do { service_ensure: 'running', postgres_password: 'new-p@s$word-to-set', } end it { is_expected.to contain_class('postgresql::params') } it { is_expected.to contain_class('postgresql::server') } it { is_expected.to contain_class('postgresql::server::passwd') } it 'validates connection' do is_expected.to contain_postgresql_conn_validator('validate_service_is_running') end it 'sets postgres password' do is_expected.to contain_exec('set_postgres_postgrespw').with('command' => '/usr/bin/psql -c "ALTER ROLE \"postgres\" PASSWORD ${NEWPASSWD_ESCAPED}"', 'user' => 'postgres', 'environment' => ['PGPASSWORD=new-p@s$word-to-set', 'PGPORT=5432', 'NEWPASSWD_ESCAPED=$$new-p@s$word-to-set$$'], 'unless' => "/usr/bin/psql -h localhost -p 5432 -c 'select 1' > /dev/null") end end describe 'service_ensure => stopped' do let(:params) { { service_ensure: 'stopped' } } it { is_expected.to contain_class('postgresql::params') } it { is_expected.to contain_class('postgresql::server') } it 'shouldnt validate connection' do is_expected.not_to contain_postgresql_conn_validator('validate_service_is_running') end end describe 'service_restart_on_change => false' do let(:params) { { service_restart_on_change: false } } it { is_expected.to contain_class('postgresql::params') } it { is_expected.to contain_class('postgresql::server') } it { is_expected.not_to contain_Postgresql_conf('data_directory').that_notifies('Class[postgresql::server::service]') } it 'validates connection' do is_expected.to contain_postgresql_conn_validator('validate_service_is_running') end end describe 'service_restart_on_change => true' do let(:params) { { service_restart_on_change: true } } it { is_expected.to contain_class('postgresql::params') } it { is_expected.to contain_class('postgresql::server') } it { is_expected.to contain_Postgresql_conf('data_directory').that_notifies('Class[postgresql::server::service]') } it 'validates connection' do is_expected.to contain_postgresql_conn_validator('validate_service_is_running') end end describe 'service_reload => /bin/true' do let(:params) { { service_reload: '/bin/true' } } it { is_expected.to contain_class('postgresql::params') } it { is_expected.to contain_class('postgresql::server') } it { is_expected.to contain_exec('postgresql_reload').with('command' => '/bin/true') } it 'validates connection' do is_expected.to contain_postgresql_conn_validator('validate_service_is_running') end end describe 'service_manage => true' do let(:params) { { service_manage: true } } it { is_expected.to contain_service('postgresqld') } end describe 'service_manage => false' do let(:params) { { service_manage: false } } it { is_expected.not_to contain_service('postgresqld') } it 'shouldnt validate connection' do is_expected.not_to contain_postgresql_conn_validator('validate_service_is_running') end end describe 'package_ensure => absent' do let(:params) do { package_ensure: 'absent', } end it 'removes the package' do is_expected.to contain_package('postgresql-server').with(ensure: 'purged') end it 'stills enable the service' do is_expected.to contain_service('postgresqld').with(ensure: 'running') end end describe 'needs_initdb => true' do let(:params) do { needs_initdb: true, } end it 'contains proper initdb exec' do is_expected.to contain_exec('postgresql_initdb') end end describe 'postgresql_version' do let(:pre_condition) do <<-EOS class { 'postgresql::globals': manage_package_repo => true, version => '99.5', before => Class['postgresql::server'], } EOS end it 'contains the correct package version' do is_expected.to contain_class('postgresql::repo').with_version('99.5') end end + + describe 'additional roles' do + let(:params) do + { + roles: { + username: { createdb: true }, + }, + } + end + + it { is_expected.to compile.with_all_deps } + it { is_expected.to contain_postgresql__server__role('username').with_createdb(true) } + end + + describe 'additional config_entries' do + let(:params) do + { + config_entries: { + fsync: 'off', + checkpoint_segments: '20', + }, + } + end + + it { is_expected.to compile.with_all_deps } + it { is_expected.to contain_postgresql__server__config_entry('fsync').with_value('off') } + it { is_expected.to contain_postgresql__server__config_entry('checkpoint_segments').with_value('20') } + end + + describe 'additional pg_hba_rules' do + let(:params) do + { + pg_hba_rules: { + from_remote_host: { + type: 'host', + database: 'mydb', + user: 'myuser', + auth_method: 'md5', + address: '192.0.2.100', + }, + }, + } + end + + it { is_expected.to compile.with_all_deps } + it do + is_expected.to contain_postgresql__server__pg_hba_rule('from_remote_host') + .with_type('host') + .with_database('mydb') + .with_user('myuser') + .with_auth_method('md5') + .with_address('192.0.2.100') + end + end end diff --git a/spec/unit/defines/server/grant_spec.rb b/spec/unit/defines/server/grant_spec.rb index a41b1f0..6e97294 100644 --- a/spec/unit/defines/server/grant_spec.rb +++ b/spec/unit/defines/server/grant_spec.rb @@ -1,295 +1,295 @@ 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 compile.with_all_deps } 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 compile.with_all_deps } it { is_expected.to contain_postgresql__server__grant('test') } it do is_expected.to contain_postgresql_psql('grant:test') .with_command(%r{GRANT USAGE ON SEQUENCE "test" TO\s* "test"}m) .with_unless(%r{SELECT 1 WHERE has_sequence_privilege\('test',\s* 'test', 'USAGE'\)}m) end end context 'SeQuEnCe case insensitive object_type match' 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 compile.with_all_deps } it { is_expected.to contain_postgresql__server__grant('test') } it do is_expected.to contain_postgresql_psql('grant:test') .with_command(%r{GRANT USAGE ON SEQUENCE "test" TO\s* "test"}m) .with_unless(%r{SELECT 1 WHERE has_sequence_privilege\('test',\s* 'test', 'USAGE'\)}m) end 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 compile.with_all_deps } it { is_expected.to contain_postgresql__server__grant('test') } it do is_expected.to contain_postgresql_psql('grant:test') .with_command(%r{GRANT USAGE ON ALL SEQUENCES IN SCHEMA "public" TO\s* "test"}m) .with_unless(%r{SELECT 1 WHERE NOT EXISTS \(\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*\)}m) # rubocop:disable Metrics/LineLength end 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 compile.with_all_deps } 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 compile.with_all_deps } 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 compile.with_all_deps } 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 'with specific schema name' do let :params do { db: 'test', role: 'test', privilege: 'all', object_name: %w[myschema mytable], object_type: 'table', } end let :pre_condition do "class {'postgresql::server':}" end it { is_expected.to compile.with_all_deps } it { is_expected.to contain_postgresql__server__grant('test') } it do is_expected.to contain_postgresql_psql('grant:test') .with_command(%r{GRANT ALL ON TABLE "myschema"."mytable" TO\s* "test"}m) .with_unless(%r{SELECT 1 WHERE has_table_privilege\('test',\s*'myschema.mytable', 'INSERT'\)}m) end end context 'with a role defined' do let :params do { db: 'test', role: 'test', privilege: 'all', object_name: %w[myschema mytable], object_type: 'table', } end let :pre_condition do <<-EOS class {'postgresql::server':} postgresql::server::role { 'test': } EOS end it { is_expected.to compile.with_all_deps } it { is_expected.to contain_postgresql__server__grant('test') } it { is_expected.to contain_postgresql__server__role('test') } it do is_expected.to contain_postgresql_psql('grant:test') \ - .that_requires('Postgresql::Server::Role[test]') + .that_requires(['Class[postgresql::server::service]', 'Postgresql::Server::Role[test]']) end end context 'invalid object_type' 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(%r{parameter 'object_type' expects a match for Pattern}) } end context 'invalid object_name - wrong type' do let :params do { db: 'test', role: 'test', privilege: 'all', object_name: 1, object_type: 'table', } end let :pre_condition do "class {'postgresql::server':}" end it { is_expected.to compile.and_raise_error(%r{parameter 'object_name' expects a value of type (Array|Undef, Array,) or String, got Integer}) } end context 'invalid object_name - insufficent array elements' do let :params do { db: 'test', role: 'test', privilege: 'all', object_name: ['oops'], object_type: 'table', } end let :pre_condition do "class {'postgresql::server':}" end if Puppet::Util::Package.versioncmp(Puppet.version, '5.2.0') >= 0 it { is_expected.to compile.and_raise_error(%r{parameter 'object_name' variant 1 expects size to be 2, got 1}) } else it { is_expected.to compile.and_raise_error(%r{parameter 'object_name' variant 0 expects size to be 2, got 1}) } end end context 'invalid object_name - too many array elements' do let :params do { db: 'test', role: 'test', privilege: 'all', object_name: %w[myschema mytable oops], object_type: 'table', } end let :pre_condition do "class {'postgresql::server':}" end if Puppet::Util::Package.versioncmp(Puppet.version, '5.2.0') >= 0 it { is_expected.to compile.and_raise_error(%r{parameter 'object_name' variant 1 expects size to be 2, got 3}) } else it { is_expected.to compile.and_raise_error(%r{parameter 'object_name' variant 0 expects size to be 2, got 3}) } end end end diff --git a/spec/unit/defines/server/reassign_owned_by_spec.rb b/spec/unit/defines/server/reassign_owned_by_spec.rb index c71dfa8..c5a1794 100644 --- a/spec/unit/defines/server/reassign_owned_by_spec.rb +++ b/spec/unit/defines/server/reassign_owned_by_spec.rb @@ -1,43 +1,44 @@ require 'spec_helper' describe 'postgresql::server::reassign_owned_by', type: :define do let :facts do { osfamily: 'Debian', operatingsystem: 'Debian', operatingsystemrelease: '6.0', kernel: 'Linux', concat_basedir: tmpfilename('reassign_owned_by'), id: 'root', path: '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin', } end let :title do 'test' end let :params do { db: 'test', old_role: 'test_old_role', new_role: 'test_new_role', } end let :pre_condition do <<-MANIFEST class {'postgresql::server':} postgresql::server::role{ ['test_old_role','test_new_role']: } MANIFEST end + it { is_expected.to compile.with_all_deps } it { is_expected.to contain_postgresql__server__reassign_owned_by('test') } it { is_expected.to contain_postgresql_psql('reassign_owned_by:test:REASSIGN OWNED BY "test_old_role" TO "test_new_role"') .with_command('REASSIGN OWNED BY "test_old_role" TO "test_new_role"') .with_onlyif(%r{SELECT tablename FROM pg_catalog.pg_tables WHERE\s*schemaname NOT IN \('pg_catalog', 'information_schema'\) AND\s*tableowner = 'test_old_role'.*}m) - .that_requires('Class[postgresql::server]') + .that_requires('Class[Postgresql::Server::Service]') } end diff --git a/spec/unit/defines/server/role_spec.rb b/spec/unit/defines/server/role_spec.rb index ba8ff87..3867eb4 100644 --- a/spec/unit/defines/server/role_spec.rb +++ b/spec/unit/defines/server/role_spec.rb @@ -1,144 +1,145 @@ 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 'has 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 1 FROM pg_roles WHERE rolname = 'test'", 'port' => '5432') end it 'has 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 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 'has 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") .with_environment('NEWPGPASSWD=new-pa$s') .with_unless("SELECT 1 FROM pg_roles WHERE rolname = 'test'") .with_port(5432) .with_connect_settings('PGHOST' => 'postgres-db-server', 'DBVERSION' => '9.1', 'PGUSER' => 'login-user', 'PGPASSWORD' => 'login-pass') + .that_requires('Class[postgresql::server::service]') end it 'has 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 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 'has 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 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 'has 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 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 context 'with update_password set to false' do let :params do { password_hash: 'new-pa$s', update_password: false, } end let :pre_condition do "class {'postgresql::server':}" end it 'does not have alter role for "test" user with password as **** if update_password is false' do is_expected.not_to contain_postgresql_psql('ALTER ROLE test ENCRYPTED PASSWORD ****') end end context 'with ensure set to absent' do let :params do { ensure: 'absent', } end let :pre_condition do "class {'postgresql::server':}" end it 'has drop role for "test" user if ensure absent' do - is_expected.to contain_postgresql_psql('DROP ROLE "test"') + is_expected.to contain_postgresql_psql('DROP ROLE "test"').that_requires('Class[postgresql::server::service]') end end end diff --git a/spec/unit/defines/server/tablespace_spec.rb b/spec/unit/defines/server/tablespace_spec.rb index 96285d5..7a3af76 100644 --- a/spec/unit/defines/server/tablespace_spec.rb +++ b/spec/unit/defines/server/tablespace_spec.rb @@ -1,42 +1,43 @@ 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') } + it { is_expected.to contain_postgresql_psql('CREATE TABLESPACE "test"').that_requires('Class[postgresql::server::service]') } 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