diff --git a/README.md b/README.md
index bef4b8bac6..2785010a37 100644
--- a/README.md
+++ b/README.md
@@ -8,6 +8,7 @@
* [Getting started with postgresql](#getting-started-with-postgresql)
3. [Usage - Configuration options and additional functionality](#usage)
* [Configure a server](#configure-a-server)
+ * [Configure an instance](#configure-an-instance)
* [Create a database](#create-a-database)
* [Manage users, roles, and permissions](#manage-users-roles-and-permissions)
* [Manage ownership of DB objects](#manage-ownership-of-db-objects)
@@ -72,6 +73,184 @@ If you get an error message from these commands, your permission settings restri
For more details about server configuration parameters, consult the [PostgreSQL Runtime Configuration documentation](http://www.postgresql.org/docs/current/static/runtime-config.html).
+### Configure an instance
+
+This module supports managing multiple instances (the default instance is referred to as 'main' and managed via including the server.pp class)
+
+**NOTE:** This feature is currently tested on Centos 8 Streams/RHEL8 with DNF Modules enabled. Different Linux plattforms and/or the Postgresql.org
+packages distribute different Systemd service files or use wrapper scripts with Systemd to start Postgres. Additional adjustmentments are needed to get this working on these plattforms.
+
+#### Working Plattforms
+
+* Centos 8 Streams
+* RHEL 8
+
+#### Background and example
+
+creating a new instance has the following advantages:
+* files are owned by the postgres user
+* instance is running under a different user, if the instance is hacked, the hacker has no access to the file system
+* the instance user can be an LDAP user, higher security because of central login monitoring, password policies, password rotation policies
+* main instance can be disabled
+
+
+Here is a profile which can be used to create instaces
+
+```puppet
+class profiles::postgres (
+ Hash $instances = {},
+ String $postgresql_version = '13',
+) {
+ class { 'postgresql::globals':
+ encoding => 'UTF-8',
+ locale => 'en_US.UTF-8',
+ manage_package_repo => false,
+ manage_dnf_module => true,
+ needs_initdb => true,
+ version => $postgresql_version,
+ }
+ include postgresql::server
+
+ $instances.each |String $instance, Hash $instance_settings| {
+ postgresql::server_instance { $instance:
+ * => $instance_settings,
+ }
+ }
+}
+```
+
+And here is data to create an instance called test1:
+
+```yaml
+# stop default main instance
+postgresql::server::service_ensure: "stopped"
+postgresql::server::service_enable: false
+
+#define an instance
+profiles::postgres::instances:
+ test1:
+ instance_user: "ins_test1"
+ instance_group: "ins_test1"
+ instance_directories:
+ "/opt/pgsql":
+ ensure: directory
+ "/opt/pgsql/backup":
+ ensure: directory
+ "/opt/pgsql/data":
+ ensure: directory
+ "/opt/pgsql/data/13":
+ ensure: directory
+ "/opt/pgsql/data/home":
+ ensure: directory
+ "/opt/pgsql/wal":
+ ensure: directory
+ "/opt/pgsql/log":
+ ensure: directory
+ "/opt/pgsql/log/13":
+ ensure: directory
+ "/opt/pgsql/log/13/test1":
+ ensure: directory
+ config_settings:
+ pg_hba_conf_path: "/opt/pgsql/data/13/test1/pg_hba.conf"
+ postgresql_conf_path: "/opt/pgsql/data/13/test1/postgresql.conf"
+ pg_ident_conf_path: "/opt/pgsql/data/13/test1/pg_ident.conf"
+ datadir: "/opt/pgsql/data/13/test1"
+ service_name: "postgresql@13-test1"
+ port: 5433
+ pg_hba_conf_defaults: false
+ service_settings:
+ service_name: "postgresql@13-test1"
+ service_status: "systemctl status postgresql@13-test1.service"
+ service_ensure: "running"
+ service_enable: true
+ initdb_settings:
+ auth_local: "peer"
+ auth_host: "md5"
+ needs_initdb: true
+ datadir: "/opt/pgsql/data/13/test1"
+ encoding: "UTF-8"
+ lc_messages: "en_US.UTF8"
+ locale: "en_US.UTF8"
+ data_checksums: false
+ group: "postgres"
+ user: "postgres"
+ username: "ins_test1"
+ config_entries:
+ authentication_timeout:
+ value: "1min"
+ comment: "a test"
+ log_statement_stats:
+ value: "off"
+ autovacuum_vacuum_scale_factor:
+ value: 0.3
+ databases:
+ testdb1:
+ encoding: "UTF8"
+ locale: "en_US.UTF8"
+ owner: "dba_test1"
+ testdb2:
+ encoding: "UTF8"
+ locale: "en_US.UTF8"
+ owner: "dba_test1"
+ roles:
+ "ins_test1":
+ superuser: true
+ login: true
+ "dba_test1":
+ createdb: true
+ login: true
+ "app_test1":
+ login: true
+ "rep_test1":
+ replication: true
+ login: true
+ "rou_test1":
+ login: true
+ pg_hba_rules:
+ "local all INSTANCE user":
+ type: "local"
+ database: "all"
+ user: "ins_test1"
+ auth_method: "peer"
+ order: 1
+ "local all DB user":
+ type: "local"
+ database: "all"
+ user: "dba_test1"
+ auth_method: "peer"
+ order: 2
+ "local all APP user":
+ type: "local"
+ database: "all"
+ user: "app_test1"
+ auth_method: "peer"
+ order: 3
+ "local all READONLY user":
+ type: "local"
+ database: "all"
+ user: "rou_test1"
+ auth_method: "peer"
+ order: 4
+ "remote all INSTANCE user PGADMIN server":
+ type: "host"
+ database: "all"
+ user: "ins_test1"
+ address: "192.168.22.131/32"
+ auth_method: "md5"
+ order: 5
+ "local replication INSTANCE user":
+ type: "local"
+ database: "replication"
+ user: "ins_test1"
+ auth_method: "peer"
+ order: 6
+ "local replication REPLICATION user":
+ type: "local"
+ database: "replication"
+ user: "rep_test1"
+ auth_method: "peer"
+ order: 7
+```
### Create a database
You can set up a variety of PostgreSQL databases with the `postgresql::server::db` defined type. For instance, to set up a database for PuppetDB:
@@ -359,7 +538,7 @@ For information on the classes and types, see the [REFERENCE.md](https://github.
## Limitations
-Works with versions of PostgreSQL on supported OSes.
+Works with versions of PostgreSQL on supported OSes.
For an extensive list of supported operating systems, see [metadata.json](https://github.com/puppetlabs/puppetlabs-postgresql/blob/main/metadata.json)
diff --git a/REFERENCE.md b/REFERENCE.md
index b65c0275e6..207f4ab99a 100644
--- a/REFERENCE.md
+++ b/REFERENCE.md
@@ -63,6 +63,7 @@
* [`postgresql::server::schema`](#postgresql--server--schema): Create a new schema.
* [`postgresql::server::table_grant`](#postgresql--server--table_grant): This resource wraps the grant resource to manage table grants specifically.
* [`postgresql::server::tablespace`](#postgresql--server--tablespace): This module creates tablespace.
+* [`postgresql::server_instance`](#postgresql--server_instance): define to install and manage additional postgresql instances
#### Private Defined types
@@ -1402,7 +1403,7 @@ Data type: `Optional[String[1]]`
username of user running the postgres instance
-Default value: `undef`
+Default value: `$user`
### `postgresql::server::contrib`
@@ -1526,6 +1527,7 @@ The following parameters are available in the `postgresql::server::config_entry`
* [`key`](#-postgresql--server--config_entry--key)
* [`value`](#-postgresql--server--config_entry--value)
* [`path`](#-postgresql--server--config_entry--path)
+* [`comment`](#-postgresql--server--config_entry--comment)
##### `ensure`
@@ -1559,6 +1561,14 @@ Path for postgresql.conf
Default value: `$postgresql::server::postgresql_conf_path`
+##### `comment`
+
+Data type: `Optional[String[1]]`
+
+Defines the comment for the setting. The # is added by default.
+
+Default value: `undef`
+
### `postgresql::server::database`
Define for creating a database.
@@ -1575,6 +1585,7 @@ The following parameters are available in the `postgresql::server::database` def
* [`encoding`](#-postgresql--server--database--encoding)
* [`locale`](#-postgresql--server--database--locale)
* [`istemplate`](#-postgresql--server--database--istemplate)
+* [`instance`](#-postgresql--server--database--instance)
* [`connect_settings`](#-postgresql--server--database--connect_settings)
* [`psql_path`](#-postgresql--server--database--psql_path)
* [`default_db`](#-postgresql--server--database--default_db)
@@ -1646,6 +1657,14 @@ Defines the database as a template if set to true.
Default value: `false`
+##### `instance`
+
+Data type: `String[1]`
+
+The name of the Postgresql database instance.
+
+Default value: `'main'`
+
##### `connect_settings`
Data type: `Hash`
@@ -1800,6 +1819,7 @@ The following parameters are available in the `postgresql::server::db` defined t
* [`port`](#-postgresql--server--db--port)
* [`psql_user`](#-postgresql--server--db--psql_user)
* [`psql_group`](#-postgresql--server--db--psql_group)
+* [`instance`](#-postgresql--server--db--instance)
##### `user`
@@ -1911,6 +1931,14 @@ Overrides the default PostgreSQL user group to be used for related files in the
Default value: `$postgresql::server::group`
+##### `instance`
+
+Data type: `String[1]`
+
+The name of the Postgresql database instance.
+
+Default value: `'main'`
+
### `postgresql::server::default_privileges`
Manage a database defaults privileges. Only works with PostgreSQL version 9.6 and above.
@@ -1931,6 +1959,7 @@ The following parameters are available in the `postgresql::server::default_privi
* [`psql_path`](#-postgresql--server--default_privileges--psql_path)
* [`port`](#-postgresql--server--default_privileges--port)
* [`connect_settings`](#-postgresql--server--default_privileges--connect_settings)
+* [`instance`](#-postgresql--server--default_privileges--instance)
* [`group`](#-postgresql--server--default_privileges--group)
##### `target_role`
@@ -2032,6 +2061,14 @@ Specifies a hash of environment variables used when connecting to a remote serve
Default value: `$postgresql::server::default_connect_settings`
+##### `instance`
+
+Data type: `String[1]`
+
+The name of the Postgresql database instance.
+
+Default value: `'main'`
+
##### `group`
Data type: `String`
@@ -2058,6 +2095,7 @@ The following parameters are available in the `postgresql::server::extension` de
* [`port`](#-postgresql--server--extension--port)
* [`connect_settings`](#-postgresql--server--extension--connect_settings)
* [`database_resource_name`](#-postgresql--server--extension--database_resource_name)
+* [`instance`](#-postgresql--server--extension--instance)
* [`psql_path`](#-postgresql--server--extension--psql_path)
* [`user`](#-postgresql--server--extension--user)
* [`group`](#-postgresql--server--extension--group)
@@ -2148,6 +2186,14 @@ Specifies the resource name of the DB being managed. Defaults to the parameter $
Default value: `$database`
+##### `instance`
+
+Data type: `String[1]`
+
+The name of the Postgresql database instance.
+
+Default value: `'main'`
+
##### `psql_path`
Data type: `Stdlib::Absolutepath`
@@ -2194,6 +2240,7 @@ The following parameters are available in the `postgresql::server::grant` define
* [`ensure`](#-postgresql--server--grant--ensure)
* [`group`](#-postgresql--server--grant--group)
* [`psql_path`](#-postgresql--server--grant--psql_path)
+* [`instance`](#-postgresql--server--grant--instance)
##### `role`
@@ -2323,6 +2370,14 @@ Sets the path to psql command
Default value: `$postgresql::server::psql_path`
+##### `instance`
+
+Data type: `String[1]`
+
+The name of the Postgresql database instance.
+
+Default value: `'main'`
+
### `postgresql::server::grant_role`
Define for granting membership to a role.
@@ -2338,6 +2393,7 @@ The following parameters are available in the `postgresql::server::grant_role` d
* [`psql_user`](#-postgresql--server--grant_role--psql_user)
* [`port`](#-postgresql--server--grant_role--port)
* [`connect_settings`](#-postgresql--server--grant_role--connect_settings)
+* [`instance`](#-postgresql--server--grant_role--instance)
##### `group`
@@ -2393,6 +2449,14 @@ Specifies a hash of environment variables used when connecting to a remote serve
Default value: `$postgresql::server::default_connect_settings`
+##### `instance`
+
+Data type: `String[1]`
+
+The name of the Postgresql database instance.
+
+Default value: `'main'`
+
### `postgresql::server::instance::config`
Manages the config for a postgresql::server instance
@@ -3330,6 +3394,7 @@ The following parameters are available in the `postgresql::server::reassign_owne
* [`connect_settings`](#-postgresql--server--reassign_owned_by--connect_settings)
* [`group`](#-postgresql--server--reassign_owned_by--group)
* [`psql_path`](#-postgresql--server--reassign_owned_by--psql_path)
+* [`instance`](#-postgresql--server--reassign_owned_by--instance)
##### `old_role`
@@ -3389,6 +3454,14 @@ Sets the path to psql command
Default value: `$postgresql::server::psql_path`
+##### `instance`
+
+Data type: `String[1]`
+
+The name of the Postgresql database instance.
+
+Default value: `'main'`
+
### `postgresql::server::recovery`
This resource manages the parameters that applies to the recovery.conf template.
@@ -3578,6 +3651,7 @@ The following parameters are available in the `postgresql::server::role` defined
* [`module_workdir`](#-postgresql--server--role--module_workdir)
* [`hash`](#-postgresql--server--role--hash)
* [`salt`](#-postgresql--server--role--salt)
+* [`instance`](#-postgresql--server--role--instance)
##### `update_password`
@@ -3740,6 +3814,14 @@ Specify the salt use for the scram-sha-256 encoding password (default username)
Default value: `undef`
+##### `instance`
+
+Data type: `String[1]`
+
+The name of the Postgresql database instance.
+
+Default value: `'main'`
+
### `postgresql::server::schema`
Create a new schema.
@@ -3769,6 +3851,7 @@ The following parameters are available in the `postgresql::server::schema` defin
* [`group`](#-postgresql--server--schema--group)
* [`psql_path`](#-postgresql--server--schema--psql_path)
* [`module_workdir`](#-postgresql--server--schema--module_workdir)
+* [`instance`](#-postgresql--server--schema--instance)
##### `db`
@@ -3843,6 +3926,14 @@ May need to specify if '/tmp' is on volume mounted with noexec option.
Default value: `$postgresql::server::module_workdir`
+##### `instance`
+
+Data type: `String[1]`
+
+The name of the Postgresql database instance.
+
+Default value: `'main'`
+
### `postgresql::server::table_grant`
This resource wraps the grant resource to manage table grants specifically.
@@ -3958,6 +4049,7 @@ The following parameters are available in the `postgresql::server::tablespace` d
* [`group`](#-postgresql--server--tablespace--group)
* [`psql_path`](#-postgresql--server--tablespace--psql_path)
* [`module_workdir`](#-postgresql--server--tablespace--module_workdir)
+* [`instance`](#-postgresql--server--tablespace--instance)
##### `location`
@@ -4038,6 +4130,176 @@ May need to specify if '/tmp' is on volume mounted with noexec option.
Default value: `$postgresql::server::module_workdir`
+##### `instance`
+
+Data type: `String[1]`
+
+The name of the Postgresql database instance.
+
+Default value: `'main'`
+
+### `postgresql::server_instance`
+
+define to install and manage additional postgresql instances
+
+#### Parameters
+
+The following parameters are available in the `postgresql::server_instance` defined type:
+
+* [`instance_name`](#-postgresql--server_instance--instance_name)
+* [`instance_user`](#-postgresql--server_instance--instance_user)
+* [`instance_group`](#-postgresql--server_instance--instance_group)
+* [`instance_user_homedirectory`](#-postgresql--server_instance--instance_user_homedirectory)
+* [`manage_instance_user_and_group`](#-postgresql--server_instance--manage_instance_user_and_group)
+* [`instance_directories`](#-postgresql--server_instance--instance_directories)
+* [`initdb_settings`](#-postgresql--server_instance--initdb_settings)
+* [`config_settings`](#-postgresql--server_instance--config_settings)
+* [`service_settings`](#-postgresql--server_instance--service_settings)
+* [`passwd_settings`](#-postgresql--server_instance--passwd_settings)
+* [`roles`](#-postgresql--server_instance--roles)
+* [`config_entries`](#-postgresql--server_instance--config_entries)
+* [`pg_hba_rules`](#-postgresql--server_instance--pg_hba_rules)
+* [`databases`](#-postgresql--server_instance--databases)
+* [`databases_and_users`](#-postgresql--server_instance--databases_and_users)
+* [`database_grants`](#-postgresql--server_instance--database_grants)
+* [`table_grants`](#-postgresql--server_instance--table_grants)
+
+##### `instance_name`
+
+Data type: `String[1]`
+
+The name of the instance.
+
+Default value: `$name`
+
+##### `instance_user`
+
+Data type: `String[1]`
+
+The user to run the instance as.
+
+Default value: `$instance_name`
+
+##### `instance_group`
+
+Data type: `String[1]`
+
+The group to run the instance as.
+
+Default value: `$instance_name`
+
+##### `instance_user_homedirectory`
+
+Data type: `Stdlib::Absolutepath`
+
+The home directory of the instance user.
+
+Default value: `"/opt/pgsql/data/home/${instance_user}"`
+
+##### `manage_instance_user_and_group`
+
+Data type: `Boolean`
+
+Should Puppet manage the instance user and it's primary group?.
+
+Default value: `true`
+
+##### `instance_directories`
+
+Data type: `Hash`
+
+directories needed for the instance. Option to manage the directory properties for each directory.
+
+Default value: `{}`
+
+##### `initdb_settings`
+
+Data type: `Hash`
+
+Specifies a hash witn parameters for postgresql::server::instance::initdb
+
+Default value: `{}`
+
+##### `config_settings`
+
+Data type: `Hash`
+
+Specifies a hash with parameters for postgresql::server::instance::config
+
+Default value: `{}`
+
+##### `service_settings`
+
+Data type: `Hash`
+
+Specifies a hash with parameters for postgresql::server:::instance::service
+
+Default value: `{}`
+
+##### `passwd_settings`
+
+Data type: `Hash`
+
+Specifies a hash with parameters for postgresql::server::instance::passwd
+
+Default value: `{}`
+
+##### `roles`
+
+Data type: `Hash`
+
+Specifies a hash from which to generate postgresql::server::role resources.
+
+Default value: `{}`
+
+##### `config_entries`
+
+Data type: `Hash`
+
+Specifies a hash from which to generate postgresql::server::config_entry resources.
+
+Default value: `{}`
+
+##### `pg_hba_rules`
+
+Data type: `Hash`
+
+Specifies a hash from which to generate postgresql::server::pg_hba_rule resources.
+
+Default value: `{}`
+
+##### `databases`
+
+Data type: `Hash`
+
+Specifies a hash from which to generate postgresql::server::database resources.
+
+Default value: `{}`
+
+##### `databases_and_users`
+
+Data type: `Hash`
+
+Specifies a hash from which to generate postgresql::server::db resources.
+
+Default value: `{}`
+
+##### `database_grants`
+
+Data type: `Hash`
+
+Specifies a hash from which to generate postgresql::server::database_grant resources.
+
+Default value: `{}`
+
+##### `table_grants`
+
+Data type: `Hash`
+
+Specifies a hash from which to generate postgresql::server::table_grant resources.
+
+Default value: `{}`
+
## Resource types
### `postgresql_conf`
@@ -4048,6 +4310,12 @@ This type allows puppet to manage postgresql.conf parameters.
The following properties are available in the `postgresql_conf` type.
+##### `comment`
+
+Valid values: `%r{^[\w\W]+$}`
+
+The comment to set for this parameter.
+
##### `ensure`
Valid values: `present`, `absent`
@@ -4056,20 +4324,26 @@ The basic property that the resource should be in.
Default value: `present`
-##### `target`
-
-The path to postgresql.conf
-
##### `value`
+Valid values: `%r{^\S(.*\S)?$}`
+
The value to set for this parameter.
#### Parameters
The following parameters are available in the `postgresql_conf` type.
+* [`key`](#-postgresql_conf--key)
* [`name`](#-postgresql_conf--name)
* [`provider`](#-postgresql_conf--provider)
+* [`target`](#-postgresql_conf--target)
+
+##### `key`
+
+Valid values: `%r{^[\w.]+$}`
+
+The Postgresql parameter to manage.
##### `name`
@@ -4077,13 +4351,19 @@ Valid values: `%r{^[\w.]+$}`
namevar
-The postgresql parameter name to manage.
+A unique title for the resource.
##### `provider`
The specific backend to use for this `postgresql_conf` resource. You will seldom need to specify this --- Puppet will
usually discover the appropriate provider for your platform.
+##### `target`
+
+Valid values: `%r{^/\S+[a-z0-9(/)-]*\w+.conf$}`
+
+The path to the postgresql config file
+
### `postgresql_conn_validator`
Verify that a connection can be successfully established between a node
diff --git a/lib/puppet/provider/postgresql_conf/parsed.rb b/lib/puppet/provider/postgresql_conf/parsed.rb
deleted file mode 100644
index 8918769cab..0000000000
--- a/lib/puppet/provider/postgresql_conf/parsed.rb
+++ /dev/null
@@ -1,45 +0,0 @@
-# frozen_string_literal: true
-
-require 'puppet/provider/parsedfile'
-
-Puppet::Type.type(:postgresql_conf).provide(
- :parsed,
- parent: Puppet::Provider::ParsedFile,
- default_target: '/etc/postgresql.conf',
- filetype: :flat,
-) do
- desc 'Set key/values in postgresql.conf.'
-
- text_line :comment, match: %r{^\s*#}
- text_line :blank, match: %r{^\s*$}
-
- record_line :parsed,
- fields: ['name', 'value', 'comment'],
- optional: ['comment'],
- match: %r{^\s*([\w.]+)\s*=?\s*(.*?)(?:\s*#\s*(.*))?\s*$},
- to_line: proc { |h|
- # simple string and numeric values don't need to be enclosed in quotes
- val = if h[:value].is_a?(Numeric)
- h[:value].to_s
- elsif h[:value].is_a?(Array)
- # multiple listen_addresses specified as a string containing a comma-speparated list
- h[:value].join(', ')
- else
- h[:value]
- end
- dontneedquote = val.match(%r{^(\d+.?\d+|\w+)$})
- dontneedequal = h[:name].match(%r{^(include|include_if_exists)$}i)
-
- str = h[:name].downcase # normalize case
- str += dontneedequal ? ' ' : ' = '
- str += "'" unless dontneedquote && !dontneedequal
- str += val
- str += "'" unless dontneedquote && !dontneedequal
- str += " # #{h[:comment]}" unless h[:comment].nil? || h[:comment] == :absent
- str
- },
- post_parse: proc { |h|
- h[:name].downcase! # normalize case
- h[:value].gsub!(%r{(^'|'$)}, '') # strip out quotes
- }
-end
diff --git a/lib/puppet/provider/postgresql_conf/ruby.rb b/lib/puppet/provider/postgresql_conf/ruby.rb
new file mode 100644
index 0000000000..63b87478d1
--- /dev/null
+++ b/lib/puppet/provider/postgresql_conf/ruby.rb
@@ -0,0 +1,167 @@
+# frozen_string_literal: true
+
+# This provider is used to manage postgresql.conf files
+# It uses ruby to parse the config file and
+# to add, remove or modify settings.
+#
+# The provider is able to parse postgresql.conf files with the following format:
+# key = value # comment
+
+Puppet::Type.type(:postgresql_conf).provide(:ruby) do
+ desc 'Set keys, values and comments in a postgresql config file.'
+ confine kernel: 'Linux'
+
+ # The function pareses the postgresql.conf and figures out which active settings exist in a config file and returns an array of hashes
+ #
+ def parse_config
+ # open the config file
+ file = File.open(resource[:target])
+ # regex to match active keys, values and comments
+ active_values_regex = %r{^\s*(?[\w.]+)\s*=?\s*(?.*?)(?:\s*#\s*(?.*))?\s*$}
+ # empty array to be filled with hashes
+ active_settings = []
+ # iterate the file and construct a hash for every matching/active setting
+ # the hash is pushed to the array and the array is returned
+ File.foreach(file).with_index do |line, index|
+ line_number = index + 1
+ matches = line.match(active_values_regex)
+ if matches
+ value = if matches[:value].to_i.to_s == matches[:value]
+ matches[:value].to_i
+ elsif matches[:value].to_f.to_s == matches[:value]
+ matches[:value].to_f
+ else
+ matches[:value].delete("'")
+ end
+ attributes_hash = { line_number: line_number, key: matches[:key], ensure: 'present', value: value, comment: matches[:comment] }
+ active_settings.push(attributes_hash)
+ end
+ end
+ Puppet.debug("DEBUG: parse_config Active Settings found in Postgreql config file: #{active_settings}")
+ active_settings
+ end
+
+ # Deletes an existing header from a parsed postgresql.conf configuration file
+ #
+ # @param [Array] lines of the parsed postgresql configuration file
+ def delete_header(lines)
+ header_regex = %r{^# HEADER:.*}
+ lines.delete_if do |entry|
+ entry.match?(header_regex)
+ end
+ end
+
+ # Adds a header to a parsed postgresql.conf configuration file, after all other changes are made
+ #
+ # @param [Array] lines of the parsed postgresql configuration file
+ def add_header(lines)
+ timestamp = Time.now.strftime('%F %T %z')
+ header = ["# HEADER: This file was autogenerated at #{timestamp}\n",
+ "# HEADER: by puppet. While it can still be managed manually, it\n",
+ "# HEADER: is definitely not recommended.\n"]
+ header + lines
+ end
+
+ # This function writes the config file, it removes the old header, adds a new one and writes the file
+ #
+ # @param [File] the file object of the postgresql configuration file
+ # @param [Array] lines of the parsed postgresql configuration file
+ def write_config(file, lines)
+ lines = delete_header(lines)
+ lines = add_header(lines)
+ File.write(file, lines.join)
+ end
+
+ # check, if resource exists in postgresql.conf file
+ def exists?
+ select = parse_config.select { |hash| hash[:key] == resource[:key] }
+ raise ParserError, "found multiple config items of #{resource[:key]} found, please fix this" if select.length > 1
+ return false if select.empty?
+
+ @result = select.first
+ Puppet.debug("DEBUG: exists? @result: #{@result}")
+ true
+ end
+
+ # remove resource if exists and is set to absent
+ def destroy
+ entry_regex = %r{#{resource[:key]}.*=.*#{resource[:value]}}
+ file = File.open(resource[:target])
+ lines = File.readlines(file)
+
+ lines.delete_if do |entry|
+ entry.match?(entry_regex)
+ end
+ write_config(file, lines)
+ end
+
+ # create resource if it does not exists
+ def create
+ file = File.open(resource[:target])
+ lines = File.readlines(file)
+ new_line = line(key: resource[:key], value: resource[:value], comment: resource[:comment])
+
+ lines.push(new_line)
+ write_config(file, lines)
+ end
+
+ # getter - get value of a resource
+ def value
+ @result[:value]
+ end
+
+ # getter - get comment of a resource
+ def comment
+ @result[:comment]
+ end
+
+ # setter - set value of a resource
+ def value=(_value)
+ file = File.open(resource[:target])
+ lines = File.readlines(file)
+ active_values_regex = %r{^\s*(?[\w.]+)\s*=?\s*(?.*?)(?:\s*#\s*(?.*))?\s*$}
+ new_line = line(key: resource[:key], value: resource[:value], comment: resource[:comment])
+
+ lines.each_with_index do |line, index|
+ matches = line.to_s.match(active_values_regex)
+ lines[index] = new_line if matches && (matches[:key] == resource[:key] && matches[:value] != resource[:value])
+ end
+ write_config(file, lines)
+ end
+
+ # setter - set comment of a resource
+ def comment=(_comment)
+ file = File.open(resource[:target])
+ lines = File.readlines(file)
+ active_values_regex = %r{^\s*(?[\w.]+)\s*=?\s*(?.*?)(?:\s*#\s*(?.*))?\s*$}
+ new_line = line(key: resource[:key], value: resource[:value], comment: resource[:comment])
+
+ lines.each_with_index do |line, index|
+ matches = line.to_s.match(active_values_regex)
+ lines[index] = new_line if matches && (matches[:key] == resource[:key] && matches[:comment] != resource[:comment])
+ end
+ write_config(file, lines)
+ end
+
+ private
+
+ # Takes elements for a postgresql.conf configuration line and formats them properly
+ #
+ # @param [String] key postgresql.conf configuration option
+ # @param [String] value the value for the configuration option
+ # @param [String] comment optional comment that will be added at the end of the line
+ # @return [String] line the whole line for the config file, with \n
+ def line(key: '', value: '', comment: nil)
+ value = value.to_s if value.is_a?(Numeric)
+ dontneedquote = value.match(%r{^(\d+.?\d+|\w+)$})
+ dontneedequal = key.match(%r{^(include|include_if_exists)$}i)
+ line = key.downcase # normalize case
+ line += dontneedequal ? ' ' : ' = '
+ line += "'" unless dontneedquote && !dontneedequal
+ line += value
+ line += "'" unless dontneedquote && !dontneedequal
+ line += " # #{comment}" unless comment.nil? || comment == :absent
+ line += "\n"
+ line
+ end
+end
diff --git a/lib/puppet/type/postgresql_conf.rb b/lib/puppet/type/postgresql_conf.rb
index c014ac0fe8..432f5aa877 100644
--- a/lib/puppet/type/postgresql_conf.rb
+++ b/lib/puppet/type/postgresql_conf.rb
@@ -2,28 +2,40 @@
Puppet::Type.newtype(:postgresql_conf) do
@doc = 'This type allows puppet to manage postgresql.conf parameters.'
-
ensurable
newparam(:name) do
- desc 'The postgresql parameter name to manage.'
- isnamevar
+ desc 'A unique title for the resource.'
+ newvalues(%r{^[\w.]+$})
+ end
+ newparam(:key) do
+ desc 'The Postgresql parameter to manage.'
newvalues(%r{^[\w.]+$})
end
newproperty(:value) do
desc 'The value to set for this parameter.'
- end
+ newvalues(%r{^\S(.*\S)?$})
- newproperty(:target) do
- desc 'The path to postgresql.conf'
- defaultto do
- if @resource.class.defaultprovider.ancestors.include?(Puppet::Provider::ParsedFile)
- @resource.class.defaultprovider.default_target
+ munge do |value|
+ if value.to_i.to_s == value
+ value.to_i
+ elsif value.to_f.to_s == value
+ value.to_f
else
- nil
+ value
end
end
end
+
+ newproperty(:comment) do
+ desc 'The comment to set for this parameter.'
+ newvalues(%r{^[\w\W]+$})
+ end
+
+ newparam(:target) do
+ desc 'The path to the postgresql config file'
+ newvalues(%r{^/\S+[a-z0-9(/)-]*\w+.conf$})
+ end
end
diff --git a/manifests/server.pp b/manifests/server.pp
index 89d45fb7d5..2516e43611 100644
--- a/manifests/server.pp
+++ b/manifests/server.pp
@@ -167,7 +167,7 @@
Optional[String[1]] $locale = $postgresql::params::locale,
Optional[String[1]] $lc_messages = undef,
Optional[Boolean] $data_checksums = $postgresql::params::data_checksums,
- Optional[String[1]] $username = undef,
+ Optional[String[1]] $username = $user,
Optional[String[1]] $timezone = $postgresql::params::timezone,
Boolean $manage_pg_hba_conf = $postgresql::params::manage_pg_hba_conf,
diff --git a/manifests/server/config_entry.pp b/manifests/server/config_entry.pp
index 65cd68315c..d17b844a18 100644
--- a/manifests/server/config_entry.pp
+++ b/manifests/server/config_entry.pp
@@ -4,12 +4,14 @@
# @param key Defines the key/name for the setting. Defaults to $name
# @param value Defines the value for the setting.
# @param path Path for postgresql.conf
+# @param comment Defines the comment for the setting. The # is added by default.
#
define postgresql::server::config_entry (
- Enum['present', 'absent'] $ensure = 'present',
- String[1] $key = $name,
- Optional[Variant[String[1], Numeric, Array[String[1]]]] $value = undef,
- Stdlib::Absolutepath $path = $postgresql::server::postgresql_conf_path
+ Enum['present', 'absent'] $ensure = 'present',
+ String[1] $key = $name,
+ Optional[Variant[String[1], Numeric, Array[String[1]]]] $value = undef,
+ Stdlib::Absolutepath $path = $postgresql::server::postgresql_conf_path,
+ Optional[String[1]] $comment = undef,
) {
# Those are the variables that are marked as "(change requires restart)"
# on postgresql.conf. Items are ordered as on postgresql.conf.
@@ -85,8 +87,9 @@
postgresql_conf { $name:
ensure => $ensure,
target => $path,
- name => $key,
+ key => $key,
value => $value,
+ comment => $comment,
require => Class['postgresql::server::initdb'],
}
}
diff --git a/manifests/server/database.pp b/manifests/server/database.pp
index c48e01f805..7d95e76056 100644
--- a/manifests/server/database.pp
+++ b/manifests/server/database.pp
@@ -8,6 +8,7 @@
# @param encoding Overrides the character set during creation of the database.
# @param locale Overrides the locale during creation of the database.
# @param istemplate Defines the database as a template if set to true.
+# @param instance The name of the Postgresql database instance.
# @param connect_settings Specifies a hash of environment variables used when connecting to a remote server.
# @param psql_path Specifies the path to the psql command.
# @param default_db Specifies the name of the default database to connect with. On most systems this is 'postgres'.
@@ -23,6 +24,7 @@
Optional[String[1]] $encoding = $postgresql::server::encoding,
Optional[String[1]] $locale = $postgresql::server::locale,
Boolean $istemplate = false,
+ String[1] $instance = 'main',
Hash $connect_settings = $postgresql::server::default_connect_settings,
String[1] $user = $postgresql::server::user,
String[1] $group = $postgresql::server::group,
@@ -41,6 +43,7 @@
psql_path => $psql_path,
port => $port_override,
connect_settings => $connect_settings,
+ instance => $instance,
}
# Optionally set the locale switch. Older versions of createdb may not accept
diff --git a/manifests/server/db.pp b/manifests/server/db.pp
index 01cc61b665..513e548ed7 100644
--- a/manifests/server/db.pp
+++ b/manifests/server/db.pp
@@ -14,6 +14,7 @@
# @param port Specifies the port where the PostgreSQL server is listening on.
# @param psql_user Overrides the default PostgreSQL super user and owner of PostgreSQL related files in the file system.
# @param psql_group Overrides the default PostgreSQL user group to be used for related files in the file system.
+# @param instance The name of the Postgresql database instance.
define postgresql::server::db (
String[1] $user,
Optional[Variant[String, Sensitive[String]]] $password = undef,
@@ -29,6 +30,7 @@
Optional[Stdlib::Port] $port = undef,
String[1] $psql_user = $postgresql::server::user,
String[1] $psql_group = $postgresql::server::group,
+ String[1] $instance = 'main',
) {
if ! defined(Postgresql::Server::Database[$dbname]) {
postgresql::server::database { $dbname:
diff --git a/manifests/server/default_privileges.pp b/manifests/server/default_privileges.pp
index 771c86cd58..815abaebbd 100644
--- a/manifests/server/default_privileges.pp
+++ b/manifests/server/default_privileges.pp
@@ -12,6 +12,7 @@
# @param psql_path Specifies the OS user for running psql. Default value: The default user for the module, usually 'postgres'.
# @param port Specifies the port to access the server. Default value: The default user for the module, usually '5432'.
# @param connect_settings Specifies a hash of environment variables used when connecting to a remote server.
+# @param instance The name of the Postgresql database instance.
# @param group Specifies the user group to which the privileges will be granted.
define postgresql::server::default_privileges (
String $role,
@@ -34,6 +35,7 @@
String $group = $postgresql::server::group,
Stdlib::Absolutepath $psql_path = $postgresql::server::psql_path,
Optional[String] $target_role = undef,
+ String[1] $instance = 'main',
) {
$version = pick($connect_settings['DBVERSION'],postgresql::default('version'))
$port_override = pick($connect_settings['PGPORT'], $port)
@@ -160,6 +162,7 @@
psql_path => $psql_path,
unless => $unless_cmd,
environment => 'PGOPTIONS=--client-min-messages=error',
+ instance => $instance,
}
if defined(Postgresql::Server::Role[$role]) {
diff --git a/manifests/server/extension.pp b/manifests/server/extension.pp
index 79dfd3b126..196c077c0b 100644
--- a/manifests/server/extension.pp
+++ b/manifests/server/extension.pp
@@ -21,6 +21,7 @@
# @param port Port to use when connecting.
# @param connect_settings Specifies a hash of environment variables used when connecting to a remote server.
# @param database_resource_name Specifies the resource name of the DB being managed. Defaults to the parameter $database, if left blank.
+# @param instance The name of the Postgresql database instance.
# @param psql_path Specifies the path to the psql command.
# @param user Overrides the default PostgreSQL super user and owner of PostgreSQL related files in the file system.
# @param group Overrides the default postgres user group to be used for related files in the file system.
@@ -35,6 +36,7 @@
Stdlib::Port $port = postgresql::default('port'),
Hash $connect_settings = postgresql::default('default_connect_settings'),
String[1] $database_resource_name = $database,
+ String[1] $instance = 'main',
String[1] $user = postgresql::default('user'),
String[1] $group = postgresql::default('group'),
Stdlib::Absolutepath $psql_path = postgresql::default('psql_path'),
@@ -86,6 +88,7 @@
db => $database,
port => $port_override,
command => $command,
+ instance => $instance,
unless => "SELECT 1 WHERE ${unless_mod}EXISTS (SELECT 1 FROM pg_extension WHERE extname = '${extension}')",
require => $psql_cmd_require,
before => $psql_cmd_before,
@@ -113,6 +116,7 @@
connect_settings => $connect_settings,
db => $database,
port => $port_override,
+ instance => $instance,
require => Postgresql_psql["${database}: ${command}"],
}
@@ -146,6 +150,7 @@
psql_path => $psql_path,
connect_settings => $connect_settings,
command => $alter_extension_sql,
+ instance => $instance,
unless => $update_unless,
}
}
diff --git a/manifests/server/grant.pp b/manifests/server/grant.pp
index 68591851bb..e9c0894003 100644
--- a/manifests/server/grant.pp
+++ b/manifests/server/grant.pp
@@ -18,6 +18,7 @@
# @param ensure Specifies whether to grant or revoke the privilege. Default is to grant the privilege. Valid values: 'present', 'absent'.
# @param group Sets the OS group to run psql
# @param psql_path Sets the path to psql command
+# @param instance The name of the Postgresql database instance.
define postgresql::server::grant (
String $role,
String $db,
@@ -47,6 +48,7 @@
Enum['present', 'absent'] $ensure = 'present',
String $group = $postgresql::server::group,
Stdlib::Absolutepath $psql_path = $postgresql::server::psql_path,
+ String[1] $instance = 'main',
) {
case $ensure {
default: {
@@ -470,6 +472,7 @@
psql_user => $psql_user,
psql_group => $group,
psql_path => $psql_path,
+ instance => $instance,
unless => $_unless,
onlyif => $_onlyif,
}
diff --git a/manifests/server/grant_role.pp b/manifests/server/grant_role.pp
index 4edf59ea0d..11ef6a70de 100644
--- a/manifests/server/grant_role.pp
+++ b/manifests/server/grant_role.pp
@@ -7,10 +7,12 @@
# @param psql_user Sets the OS user to run psql.
# @param port Port to use when connecting.
# @param connect_settings Specifies a hash of environment variables used when connecting to a remote server.
+# @param instance The name of the Postgresql database instance.
define postgresql::server::grant_role (
String[1] $group,
String[1] $role = $name,
Enum['present', 'absent'] $ensure = 'present',
+ String[1] $instance = 'main',
String[1] $psql_db = $postgresql::server::default_database,
String[1] $psql_user = $postgresql::server::user,
Stdlib::Port $port = $postgresql::server::port,
@@ -36,6 +38,7 @@
db => $psql_db,
psql_user => $psql_user,
port => $port,
+ instance => $instance,
connect_settings => $connect_settings,
}
diff --git a/manifests/server/instance/config.pp b/manifests/server/instance/config.pp
index 630bcff3e4..d596d0846b 100644
--- a/manifests/server/instance/config.pp
+++ b/manifests/server/instance/config.pp
@@ -94,7 +94,8 @@
if $pg_hba_conf_defaults {
Postgresql::Server::Pg_hba_rule {
database => 'all',
- user => 'all',
+ target => $pg_hba_conf_path,
+ user => 'all',
}
postgresql::server::pg_hba_rule {
@@ -135,6 +136,10 @@
auth_method => $_pg_hba_auth_password_encryption,
order => 101;
}
+ } else {
+ Postgresql::Server::Pg_hba_rule {
+ target => $pg_hba_conf_path,
+ }
}
# $ipv4acls and $ipv6acls are arrays of rule strings
@@ -148,6 +153,11 @@
}
}
}
+ # set default postgresql_conf_path here so the path is configurable in instances for
+ # default values like port or listen_address
+ Postgresql::Server::Config_entry {
+ path => $postgresql_conf_path,
+ }
if $manage_postgresql_conf_perms {
file { $postgresql_conf_path:
@@ -242,12 +252,11 @@
notify => Class['postgresql::server::reload'],
}
}
- # RHEL based systems and Gentoo need variables set for $PGPORT, $DATA_DIR or $PGDATA via a drop-in file
- if $facts['os']['family'] == 'RedHat' or ($facts['os']['family'] == 'Gentoo' and $facts['service_provider'] == 'systemd') {
- postgresql::server::instance::systemd { $service_name:
- port => $port,
- datadir => $datadir,
- extra_systemd_config => $extra_systemd_config,
- }
+
+ postgresql::server::instance::systemd { $name:
+ port => $port,
+ datadir => $datadir,
+ extra_systemd_config => $extra_systemd_config,
+ service_name => $service_name,
}
}
diff --git a/manifests/server/instance/late_initdb.pp b/manifests/server/instance/late_initdb.pp
index 05a93f81a6..bc011b9a01 100644
--- a/manifests/server/instance/late_initdb.pp
+++ b/manifests/server/instance/late_initdb.pp
@@ -25,6 +25,7 @@
psql_group => $group,
psql_path => $psql_path,
port => $port,
+ instance => $name,
cwd => $module_workdir,
}
diff --git a/manifests/server/instance/systemd.pp b/manifests/server/instance/systemd.pp
index d3f217e09e..b9a46a2336 100644
--- a/manifests/server/instance/systemd.pp
+++ b/manifests/server/instance/systemd.pp
@@ -5,26 +5,36 @@
define postgresql::server::instance::systemd (
Stdlib::Port $port,
Stdlib::Absolutepath $datadir,
+ String[1] $instance_name = $name,
Optional[String[1]] $extra_systemd_config = undef,
String[1] $service_name = $name,
Enum[present, absent] $drop_in_ensure = 'present',
) {
- # Template uses:
- # - $port
- # - $datadir
- # - $extra_systemd_config
- systemd::dropin_file { "${service_name}.conf":
- ensure => $drop_in_ensure,
- unit => "${service_name}.service",
- owner => 'root',
- group => 'root',
- content => epp('postgresql/systemd-override.conf.epp', {
- port => $port,
- datadir => $datadir,
- extra_systemd_config => $extra_systemd_config,
+ if $facts['service_provider'] == 'systemd' {
+ if $facts['os']['family'] in ['RedHat', 'Gentoo'] {
+ # RHEL 7 and 8 both support drop-in files for systemd units.
+ # Gentoo also supports drop-in files.
+ # RHEL based Systems need Variables set for $PGPORT, $DATA_DIR or $PGDATA, thats what the drop-in file is for.
+ # For additional instances (!= 'main') we need a new systemd service anyhow and use one systemd-file. no dropin needed.
+ #
+ # Template uses:
+ # - $port
+ # - $datadir
+ # - $extra_systemd_config
+ systemd::dropin_file { "${service_name}.conf":
+ ensure => $drop_in_ensure,
+ unit => "${service_name}.service",
+ owner => 'root',
+ group => 'root',
+ content => epp('postgresql/systemd-override.conf.epp', {
+ port => $port,
+ datadir => $datadir,
+ extra_systemd_config => $extra_systemd_config,
+ }
+ ),
+ notify => Class['postgresql::server::service'],
+ before => Class['postgresql::server::reload'],
}
- ),
- notify => Class['postgresql::server::service'],
- before => Class['postgresql::server::reload'],
+ }
}
}
diff --git a/manifests/server/pg_hba_rule.pp b/manifests/server/pg_hba_rule.pp
index 1144327951..e7945669e0 100644
--- a/manifests/server/pg_hba_rule.pp
+++ b/manifests/server/pg_hba_rule.pp
@@ -32,9 +32,6 @@
String[1] $description = 'none',
Optional[String] $auth_option = undef,
Variant[String, Integer] $order = 150,
-
- # Needed for testing primarily, support for multiple files is not really
- # working.
Stdlib::Absolutepath $target = $postgresql::server::pg_hba_conf_path,
String $postgresql_version = $postgresql::server::_version
) {
diff --git a/manifests/server/reassign_owned_by.pp b/manifests/server/reassign_owned_by.pp
index 30d8729318..ce98f2601b 100644
--- a/manifests/server/reassign_owned_by.pp
+++ b/manifests/server/reassign_owned_by.pp
@@ -10,6 +10,7 @@
# @param connect_settings Specifies a hash of environment variables used when connecting to a remote server.
# @param group Sets the OS group to run psql
# @param psql_path Sets the path to psql command
+# @param instance The name of the Postgresql database instance.
define postgresql::server::reassign_owned_by (
String $old_role,
String $new_role,
@@ -19,6 +20,7 @@
Hash $connect_settings = $postgresql::server::default_connect_settings,
String[1] $group = $postgresql::server::group,
Stdlib::Absolutepath $psql_path = $postgresql::server::psql_path,
+ String[1] $instance = 'main',
) {
$sql_command = "REASSIGN OWNED BY \"${old_role}\" TO \"${new_role}\""
@@ -43,6 +45,7 @@
psql_user => $psql_user,
psql_group => $group,
psql_path => $psql_path,
+ instance => $instance,
onlyif => $onlyif,
}
diff --git a/manifests/server/role.pp b/manifests/server/role.pp
index 91d07e7798..1b37ce282c 100644
--- a/manifests/server/role.pp
+++ b/manifests/server/role.pp
@@ -23,6 +23,7 @@
# May need to specify if '/tmp' is on volume mounted with noexec option.
# @param hash Specify the hash method for pg password
# @param salt Specify the salt use for the scram-sha-256 encoding password (default username)
+# @param instance The name of the Postgresql database instance.
define postgresql::server::role (
Boolean $update_password = true,
Variant[Boolean, String, Sensitive[String]] $password_hash = false,
@@ -44,6 +45,7 @@
Enum['present', 'absent'] $ensure = 'present',
Optional[Enum['md5', 'scram-sha-256']] $hash = undef,
Optional[Variant[String[1], Integer]] $salt = undef,
+ String[1] $instance = 'main',
) {
$password_hash_unsensitive = if $password_hash =~ Sensitive[String] {
$password_hash.unwrap
@@ -54,14 +56,15 @@
$version = pick($connect_settings['DBVERSION'], postgresql::default('version'))
Postgresql_psql {
- db => $db,
- port => $port_override,
- psql_user => $psql_user,
- psql_group => $psql_group,
- psql_path => $psql_path,
+ 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 ****"],
+ instance => $instance,
+ cwd => $module_workdir,
+ require => Postgresql_psql["CREATE ROLE ${username} ENCRYPTED PASSWORD ****"],
}
if $ensure == 'present' {
diff --git a/manifests/server/schema.pp b/manifests/server/schema.pp
index 369f638c35..e8405792f7 100644
--- a/manifests/server/schema.pp
+++ b/manifests/server/schema.pp
@@ -15,6 +15,7 @@
# @param module_workdir
# Specifies working directory under which the psql command should be executed.
# May need to specify if '/tmp' is on volume mounted with noexec option.
+# @param instance The name of the Postgresql database instance.
# @example
# postgresql::server::schema {'private':
# db => 'template1',
@@ -29,6 +30,7 @@
String[1] $group = $postgresql::server::group,
Stdlib::Absolutepath $psql_path = $postgresql::server::psql_path,
Stdlib::Absolutepath $module_workdir = $postgresql::server::module_workdir,
+ String[1] $instance = 'main',
) {
Postgresql::Server::Db <| dbname == $db |> -> Postgresql::Server::Schema[$name]
@@ -36,13 +38,14 @@
$port_override = pick($connect_settings['PGPORT'], $port)
Postgresql_psql {
- db => $db,
- psql_user => $user,
- psql_group => $group,
- psql_path => $psql_path,
- port => $port_override,
- cwd => $module_workdir,
+ db => $db,
+ psql_user => $user,
+ psql_group => $group,
+ psql_path => $psql_path,
+ port => $port_override,
+ cwd => $module_workdir,
connect_settings => $connect_settings,
+ instance => $instance,
}
postgresql_psql { "${db}: CREATE SCHEMA \"${schema}\"":
diff --git a/manifests/server/tablespace.pp b/manifests/server/tablespace.pp
index 9f166cc7d2..2774732780 100644
--- a/manifests/server/tablespace.pp
+++ b/manifests/server/tablespace.pp
@@ -12,6 +12,7 @@
# @param module_workdir
# Specifies working directory under which the psql command should be executed.
# May need to specify if '/tmp' is on volume mounted with noexec option.
+# @param instance The name of the Postgresql database instance.
define postgresql::server::tablespace (
String[1] $location,
Boolean $manage_location = true,
@@ -23,6 +24,7 @@
String[1] $group = $postgresql::server::group,
Stdlib::Absolutepath $psql_path = $postgresql::server::psql_path,
String[1] $module_workdir = $postgresql::server::module_workdir,
+ String[1] $instance = 'main',
) {
# If the connection settings do not contain a port, then use the local server port
$port_override = pick($connect_settings['PGPORT'], $port)
@@ -34,6 +36,7 @@
port => $port_override,
connect_settings => $connect_settings,
cwd => $module_workdir,
+ instance => $instance,
}
if($manage_location) {
diff --git a/manifests/server_instance.pp b/manifests/server_instance.pp
new file mode 100644
index 0000000000..49d2bbb8f7
--- /dev/null
+++ b/manifests/server_instance.pp
@@ -0,0 +1,132 @@
+# @summary define to install and manage additional postgresql instances
+# @param instance_name The name of the instance.
+# @param instance_user The user to run the instance as.
+# @param instance_group The group to run the instance as.
+# @param instance_user_homedirectory The home directory of the instance user.
+# @param manage_instance_user_and_group Should Puppet manage the instance user and it's primary group?.
+# @param instance_directories directories needed for the instance. Option to manage the directory properties for each directory.
+# @param initdb_settings Specifies a hash witn parameters for postgresql::server::instance::initdb
+# @param config_settings Specifies a hash with parameters for postgresql::server::instance::config
+# @param service_settings Specifies a hash with parameters for postgresql::server:::instance::service
+# @param passwd_settings Specifies a hash with parameters for postgresql::server::instance::passwd
+# @param roles Specifies a hash from which to generate postgresql::server::role 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 databases Specifies a hash from which to generate postgresql::server::database resources.
+# @param databases_and_users Specifies a hash from which to generate postgresql::server::db resources.
+# @param database_grants Specifies a hash from which to generate postgresql::server::database_grant resources.
+# @param table_grants Specifies a hash from which to generate postgresql::server::table_grant resources.
+define postgresql::server_instance (
+ String[1] $instance_name = $name,
+ Boolean $manage_instance_user_and_group = true,
+ Hash $instance_directories = {},
+ String[1] $instance_user = $instance_name,
+ String[1] $instance_group = $instance_name,
+ Stdlib::Absolutepath $instance_user_homedirectory = "/opt/pgsql/data/home/${instance_user}",
+ Hash $initdb_settings = {},
+ Hash $config_settings = {},
+ Hash $service_settings = {},
+ Hash $passwd_settings = {},
+ Hash $roles = {},
+ Hash $config_entries = {},
+ Hash $pg_hba_rules = {},
+ Hash $databases_and_users = {},
+ Hash $databases = {},
+ Hash $database_grants = {},
+ Hash $table_grants = {},
+) {
+ unless($facts['os']['family'] == 'RedHat' and $facts['os']['release']['major'] == '8') {
+ warning('This define postgresql::server_instance is only tested on RHEL8')
+ }
+ $instance_directories.each |Stdlib::Absolutepath $directory, Hash $directory_settings| {
+ file { $directory:
+ * => $directory_settings,
+ }
+ }
+
+ if $manage_instance_user_and_group {
+ user { $instance_user:
+ managehome => true,
+ system => true,
+ home => $instance_user_homedirectory,
+ gid => $instance_group,
+ }
+ group { $instance_group:
+ system => true,
+ }
+ }
+ postgresql::server::instance::initdb { $instance_name:
+ * => $initdb_settings,
+ }
+ postgresql::server::instance::config { $instance_name:
+ * => $config_settings,
+ }
+ postgresql::server::instance::service { $instance_name:
+ * => $service_settings,
+ port => $config_settings['port'],
+ user => $instance_user,
+ }
+ postgresql::server::instance::passwd { $instance_name:
+ * => $passwd_settings,
+ }
+
+ $roles.each |$rolename, $role| {
+ postgresql::server::role { $rolename:
+ * => $role,
+ psql_user => $instance_user,
+ psql_group => $instance_group,
+ port => $config_settings['port'],
+ instance => $instance_name,
+ }
+ }
+
+ $config_entries.each |$entry, $settings| {
+ $value = $settings['value']
+ $comment = $settings['comment']
+ postgresql::server::config_entry { "${entry}_${$instance_name}":
+ ensure => bool2str($value =~ Undef, 'absent', 'present'),
+ key => $entry,
+ value => $value,
+ comment => $comment,
+ path => $config_settings['postgresql_conf_path'],
+ }
+ }
+ $pg_hba_rules.each |String[1] $rule_name, Postgresql::Pg_hba_rule $rule| {
+ $rule_title = "${rule_name} for instance ${name}"
+ postgresql::server::pg_hba_rule { $rule_title:
+ * => $rule,
+ target => $config_settings['pg_hba_conf_path'], # TODO: breaks if removed
+ }
+ }
+ $databases_and_users.each |$database, $database_details| {
+ postgresql::server::db { $database:
+ * => $database_details,
+ psql_user => $instance_user,
+ psql_group => $instance_group,
+ port => $config_settings['port'],
+ }
+ }
+ $databases.each |$database, $database_details| {
+ postgresql::server::database { $database:
+ * => $database_details,
+ user => $instance_user,
+ group => $instance_group,
+ port => $config_settings['port'],
+ }
+ }
+ $database_grants.each |$db_grant_title, $dbgrants| {
+ postgresql::server::database_grant { $db_grant_title:
+ * => $dbgrants,
+ psql_user => $instance_user,
+ psql_group => $instance_group,
+ port => $config_settings['port'],
+ }
+ }
+ $table_grants.each |$table_grant_title, $tgrants| {
+ postgresql::server::table_grant { $table_grant_title:
+ * => $tgrants,
+ psql_user => $instance_user,
+ port => $config_settings['port'],
+ }
+ }
+}
diff --git a/spec/acceptance/server_instance_spec.rb b/spec/acceptance/server_instance_spec.rb
new file mode 100644
index 0000000000..93192bafb3
--- /dev/null
+++ b/spec/acceptance/server_instance_spec.rb
@@ -0,0 +1,161 @@
+# frozen_string_literal: true
+
+# run a test task
+require 'spec_helper_acceptance'
+
+describe 'postgresql instance test1', if: os[:family] == 'redhat' && os[:release].start_with?('8') do
+ pp = <<-MANIFEST
+ # set global defaults
+ class { 'postgresql::globals':
+ encoding => 'UTF-8',
+ locale => 'en_US.UTF-8',
+ manage_package_repo => false,
+ manage_dnf_module => true,
+ needs_initdb => true,
+ version => '13',
+ }
+ # stop default main instance
+ class { 'postgresql::server':
+ service_ensure => 'stopped',
+ service_enable => false,
+ }
+ # define instance test1
+ postgresql::server_instance { 'test1':
+ instance_user => 'ins_test1',
+ instance_group => 'ins_test1',
+ instance_directories => {
+ '/opt/pgsql' => { 'ensure' => 'directory' },
+ '/opt/pgsql/backup' => { 'ensure' => 'directory' },
+ '/opt/pgsql/data' => { 'ensure' => 'directory' },
+ '/opt/pgsql/data/13' => { 'ensure' => 'directory' },
+ '/opt/pgsql/data/home' => { 'ensure' => 'directory' },
+ '/opt/pgsql/wal' => { 'ensure' => 'directory' },
+ '/opt/pgsql/log' => { 'ensure' => 'directory' },
+ '/opt/pgsql/log/13' => { 'ensure' => 'directory' },
+ '/opt/pgsql/log/13/test1' => { 'ensure' => 'directory' },
+ },
+ config_settings => {
+ 'pg_hba_conf_path' => '/opt/pgsql/data/13/test1/pg_hba.conf',
+ 'postgresql_conf_path' => '/opt/pgsql/data/13/test1/postgresql.conf',
+ 'pg_ident_conf_path' => '/opt/pgsql/data/13/test1/pg_ident.conf',
+ 'datadir' => '/opt/pgsql/data/13/test1',
+ 'service_name' => 'postgresql@13-test1',
+ 'port' => 5433,
+ 'pg_hba_conf_defaults' => false,
+ 'manage_selinux' => true,
+ },
+ service_settings => {
+ 'service_name' => 'postgresql@13-test1',
+ 'service_status' => 'systemctl status postgresql@13-test1.service',
+ 'service_ensure' => 'running',
+ 'service_enable' => true,
+ },
+ initdb_settings => {
+ 'auth_local' => 'peer',
+ 'auth_host' => 'md5',
+ 'needs_initdb' => true,
+ 'datadir' => '/opt/pgsql/data/13/test1',
+ 'encoding' => 'UTF-8',
+ 'lc_messages' => 'en_US.UTF8',
+ 'locale' => 'en_US.UTF8',
+ 'data_checksums' => false,
+ 'group' => 'postgres',
+ 'user' => 'postgres',
+ 'username' => 'ins_test1',
+ },
+ config_entries => {
+ 'authentication_timeout' => {
+ 'value' => '1min',
+ 'comment' => 'a test',
+ },
+ 'log_statement_stats' => { 'value' => 'off' },
+ 'autovacuum_vacuum_scale_factor' => { 'value' => 0.3 },
+ },
+ databases => {
+ 'testdb1' => {
+ 'encoding' => 'UTF8',
+ 'locale' => 'en_US.UTF8',
+ 'owner' => 'dba_test1',
+ },
+ 'testdb2' => {
+ 'encoding' => 'UTF8',
+ 'locale' => 'en_US.UTF8',
+ 'owner' => 'dba_test1',
+ },
+ },
+ roles => {
+ 'ins_test1' => {
+ 'superuser' => true,
+ 'login' => true,
+ },
+ 'dba_test1' => {
+ 'createdb' => true,
+ 'login' => true,
+ },
+ 'app_test1' => { 'login' => true },
+ 'rep_test1' => {
+ 'replication' => true,
+ 'login' => true,
+ },
+ 'rou_test1' => { 'login' => true },
+ },
+ pg_hba_rules => {
+ 'local all INSTANCE user' => {
+ 'type' => 'local',
+ 'database' => 'all',
+ 'user' => 'ins_test1',
+ 'auth_method' => 'peer',
+ 'order' => 1,
+ },
+ 'local all DB user' => {
+ 'type' => 'local',
+ 'database' => 'all',
+ 'user' => 'dba_test1',
+ 'auth_method' => 'peer',
+ 'order' => 2,
+ },
+ 'local all APP user' => {
+ 'type' => 'local',
+ 'database' => 'all',
+ 'user' => 'app_test1',
+ 'auth_method' => 'peer',
+ 'order' => 3,
+ },
+ 'local all READONLY user' => {
+ 'type' => 'local',
+ 'database' => 'all',
+ 'user' => 'rou_test1',
+ 'auth_method' => 'peer',
+ 'order' => 4,
+ },
+ 'remote all INSTANCE user PGADMIN server' => {
+ 'type' => 'host',
+ 'database' => 'all',
+ 'user' => 'ins_test1',
+ 'address' => '192.168.22.131/32',
+ 'auth_method' => 'md5',
+ 'order' => 5,
+ },
+ 'local replication INSTANCE user' => {
+ 'type' => 'local',
+ 'database' => 'replication',
+ 'user' => 'ins_test1',
+ 'auth_method' => 'peer',
+ 'order' => 6,
+ },
+ 'local replication REPLICATION user' => {
+ 'type' => 'local',
+ 'database' => 'replication',
+ 'user' => 'rep_test1',
+ 'auth_method' => 'peer',
+ 'order' => 7,
+ },
+ },
+ }
+ MANIFEST
+
+ it 'installs postgres instance test1' do
+ export_locales('en_US.UTF-8 ')
+ apply_manifest(pp, catch_failures: true)
+ end
+end
diff --git a/spec/defines/server_instance_spec.rb b/spec/defines/server_instance_spec.rb
new file mode 100644
index 0000000000..89eadb06c8
--- /dev/null
+++ b/spec/defines/server_instance_spec.rb
@@ -0,0 +1,223 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+
+describe 'postgresql::server_instance' do
+ include_examples 'RedHat 8'
+
+ let :pre_condition do
+ "class { 'postgresql::globals':
+ encoding => 'UTF-8',
+ locale => 'en_US.UTF-8',
+ manage_package_repo => false,
+ manage_dnf_module => true,
+ needs_initdb => true,
+ version => '13',
+ }
+ # stop default main instance
+ class { 'postgresql::server':
+ service_ensure => 'stopped',
+ service_enable => false,
+ }"
+ end
+ let(:title) { 'test1' }
+ let(:params) do
+ {
+ 'instance_user': 'ins_test1',
+ 'instance_group': 'ins_test1',
+ 'instance_directories': { '/opt/pgsql': { 'ensure' => 'directory' },
+ '/opt/pgsql/backup': { 'ensure' => 'directory' },
+ '/opt/pgsql/data': { 'ensure' => 'directory' },
+ '/opt/pgsql/data/13': { 'ensure' => 'directory' },
+ '/opt/pgsql/data/home': { 'ensure' => 'directory' },
+ '/opt/pgsql/wal': { 'ensure' => 'directory' },
+ '/opt/pgsql/log': { 'ensure' => 'directory' },
+ '/opt/pgsql/log/13': { 'ensure' => 'directory' },
+ '/opt/pgsql/log/13/test1': { 'ensure' => 'directory' }, },
+ 'config_settings': { 'pg_hba_conf_path' => '/opt/pgsql/data/13/test1/pg_hba.conf',
+ 'postgresql_conf_path' => '/opt/pgsql/data/13/test1/postgresql.conf',
+ 'pg_ident_conf_path' => '/opt/pgsql/data/13/test1/pg_ident.conf',
+ 'datadir' => '/opt/pgsql/data/13/test1',
+ 'service_name' => 'postgresql@13-test1',
+ 'port' => 5433,
+ 'pg_hba_conf_defaults' => false },
+ 'service_settings': { 'service_name' => 'postgresql@13-test1',
+ 'service_status' => 'systemctl status postgresql@13-test1.service',
+ 'service_ensure' => 'running',
+ 'service_enable' => true },
+ 'initdb_settings': { 'auth_local' => 'peer',
+ 'auth_host' => 'md5',
+ 'needs_initdb' => true,
+ 'datadir' => '/opt/pgsql/data/13/test1',
+ 'encoding' => 'UTF-8',
+ 'lc_messages' => 'en_US.UTF8',
+ 'locale' => 'en_US.UTF8',
+ 'data_checksums' => false,
+ 'group' => 'postgres',
+ 'user' => 'postgres',
+ 'username' => 'ins_test1' },
+ 'config_entries': { 'authentication_timeout': { 'value' => '1min',
+ 'comment' => 'a test' },
+ 'log_statement_stats': { 'value' => 'off' },
+ 'autovacuum_vacuum_scale_factor': { 'value' => 0.3 }, },
+ 'databases': { 'testdb1': { 'encoding' => 'UTF8',
+ 'locale' => 'en_US.UTF8',
+ 'owner' => 'dba_test1' },
+ 'testdb2': { 'encoding' => 'UTF8',
+ 'locale' => 'en_US.UTF8',
+ 'owner' => 'dba_test1' }, },
+ 'roles': { 'ins_test1': { 'superuser' => true,
+ 'login' => true, },
+ 'dba_test1': { 'createdb' => true,
+ 'login' => true, },
+ 'app_test1': { 'login' => true },
+ 'rep_test1': { 'replication' => true,
+ 'login' => true },
+ 'rou_test1': { 'login' => true }, },
+ 'pg_hba_rules': { 'local all INSTANCE user': { 'type' => 'local',
+ 'database' => 'all',
+ 'user' => 'ins_test1',
+ 'auth_method' => 'peer',
+ 'order' => 1 },
+ 'local all DB user': { 'type' => 'local',
+ 'database' => 'all',
+ 'user' => 'dba_test1',
+ 'auth_method' => 'peer',
+ 'order' => 2 },
+ 'local all APP user': { 'type' => 'local',
+ 'database' => 'all',
+ 'user' => 'app_test1',
+ 'auth_method' => 'peer',
+ 'order' => 3 },
+ 'local all READONLY user': { 'type' => 'local',
+ 'database' => 'all',
+ 'user' => 'rou_test1',
+ 'auth_method' => 'peer',
+ 'order' => 4 },
+ 'remote all INSTANCE user PGADMIN server': { 'type' => 'host',
+ 'database' => 'all',
+ 'user' => 'ins_test1',
+ 'address' => '192.168.22.131/32',
+ 'auth_method' => 'md5',
+ 'order' => 5 },
+ 'local replication INSTANCE user': { 'type' => 'local',
+ 'database' => 'replication',
+ 'user' => 'ins_test1',
+ 'auth_method' => 'peer',
+ 'order' => 6 },
+ 'local replication REPLICATION user': { 'type' => 'local',
+ 'database' => 'replication',
+ 'user' => 'rep_test1',
+ 'auth_method' => 'peer',
+ 'order' => 7 }, },
+ }
+ end
+
+ context 'with postgresql instance test1' do
+ it { is_expected.to compile.with_all_deps }
+ it { is_expected.to contain_postgresql__server_instance('test1') }
+ it { is_expected.to contain_user('ins_test1') }
+ it { is_expected.to contain_group('ins_test1') }
+ it { is_expected.to contain_service('postgresqld_instance_test1').with_name('postgresql@13-test1').with_status('systemctl status postgresql@13-test1.service') }
+ it { is_expected.to contain_systemd__dropin_file('postgresql@13-test1.conf') }
+ it { is_expected.to contain_postgresql_conn_validator('validate_service_is_running_instance_test1') }
+ it { is_expected.to contain_postgresql_conf('port_for_instance_test1') }
+ it { is_expected.to contain_postgresql_conf('log_statement_stats_test1') }
+ it { is_expected.to contain_postgresql_conf('data_directory_for_instance_test1') }
+ it { is_expected.to contain_postgresql_conf('autovacuum_vacuum_scale_factor_test1') }
+ it { is_expected.to contain_postgresql_conf('authentication_timeout_test1') }
+ it { is_expected.to contain_postgresql__server__role('app_test1') }
+ it { is_expected.to contain_postgresql__server__role('dba_test1') }
+ it { is_expected.to contain_postgresql__server__role('ins_test1') }
+ it { is_expected.to contain_postgresql__server__role('rep_test1') }
+ it { is_expected.to contain_postgresql__server__role('rou_test1') }
+ it { is_expected.to contain_anchor('postgresql::server::service::begin::test1') }
+ it { is_expected.to contain_anchor('postgresql::server::service::end::test1') }
+ it { is_expected.to contain_class('Postgresql::Dnfmodule') }
+ it { is_expected.to contain_class('Postgresql::Server::Install') }
+ it { is_expected.to contain_class('Postgresql::Server::Reload') }
+ it { is_expected.to contain_concat__fragment('pg_hba_rule_local all APP user for instance test1') }
+ it { is_expected.to contain_concat__fragment('pg_hba_rule_local all DB user for instance test1') }
+ it { is_expected.to contain_concat__fragment('pg_hba_rule_local all INSTANCE user for instance test1') }
+ it { is_expected.to contain_concat__fragment('pg_hba_rule_local all READONLY user for instance test1') }
+ it { is_expected.to contain_concat__fragment('pg_hba_rule_local replication INSTANCE user for instance test1') }
+ it { is_expected.to contain_concat__fragment('pg_hba_rule_local replication REPLICATION user for instance test1') }
+ it { is_expected.to contain_concat__fragment('pg_hba_rule_remote all INSTANCE user PGADMIN server for instance test1') }
+ it { is_expected.to contain_concat('/opt/pgsql/data/13/test1/pg_hba.conf') }
+ it { is_expected.to contain_concat('/opt/pgsql/data/13/test1/pg_ident.conf') }
+ it { is_expected.to contain_exec('postgresql_initdb_instance_test1') }
+ it { is_expected.to contain_file('/opt/pgsql/backup') }
+ it { is_expected.to contain_file('/opt/pgsql/data/13/test1/postgresql.conf') }
+ it { is_expected.to contain_file('/opt/pgsql/data/13/test1') }
+ it { is_expected.to contain_file('/opt/pgsql/data/13') }
+ it { is_expected.to contain_file('/opt/pgsql/data/home') }
+ it { is_expected.to contain_file('/opt/pgsql/data') }
+ it { is_expected.to contain_file('/opt/pgsql/log/13/test1') }
+ it { is_expected.to contain_file('/opt/pgsql/log/13') }
+ it { is_expected.to contain_file('/opt/pgsql/log') }
+ it { is_expected.to contain_file('/opt/pgsql/wal') }
+ it { is_expected.to contain_file('/opt/pgsql') }
+ it { is_expected.to contain_postgresql__server__config_entry('authentication_timeout_test1') }
+ it { is_expected.to contain_postgresql__server__config_entry('autovacuum_vacuum_scale_factor_test1') }
+ it { is_expected.to contain_postgresql__server__config_entry('data_directory_for_instance_test1') }
+ it { is_expected.to contain_postgresql__server__config_entry('log_statement_stats_test1') }
+ it { is_expected.to contain_postgresql__server__config_entry('password_encryption_for_instance_test1') }
+ it { is_expected.to contain_postgresql__server__config_entry('port_for_instance_test1') }
+ it { is_expected.to contain_postgresql__server__database('testdb1') }
+ it { is_expected.to contain_postgresql__server__database('testdb2') }
+ it { is_expected.to contain_postgresql__server__instance__config('test1') }
+ it { is_expected.to contain_postgresql__server__instance__initdb('test1') }
+ it { is_expected.to contain_postgresql__server__instance__passwd('test1') }
+ it { is_expected.to contain_postgresql__server__instance__service('test1') }
+ it { is_expected.to contain_postgresql__server__instance__systemd('test1') }
+ it { is_expected.to contain_postgresql__server__pg_hba_rule('local all APP user for instance test1') }
+ it { is_expected.to contain_postgresql__server__pg_hba_rule('local all DB user for instance test1') }
+ it { is_expected.to contain_postgresql__server__pg_hba_rule('local all INSTANCE user for instance test1') }
+ it { is_expected.to contain_postgresql__server__pg_hba_rule('local all READONLY user for instance test1') }
+ it { is_expected.to contain_postgresql__server__pg_hba_rule('local replication INSTANCE user for instance test1') }
+ it { is_expected.to contain_postgresql__server__pg_hba_rule('local replication REPLICATION user for instance test1') }
+ it { is_expected.to contain_postgresql__server__pg_hba_rule('remote all INSTANCE user PGADMIN server for instance test1') }
+ it { is_expected.to contain_postgresql_psql('ALTER DATABASE "testdb1" OWNER TO "dba_test1"') }
+ it { is_expected.to contain_postgresql_psql('ALTER DATABASE "testdb2" OWNER TO "dba_test1"') }
+ it { is_expected.to contain_postgresql_psql('ALTER ROLE "app_test1" CONNECTION LIMIT -1') }
+ it { is_expected.to contain_postgresql_psql('ALTER ROLE "app_test1" INHERIT') }
+ it { is_expected.to contain_postgresql_psql('ALTER ROLE "app_test1" LOGIN') }
+ it { is_expected.to contain_postgresql_psql('ALTER ROLE "app_test1" NOCREATEDB') }
+ it { is_expected.to contain_postgresql_psql('ALTER ROLE "app_test1" NOCREATEROLE') }
+ it { is_expected.to contain_postgresql_psql('ALTER ROLE "app_test1" NOREPLICATION') }
+ it { is_expected.to contain_postgresql_psql('ALTER ROLE "app_test1" NOSUPERUSER') }
+ it { is_expected.to contain_postgresql_psql('ALTER ROLE "dba_test1" CONNECTION LIMIT -1') }
+ it { is_expected.to contain_postgresql_psql('ALTER ROLE "dba_test1" CREATEDB') }
+ it { is_expected.to contain_postgresql_psql('ALTER ROLE "dba_test1" INHERIT') }
+ it { is_expected.to contain_postgresql_psql('ALTER ROLE "dba_test1" LOGIN') }
+ it { is_expected.to contain_postgresql_psql('ALTER ROLE "dba_test1" NOCREATEROLE') }
+ it { is_expected.to contain_postgresql_psql('ALTER ROLE "dba_test1" NOREPLICATION') }
+ it { is_expected.to contain_postgresql_psql('ALTER ROLE "dba_test1" NOSUPERUSER') }
+ it { is_expected.to contain_postgresql_psql('ALTER ROLE "ins_test1" CONNECTION LIMIT -1') }
+ it { is_expected.to contain_postgresql_psql('ALTER ROLE "ins_test1" INHERIT') }
+ it { is_expected.to contain_postgresql_psql('ALTER ROLE "ins_test1" LOGIN') }
+ it { is_expected.to contain_postgresql_psql('ALTER ROLE "ins_test1" NOCREATEDB') }
+ it { is_expected.to contain_postgresql_psql('ALTER ROLE "ins_test1" NOCREATEROLE') }
+ it { is_expected.to contain_postgresql_psql('ALTER ROLE "ins_test1" NOREPLICATION') }
+ it { is_expected.to contain_postgresql_psql('ALTER ROLE "ins_test1" SUPERUSER') }
+ it { is_expected.to contain_postgresql_psql('ALTER ROLE "rep_test1" CONNECTION LIMIT -1') }
+ it { is_expected.to contain_postgresql_psql('ALTER ROLE "rep_test1" INHERIT') }
+ it { is_expected.to contain_postgresql_psql('ALTER ROLE "rep_test1" LOGIN') }
+ it { is_expected.to contain_postgresql_psql('ALTER ROLE "rep_test1" NOCREATEDB') }
+ it { is_expected.to contain_postgresql_psql('ALTER ROLE "rep_test1" NOCREATEROLE') }
+ it { is_expected.to contain_postgresql_psql('ALTER ROLE "rep_test1" NOSUPERUSER') }
+ it { is_expected.to contain_postgresql_psql('ALTER ROLE "rep_test1" REPLICATION') }
+ it { is_expected.to contain_postgresql_psql('ALTER ROLE "rou_test1" CONNECTION LIMIT -1') }
+ it { is_expected.to contain_postgresql_psql('ALTER ROLE "rou_test1" INHERIT') }
+ it { is_expected.to contain_postgresql_psql('ALTER ROLE "rou_test1" LOGIN') }
+ it { is_expected.to contain_postgresql_psql('ALTER ROLE "rou_test1" NOCREATEDB') }
+ it { is_expected.to contain_postgresql_psql('ALTER ROLE "rou_test1" NOCREATEROLE') }
+ it { is_expected.to contain_postgresql_psql('ALTER ROLE "rou_test1" NOREPLICATION') }
+ it { is_expected.to contain_postgresql_psql('ALTER ROLE "rou_test1" NOSUPERUSER') }
+ it { is_expected.to contain_postgresql_psql('CREATE ROLE app_test1 ENCRYPTED PASSWORD ****') }
+ it { is_expected.to contain_postgresql_psql('CREATE ROLE dba_test1 ENCRYPTED PASSWORD ****') }
+ it { is_expected.to contain_postgresql_psql('CREATE ROLE ins_test1 ENCRYPTED PASSWORD ****') }
+ it { is_expected.to contain_postgresql_psql('CREATE ROLE rep_test1 ENCRYPTED PASSWORD ****') }
+ it { is_expected.to contain_postgresql_psql('CREATE ROLE rou_test1 ENCRYPTED PASSWORD ****') }
+ end
+end
diff --git a/spec/unit/provider/postgresql_conf/parsed_spec.rb b/spec/unit/provider/postgresql_conf/parsed_spec.rb
deleted file mode 100644
index 7f6fdaef05..0000000000
--- a/spec/unit/provider/postgresql_conf/parsed_spec.rb
+++ /dev/null
@@ -1,151 +0,0 @@
-# frozen_string_literal: true
-
-require 'spec_helper'
-require 'tempfile'
-
-provider_class = Puppet::Type.type(:postgresql_conf).provider(:parsed)
-
-describe provider_class do
- let(:title) { 'postgresql_conf' }
- let(:provider) do
- conf_class = Puppet::Type.type(:postgresql_conf)
- provider = conf_class.provider(:parsed)
- conffile = tmpfilename('postgresql.conf')
- allow_any_instance_of(provider).to receive(:target).and_return conffile # rubocop:disable RSpec/AnyInstance
- provider
- end
-
- after :each do
- provider.initvars
- end
-
- describe 'simple configuration that should be allowed' do
- it 'parses a simple ini line' do
- expect(provider.parse_line("listen_addreses = '*'")).to eq(
- name: 'listen_addreses', value: '*', comment: nil, record_type: :parsed,
- )
- end
-
- it 'parses a simple ini line (2)' do
- expect(provider.parse_line(" listen_addreses = '*'")).to eq(
- name: 'listen_addreses', value: '*', comment: nil, record_type: :parsed,
- )
- end
-
- it 'parses a simple ini line (3)' do
- expect(provider.parse_line("listen_addreses = '*' # dont mind me")).to eq(
- name: 'listen_addreses', value: '*', comment: 'dont mind me', record_type: :parsed,
- )
- end
-
- it 'parses a comment' do
- expect(provider.parse_line('# dont mind me')).to eq(
- line: '# dont mind me', record_type: :comment,
- )
- end
-
- it 'parses a comment (2)' do
- expect(provider.parse_line(" \t# dont mind me")).to eq(
- line: " \t# dont mind me", record_type: :comment,
- )
- end
-
- it 'allows includes' do
- expect(provider.parse_line('include puppetextra')).to eq(
- name: 'include', value: 'puppetextra', comment: nil, record_type: :parsed,
- )
- end
-
- it 'allows numbers through without quotes' do
- expect(provider.parse_line('wal_keep_segments = 32')).to eq(
- name: 'wal_keep_segments', value: '32', comment: nil, record_type: :parsed,
- )
- end
-
- it 'allows blanks through' do
- expect(provider.parse_line('')).to eq(
- line: '', record_type: :blank,
- )
- end
-
- it 'parses keys with dots' do
- expect(provider.parse_line('auto_explain.log_min_duration = 1ms')).to eq(
- name: 'auto_explain.log_min_duration', value: '1ms', comment: nil, record_type: :parsed,
- )
- end
- end
-
- describe 'configuration that should be set' do
- it 'sets comment lines' do
- expect(provider.to_line(line: '# dont mind me', record_type: :comment)).to eq(
- '# dont mind me',
- )
- end
-
- it 'sets blank lines' do
- expect(provider.to_line(line: '', record_type: :blank)).to eq(
- '',
- )
- end
-
- it 'sets simple configuration' do
- expect(provider.to_line(name: 'listen_addresses', value: '*', comment: nil, record_type: :parsed)).to eq(
- "listen_addresses = '*'",
- )
- end
-
- it 'sets simple configuration with period in name' do
- expect(provider.to_line(name: 'auto_explain.log_min_duration', value: '100ms', comment: nil, record_type: :parsed)).to eq(
- 'auto_explain.log_min_duration = 100ms',
- )
- end
-
- it 'sets simple configuration even with comments' do
- expect(provider.to_line(name: 'listen_addresses', value: '*', comment: 'dont mind me', record_type: :parsed)).to eq(
- "listen_addresses = '*' # dont mind me",
- )
- end
-
- it 'quotes includes' do
- expect(provider.to_line(name: 'include', value: 'puppetextra', comment: nil, record_type: :parsed)).to eq(
- "include 'puppetextra'",
- )
- end
-
- it 'quotes multiple words' do
- expect(provider.to_line(name: 'archive_command', value: 'rsync up', comment: nil, record_type: :parsed)).to eq(
- "archive_command = 'rsync up'",
- )
- end
-
- it 'does not quote numbers' do
- expect(provider.to_line(name: 'wal_segments', value: '32', comment: nil, record_type: :parsed)).to eq(
- 'wal_segments = 32',
- )
- end
-
- it 'allows numbers' do
- expect(provider.to_line(name: 'integer', value: 42, comment: nil, record_type: :parsed)).to eq(
- 'integer = 42',
- )
- end
-
- it 'allows floats' do
- expect(provider.to_line(name: 'float', value: 2.71828182845, comment: nil, record_type: :parsed)).to eq(
- 'float = 2.71828182845',
- )
- end
-
- it 'quotes single string address' do
- expect(provider.to_line(name: 'listen_addresses', value: '0.0.0.0', comment: nil, record_type: :parsed)).to eq(
- "listen_addresses = '0.0.0.0'",
- )
- end
-
- it 'quotes an array of addresses' do
- expect(provider.to_line(name: 'listen_addresses', value: ['0.0.0.0', '127.0.0.1'], comment: nil, record_type: :parsed)).to eq(
- "listen_addresses = '0.0.0.0, 127.0.0.1'",
- )
- end
- end
-end
diff --git a/spec/unit/provider/postgresql_conf/ruby_spec.rb b/spec/unit/provider/postgresql_conf/ruby_spec.rb
new file mode 100644
index 0000000000..11800b0fc7
--- /dev/null
+++ b/spec/unit/provider/postgresql_conf/ruby_spec.rb
@@ -0,0 +1,60 @@
+# frozen_string_literal: true
+
+require 'spec_helper'
+provider_class = Puppet::Type.type(:postgresql_conf).provider(:ruby)
+
+describe provider_class do
+ let(:resource) { Puppet::Type.type(:postgresql_conf).new(name: 'foo', value: 'bar') }
+ let(:provider) { resource.provider }
+
+ before(:each) do
+ allow(provider).to receive(:file_path).and_return('/tmp/foo')
+ allow(provider).to receive(:read_file).and_return('foo = bar')
+ allow(provider).to receive(:write_file).and_return(true)
+ end
+ # rubocop:enable RSpec/ReceiveMessages
+
+ it 'has a method parse_config' do
+ expect(provider).to respond_to(:parse_config)
+ end
+
+ it 'has a method delete_header' do
+ expect(provider).to respond_to(:delete_header)
+ end
+
+ it 'has a method add_header' do
+ expect(provider).to respond_to(:add_header)
+ end
+
+ it 'has a method exists?' do
+ expect(provider).to respond_to(:exists?)
+ end
+
+ it 'has a method create' do
+ expect(provider).to respond_to(:create)
+ end
+
+ it 'has a method destroy' do
+ expect(provider).to respond_to(:destroy)
+ end
+
+ it 'has a method value' do
+ expect(provider).to respond_to(:value)
+ end
+
+ it 'has a method value=' do
+ expect(provider).to respond_to(:value=)
+ end
+
+ it 'has a method comment' do
+ expect(provider).to respond_to(:comment)
+ end
+
+ it 'has a method comment=' do
+ expect(provider).to respond_to(:comment=)
+ end
+
+ it 'is an instance of the Provider Ruby' do
+ expect(provider).to be_an_instance_of Puppet::Type::Postgresql_conf::ProviderRuby
+ end
+end
diff --git a/spec/unit/type/postgresql_conf_spec.rb b/spec/unit/type/postgresql_conf_spec.rb
index 179c369740..9ce4269bfa 100644
--- a/spec/unit/type/postgresql_conf_spec.rb
+++ b/spec/unit/type/postgresql_conf_spec.rb
@@ -24,13 +24,13 @@
end
describe 'when validating attributes' do
- [:name, :provider].each do |param|
+ [:name, :provider, :target].each do |param|
it "has a #{param} parameter" do
expect(described_class.attrtype(param)).to eq(:param)
end
end
- [:value, :target].each do |property|
+ [:value, :comment].each do |property|
it "has a #{property} property" do
expect(described_class.attrtype(property)).to eq(:property)
end