Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
57 changes: 57 additions & 0 deletions manifests/server.pp
Original file line number Diff line number Diff line change
Expand Up @@ -99,10 +99,19 @@
# @param pg_hba_auth_password_encryption
# Specify the type of encryption set for the password in pg_hba_conf,
# this value is usefull if you want to start enforcing scram-sha-256, but give users transition time.
# @param databases Specifies a hash from which to generate postgresql::server::database resources.
# @param roles Specifies a hash from which to generate postgresql::server::role resources.
# @param grants Specifies a hash from which to generate postgresql::server::grant resources.
# @param config_entries Specifies a hash from which to generate postgresql::server::config_entry resources.
# @param pg_hba_rules Specifies a hash from which to generate postgresql::server::pg_hba_rule resources.
# @param extensions Specifies a hash from which to generate postgresql::server::extension resources.
# The hash keys are database names, and the values are hashes of extension names to extension parameters.
# @param grant_roles Specifies a hash from which to generate postgresql::server::grant_role resources.
# @param standby Specifies a hash from which to generate postgresql::server::recovery resources, for standby/recovery configuration.
# @param replication_slots
# Specifies a hash from which to generate postgresql_replication_slot resources, for streaming replication clients to
# connect via primary_slot_name. Only physical slots on the default instance are supported; the underlying native
# resource has no port/psql_path/connect_settings parameters, so this is not multi-instance aware.
#
# @param backup_enable Whether a backup job should be enabled.
# @param backup_options A hash of options that should be passed through to the backup provider.
Expand Down Expand Up @@ -185,10 +194,15 @@
Optional[Postgresql::Pg_password_encryption] $pg_hba_auth_password_encryption = undef,
Optional[String] $extra_systemd_config = $postgresql::params::extra_systemd_config,

Hash[String[1], Hash] $databases = {},
Hash[String, Hash] $roles = {},
Hash[String[1], Hash] $grants = {},
Hash[String, Any] $config_entries = {},
Postgresql::Pg_hba_rules $pg_hba_rules = {},
Hash[String, Hash] $extensions = {},
Hash[String[1], Hash] $grant_roles = {},
Postgresql::Standby $standby = {},
Hash[String[1], Hash] $replication_slots = {},

Boolean $backup_enable = $postgresql::params::backup_enable,
Hash $backup_options = {},
Expand All @@ -213,6 +227,12 @@
-> Class['postgresql::server::service']
-> Class['postgresql::server::passwd']

$databases.each |$databasename, $database| {
postgresql::server::database { $databasename:
* => $database,
}
}

$roles.each |$rolename, $role| {
postgresql::server::role { $rolename:
* => $role,
Expand All @@ -225,6 +245,24 @@
}
}

$grant_roles.each |$grantname, $grant_role| {
postgresql::server::grant_role { $grantname:
* => $grant_role,
}
}

$standby.each |$standbyname, $recovery| {
postgresql::server::recovery { $standbyname:
* => $recovery,
}
}

$replication_slots.each |$slotname, $slot| {
postgresql_replication_slot { $slotname:
* => $slot,
}
}

$config_entries.each |$entry, $value| {
postgresql::server::config_entry { $entry:
ensure => bool2str($value =~ Undef, 'absent', 'present'),
Expand All @@ -238,6 +276,25 @@
}
}

# Create databases first if not already defined
$extensions.each |$database, $extensions_hash| {
if $database != 'postgres' and ! defined(Postgresql::Server::Database[$database]) {
# The database resource doesn't exist, create it
postgresql::server::database { $database:
dbname => $database,
}
}
}

$extensions.each |$database, $extensions_hash| {
$extensions_hash.each |$extension_name, $extension_params| {
postgresql::server::extension { "${database}:${extension_name}":
database => $database,
* => $extension_params,
}
}
}

if $backup_enable {
case $backup_provider {
'pg_dump': {
Expand Down
4 changes: 2 additions & 2 deletions manifests/server/default_privileges.pp
Original file line number Diff line number Diff line change
Expand Up @@ -145,8 +145,8 @@
}

$_unless = $ensure ? {
'absent' => "SELECT 1 WHERE NOT EXISTS (SELECT * FROM pg_default_acl AS da LEFT JOIN pg_namespace AS n ON da.defaclnamespace = n.oid WHERE '%s=%s%s' = ANY (defaclacl)%s and defaclobjtype = '%s')", # lint:ignore:140chars
default => "SELECT 1 WHERE EXISTS (SELECT * FROM pg_default_acl AS da LEFT JOIN pg_namespace AS n ON da.defaclnamespace = n.oid WHERE '%s=%s%s' = ANY (defaclacl)%s and defaclobjtype = '%s')", # lint:ignore:140chars
'absent' => "SELECT 1 WHERE NOT EXISTS (SELECT * FROM pg_default_acl AS da LEFT JOIN pg_namespace AS n ON da.defaclnamespace = n.oid WHERE '\"%s\"=%s%s' = ANY (defaclacl)%s and defaclobjtype = '%s')", # lint:ignore:140chars
default => "SELECT 1 WHERE EXISTS (SELECT * FROM pg_default_acl AS da LEFT JOIN pg_namespace AS n ON da.defaclnamespace = n.oid WHERE '\"%s\"=%s%s' = ANY (defaclacl)%s and defaclobjtype = '%s')", # lint:ignore:140chars
}

$unless_cmd = sprintf($_unless, $role, $_check_privilege, $_check_target_role, $_check_schema, $_check_type)
Expand Down
2 changes: 1 addition & 1 deletion manifests/server/extension.pp
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@
define postgresql::server::extension (
String[1] $database,
Optional[Variant[Enum['present', 'absent', 'purged', 'disabled', 'installed', 'latest'], String[1]]] $package_ensure = undef,
String[1] $extension = $name,
String[1] $extension = split($name, ':')[1],
Optional[String[1]] $schema = undef,
Optional[String[1]] $version = undef,
Enum['present', 'absent'] $ensure = 'present',
Expand Down
3 changes: 0 additions & 3 deletions manifests/server/grant_role.pp
Original file line number Diff line number Diff line change
Expand Up @@ -42,9 +42,6 @@
connect_settings => $connect_settings,
}

if 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}"]
}
Expand Down
166 changes: 125 additions & 41 deletions manifests/server/recovery.pp
Original file line number Diff line number Diff line change
@@ -1,12 +1,19 @@
# @summary This resource manages the parameters that applies to the recovery.conf template.
# @summary This resource manages the parameters that apply to standby/recovery configuration.
#
# @note
# Allows you to create the content for recovery.conf. For more details see the usage example and the PostgreSQL documentation.
# Every parameter value is a string set in the template except recovery_target_inclusive, pause_at_recovery_target, standby_mode and
# recovery_min_apply_delay.
# A detailed description of all listed parameters can be found in the PostgreSQL documentation.
# Only the specified parameters are recognized in the template. The recovery.conf is only created if at least one parameter is set and
# manage_recovery_conf is set to true.
# On PostgreSQL < 12 this creates the content for recovery.conf. For more details see the usage example and the PostgreSQL
# documentation. Every parameter value is a string set in the template except recovery_target_inclusive, pause_at_recovery_target,
# standby_mode and recovery_min_apply_delay. A detailed description of all listed parameters can be found in the PostgreSQL
# documentation. Only the specified parameters are recognized in the template. The recovery.conf is only created if at least one
# parameter is set and manage_recovery_conf is set to true.
#
# On PostgreSQL >= 12, recovery.conf is never read by PostgreSQL. Instead this creates an empty standby.signal marker file and
# writes the recovery-relevant settings (primary_conninfo, primary_slot_name, restore_command, etc.) as ordinary postgresql.conf
# GUCs via postgresql::server::config_entry, since that is how PostgreSQL 12 and later expect standby/recovery configuration to
# be supplied. standby_mode, trigger_file and pause_at_recovery_target are legacy-only concepts on 12+: standby_mode is replaced
# by the mere presence of standby.signal, trigger_file was renamed to promote_trigger_file, and pause_at_recovery_target was
# replaced by recovery_target_action. If any of the three legacy-only parameters are set on PostgreSQL >= 12, a warning is
# raised and they are otherwise ignored (trigger_file is still honored as a fallback value for promote_trigger_file).
#
# @param restore_command The shell command to execute to retrieve an archived segment of the WAL file series.
# @param archive_cleanup_command This optional parameter specifies a shell command that will be executed at every restartpoint.
Expand All @@ -20,16 +27,28 @@
# @param recovery_target
# This parameter specifies that recovery should end as soon as a consistent state is reached, i.e. as early as possible.
# @param recovery_target_timeline Specifies recovering into a particular timeline.
# @param pause_at_recovery_target Specifies whether recovery should pause when the recovery target is reached.
# @param standby_mode Specifies whether to start the PostgreSQL server as a standby.
# @param recovery_target_action
# PostgreSQL >= 12 only. Specifies what action the server should take once the recovery target is reached: 'pause', 'promote' or
# 'shutdown'. Replaces the legacy pause_at_recovery_target boolean.
# @param pause_at_recovery_target
# PostgreSQL < 12 only. Specifies whether recovery should pause when the recovery target is reached. Ignored (with a warning) on
# PostgreSQL >= 12 — use recovery_target_action instead.
# @param standby_mode
# PostgreSQL < 12 only. Specifies whether to start the PostgreSQL server as a standby. Ignored (with a warning) on PostgreSQL >= 12,
# where standby state is instead determined purely by the presence of the standby.signal file.
# @param primary_conninfo Specifies a connection string to be used for the standby server to connect with the primary.
# @param primary_slot_name
# Optionally specifies an existing replication slot to be used when connecting to the primary via streaming replication to control
# resource removal on the upstream node.
# @param trigger_file Specifies a trigger file whose presence ends recovery in the standby.
# @param trigger_file
# PostgreSQL < 12 only. Specifies a trigger file whose presence ends recovery in the standby. On PostgreSQL >= 12 this is used only
# as a fallback value for promote_trigger_file if that is not also set, with a warning.
# @param promote_trigger_file
# PostgreSQL >= 12 only. Specifies a trigger file whose presence ends recovery in the standby. This is the PG12+ rename of
# trigger_file.
# @param recovery_min_apply_delay
# This parameter allows you to delay recovery by a fixed period of time, measured in milliseconds if no unit is specified.
# @param target Provides the target for the rule, and is generally an internal only property. Use with caution.
# @param target Provides the target for the rule, and is generally an internal only property. Use with caution. PostgreSQL < 12 only.
define postgresql::server::recovery (
Optional[String] $restore_command = undef,
Optional[String[1]] $archive_cleanup_command = undef,
Expand All @@ -40,11 +59,13 @@
Optional[Boolean] $recovery_target_inclusive = undef,
Optional[String[1]] $recovery_target = undef,
Optional[String[1]] $recovery_target_timeline = undef,
Optional[Enum['pause', 'promote', 'shutdown']] $recovery_target_action = undef,
Optional[Boolean] $pause_at_recovery_target = undef,
Optional[String[1]] $standby_mode = undef,
Optional[String[1]] $primary_conninfo = undef,
Optional[String[1]] $primary_slot_name = undef,
Optional[String[1]] $trigger_file = undef,
Optional[String[1]] $promote_trigger_file = undef,
Optional[Integer] $recovery_min_apply_delay = undef,
Stdlib::Absolutepath $target = $postgresql::server::recovery_conf_path
) {
Expand All @@ -54,41 +75,104 @@
if($restore_command == undef and $archive_cleanup_command == undef and $recovery_end_command == undef
and $recovery_target_name == undef and $recovery_target_time == undef and $recovery_target_xid == undef
and $recovery_target_inclusive == undef and $recovery_target == undef and $recovery_target_timeline == undef
and $pause_at_recovery_target == undef and $standby_mode == undef and $primary_conninfo == undef
and $primary_slot_name == undef and $trigger_file == undef and $recovery_min_apply_delay == undef) {
and $recovery_target_action == undef and $pause_at_recovery_target == undef and $standby_mode == undef
and $primary_conninfo == undef and $primary_slot_name == undef and $trigger_file == undef
and $promote_trigger_file == undef and $recovery_min_apply_delay == undef) {
fail('postgresql::server::recovery use this resource but do not pass a parameter will avoid creating the recovery.conf, because it makes no sense.') # lint:ignore:140chars
}

concat { $target:
owner => $postgresql::server::user,
group => $postgresql::server::group,
force => true, # do not crash if there is no recovery conf file
mode => '0640',
warn => true,
notify => Class['postgresql::server::reload'],
}
$_version = $postgresql::server::_version

if versioncmp($_version, '12') < 0 {
# ---------------- PostgreSQL < 12: recovery.conf (legacy, unchanged) ----------------
concat { $target:
owner => $postgresql::server::user,
group => $postgresql::server::group,
force => true, # do not crash if there is no recovery conf file
mode => '0640',
warn => true,
notify => Postgresql::Server::Instance::Reload['main'],
}

# Create the recovery.conf content
concat::fragment { "${name}-recovery.conf":
target => $target,
content => epp('postgresql/recovery.conf.epp', {
restore_command => $restore_command,
archive_cleanup_command => $archive_cleanup_command,
recovery_end_command => $recovery_end_command,
recovery_target_name => $recovery_target_name,
recovery_target_time => $recovery_target_time,
recovery_target_xid => $recovery_target_xid,
recovery_target_inclusive => $recovery_target_inclusive,
recovery_target => $recovery_target,
recovery_target_timeline => $recovery_target_timeline,
pause_at_recovery_target => $pause_at_recovery_target,
standby_mode => $standby_mode,
primary_conninfo => $primary_conninfo,
primary_slot_name => $primary_slot_name,
trigger_file => $trigger_file,
recovery_min_apply_delay => $recovery_min_apply_delay,
}
),
}
} else {
# ---------------- PostgreSQL >= 12: standby.signal + postgresql.conf GUCs ----------------
if $standby_mode != undef or $trigger_file != undef or $pause_at_recovery_target != undef {
warning("postgresql::server::recovery[${name}]: standby_mode, trigger_file and pause_at_recovery_target are legacy recovery.conf concepts and are ignored on PostgreSQL ${_version}. Standby state is now determined by the presence of standby.signal, trigger_file has been renamed to promote_trigger_file (still honored here as a fallback), and pause_at_recovery_target has been replaced by recovery_target_action.") # lint:ignore:140chars
}

if $promote_trigger_file {
$_promote_trigger_file = $promote_trigger_file
} else {
$_promote_trigger_file = $trigger_file
}

# postgresql::server::config_entry's $value only accepts String[1]/Numeric/Array[String[1]],
# so booleans must be rendered as postgresql.conf's on/off strings before being handed to it.
$_recovery_target_inclusive = $recovery_target_inclusive ? {
undef => undef,
true => 'on',
default => 'off',
}

file { "${name}_standby_signal":
ensure => file,
path => "${postgresql::server::datadir}/standby.signal",
owner => $postgresql::server::user,
group => $postgresql::server::group,
mode => '0640',
content => '',
require => Postgresql::Server::Instance::Initdb['main'],
before => Postgresql::Server::Instance::Service['main'],
}

$_guc_values = {
'primary_conninfo' => $primary_conninfo,
'primary_slot_name' => $primary_slot_name,
'restore_command' => $restore_command,
'archive_cleanup_command' => $archive_cleanup_command,
'recovery_end_command' => $recovery_end_command,
'recovery_target_name' => $recovery_target_name,
'recovery_target_time' => $recovery_target_time,
'recovery_target_xid' => $recovery_target_xid,
'recovery_target_inclusive' => $_recovery_target_inclusive,
'recovery_target' => $recovery_target,
'recovery_target_timeline' => $recovery_target_timeline,
'recovery_target_action' => $recovery_target_action,
'recovery_min_apply_delay' => $recovery_min_apply_delay,
'promote_trigger_file' => $_promote_trigger_file,
}.filter |$key, $value| { $value != undef }

# Create the recovery.conf content
concat::fragment { "${name}-recovery.conf":
target => $target,
content => epp('postgresql/recovery.conf.epp', {
restore_command => $restore_command,
archive_cleanup_command => $archive_cleanup_command,
recovery_end_command => $recovery_end_command,
recovery_target_name => $recovery_target_name,
recovery_target_time => $recovery_target_time,
recovery_target_xid => $recovery_target_xid,
recovery_target_inclusive => $recovery_target_inclusive,
recovery_target => $recovery_target,
recovery_target_timeline => $recovery_target_timeline,
pause_at_recovery_target => $pause_at_recovery_target,
standby_mode => $standby_mode,
primary_conninfo => $primary_conninfo,
primary_slot_name => $primary_slot_name,
trigger_file => $trigger_file,
recovery_min_apply_delay => $recovery_min_apply_delay,
$_guc_values.each |$key, $value| {
postgresql::server::config_entry { "${name}_${key}":
ensure => present,
key => $key,
value => $value,
path => $postgresql::server::postgresql_conf_path,
before => Postgresql::Server::Instance::Service['main'],
}
),
}
}
}
}
Loading
Loading