diff --git a/.github/workflows/molecule.yml b/.github/workflows/molecule.yml index ddeeece..ef42adf 100644 --- a/.github/workflows/molecule.yml +++ b/.github/workflows/molecule.yml @@ -49,7 +49,7 @@ jobs: needs: - lint - setup - runs-on: ubuntu-20.04 + runs-on: ubuntu-22.04 strategy: fail-fast: false matrix: @@ -58,11 +58,11 @@ jobs: - 16 config: - name: rocky8 - image: "rockylinux" - tag: "8.9" + image: "rockylinux/rockylinux" + tag: "8.10" - name: rocky9 - image: "rockylinux" - tag: "9.3" + image: "rockylinux/rockylinux" + tag: "9.5" - name: debian11 image: "debian" tag: "11" diff --git a/.gitignore b/.gitignore index 1f274fa..a281698 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ .vscode/ test.yml env/ +.ansible/ diff --git a/README.md b/README.md index 8202cdf..8efd5b9 100644 --- a/README.md +++ b/README.md @@ -14,13 +14,14 @@ Install and configure PostgreSQL server on Debian and RedHat systems using this ## Table of Contents 1. [Role Requirements](#warning-requirements) -2. [Role Dependencies](#arrows_counterclockwise-dependencies) +2. [Role Dependencies](#arrows_counterclockwise-collection-dependencies) 3. [Role Installation](#zap-role-installation) 4. [Features and Tags](#available-features-and-tags) 6. [Supported Linux/PostgreSQL Versions](#linuxpostgresql-versions-supported) 5. [Role features in use](#role-features-in-use) - [Proxy usage](#proxy-usage) - [Installation](#installation) + - [Patroni integration](#patroni-integration) - [Configuration](#configuration) - [Auto tuning](#auto-tuning) - [Physical replication](#physical-replication) @@ -59,38 +60,39 @@ ansible-galaxy install claranet.postgresql ### Available features and tags ----- -This role support the following features and tags in the following order during execution: -Feature | Tag -------------------------------------|--------------------- -Uninstallation | uninstallation -Installation | install, installation -Datadir initialization | init,initialize,initialise -Auto tune (with pg-config.org) | autotune, auto-tune -Configuration | config, configure, configuration -Replication | repli, replication -Vacuum | vacuum -Backup | backup -User & membership management | user, users -Tablespace management | tblspc, tablespace, tablespaces -Database management | db, database, databases -Ownership & privileges management | owner, owners, ownership, priv, privs, privileges -Extensions management | ext, extension, extensions -SQL code executions | query, script +This role support the following features and tags along with control variables in the following order during execution: + +Feature | Control variable(s) | Tag(s) +------------------------------------|---------------------------------------------------------|------------------------ +Uninstallation | postgresql_uninstall_1, postgresql_uninstall_2 | uninstallation +Installation | postgresql_install | install, installation +Datadir initialization | postgresql_initialize | init,initialize,initialise +Auto tune (with pg-config.org) | postgresql_autotune | autotune, auto-tune +Configuration | postgresql_configure | config, configure, configuration +Replication | postgresql_replication, postgresql_configure_replication | repli, replication +Vacuum | postgresql_vacuum | vacuum +Backup | postgresql_backup | backup +User & membership management | postgresql_manage_objects | user, users +Tablespace management | postgresql_manage_objects | tblspc, tablespace, tablespaces +Database management | postgresql_manage_objects | db, database, databases +Ownership & privileges management | postgresql_manage_objects | owner, owners, ownership, priv, privs, privileges +Extensions management | postgresql_manage_objects | ext, extension, extensions +SQL code executions | postgresql_manage_objects | query, script Linux/PostgreSQL versions supported ----- -Linux/PostgreSQL | 12 | 13 | 14 | 15 | 16 -------------------|:----:|:----:|:----:|:----:|:----: -Debian 11 | Yes | Yes | Yes | Yes | Yes -Debian 12 | Yes | Yes | Yes | Yes | Yes -Ubuntu 20.04 | Yes | Yes | Yes | Yes | Yes -Ubuntu 22.04 | Yes | Yes | Yes | Yes | Yes -Ubuntu 24.04 | Yes | Yes | Yes | Yes | Yes -RockyLinux 8.9 | Yes | Yes | Yes | Yes | Yes -RockyLinux 9.3 | Yes | Yes | Yes | Yes | Yes -Fedora 38 | No | No | No | No | No +Linux/PostgreSQL | 12 | 13 | 14 | 15 | 16 | 17 +------------------|:----:|:----:|:----:|:----:|:----:|:----: +Debian 11 | Yes | Yes | Yes | Yes | Yes | Yes +Debian 12 | Yes | Yes | Yes | Yes | Yes | Yes +Ubuntu 20.04 | Yes | Yes | Yes | Yes | Yes | Yes +Ubuntu 22.04 | Yes | Yes | Yes | Yes | Yes | Yes +Ubuntu 24.04 | Yes | Yes | Yes | Yes | Yes | Yes +RockyLinux 8.9 | Yes | Yes | Yes | Yes | Yes | Yes +RockyLinux 9.3 | Yes | Yes | Yes | Yes | Yes | Yes +Fedora 38 | No | No | No | No | No | No ## Role features in use @@ -109,11 +111,11 @@ These variables are translated to environnement variables `http_proxy` and `http ### Installation ---- -_default PostgreSQL version is 15_ +_default PostgreSQL version is 16_ PostgreSQL and locales installation. ```yaml -postgresql_version: "15" +postgresql_version: "16" # Debian only. Used to generate the locales used by PostgreSQL databases. postgresql_locales: @@ -124,8 +126,33 @@ postgresql_locales: postgresql_locale_packages: - glibc-langpack-en - glibc-langpack-fr + +# Controls running tasks handling: postgreSQL packages installation +postgresql_install: true +``` + + +### Patroni integration +---- +When using Patroni to manage PostgreSQL replication, Patroni expects PostgreSQL packages be installed upfront. +However once the Patroni cluster is bootstrapped, the underlying PostgreSQL instances can be managed just like any other regular replication. + +In order to install PostgreSQL pacakges before bootstrapping a Patroni cluster this role can be invoked with the following variables which will cause the role to only perform installation. + +```yaml +postgresql_is_patroni: true +postgresql_install: true +postgresql_only_install: true ``` + +After Patroni bootstrap this role can be invoked with the following combination of variables to essentially skip the packages installation and manage the cluster like a pre configuration replication setup: +```yaml +postgresql_is_patroni: true +postgresql_install: false +``` + + ### Configuration ---- Example for configuration related variables: @@ -152,7 +179,8 @@ postgresql_hba_raw: | # Allow service restart for configuration changes that require it postgresql_config_change_allow_restart: true - +# Controls running tasks handling: configuration +postgresql_configure: true ``` _Notes:_ @@ -255,8 +283,12 @@ postgresql_pg_basebackup_walmethod: stream # none/stream/fetch postgresql_pg_basebackup_args: "" # Actual pg_basebackup built with the previous parameters -# DO NOT override this variable except you know what you are doing +# DO NOT override this variable unless you know what you are doing postgresql_pg_basebackup_cmd: {{ _postgresql_bin_path }}/pg_basebackup --no-password --host {{ postgresql_replication_primary_address }} --port {{ postgresql_replication_primary_port }} --username {{ postgresql_replication_user }} --pgdata {{ _postgresql_data_dir }} --checkpoint {{ postgresql_pg_basebackup_checkpoint }} {{ (postgresql_replication_slot != '') | ternary('--slot ' ~ postgresql_replication_slot, '') }} --wal-method {{ postgresql_pg_basebackup_walmethod }} --write-recovery-conf --verbose --progress {{ postgresql_pg_basebackup_args }} + +# Controls running tasks handling: actual replication configuration +# DO NOT override this variable unless you know what you are doing +postgresql_configure_replication: true ``` ### Vacuum @@ -572,6 +604,28 @@ postgresql_tempfile_mode: '0644' postgresql_tempfile_owner: root postgresql_tempfile_group: root +# Controls running tasks handling: cluster initialization +postgresql_initialize: true +# Controls running tasks handling: engine specific objects like databases,users,tablespaces,ownerships,extensions,sqlquery executions +postgresql_manage_objects: true +# Controls running tasks handling: actual replication configuration +postgresql_configure_replication: true + +# PostgreSQl connection vars object +# This variable is used to feed common connection parameters when calling community.postgresql modules +# to manage database objects (users, databases, schemas, etc..) +postgresql_conn_vars: + ca_cert: null # alias ssl_rootcert + connect_params: null + login_host: null + login_password: null + login_unix_socket: "{{ postgresql_unix_socket_directories[0] | d(null, true) }}" + login_user: "{{ postgresql_user }}" + login_port: "{{ postgresql_port }}" + session_role: null + ssl_cert: null + ssl_key: null + ssl_mode: null ``` ### Uninstallation @@ -588,9 +642,9 @@ If you want to uninstall a Postgresql installation with this role, set both vari gather_facts: true vars: - postgresql_version: "15" + postgresql_version: "16" - # Run debug tasks withint the role + # Run debug tasks within the role postgresql_debug: true # Configuration diff --git a/defaults/main.yml b/defaults/main.yml index bd16213..55e8fbc 100644 --- a/defaults/main.yml +++ b/defaults/main.yml @@ -5,6 +5,10 @@ postgresql_version: 16 postgresql_debug: false # Postgresql installation related variables +# Controls running tasks handling: postgreSQL packages installation +postgresql_install: true +# Controls running tasks handling: cluster initialization +postgresql_initialize: true # Debian only. Used to generate the locales used by PostgreSQL databases. postgresql_locales: - 'en_US.UTF-8' @@ -20,6 +24,8 @@ postgresql_enablerepo: "" # Configuration related variables +# Controls running tasks handling: configuration +postgresql_configure: true postgresql_port: 5432 postgresql_listen_addresses: 0.0.0.0 postgresql_max_connections: 100 @@ -103,8 +109,26 @@ postgresql_group: postgres postgresql_service_state: started # Whether or not to enable the postgresql service after installation postgresql_service_enabled: true - - +# PostgreSQl connection vars object +# This variable is used to feed common connection parameters when calling community.postgresql modules +# to manage database objects (users, databases, schemas, etc..) +postgresql_conn_vars: + ca_cert: null # alias ssl_rootcert + connect_params: null + login_host: null + login_password: null + login_unix_socket: "{{ postgresql_unix_socket_directories[0] | d(null, true) }}" + login_user: "{{ postgresql_user }}" + login_port: "{{ postgresql_port }}" + session_role: null + ssl_cert: null + ssl_key: null + ssl_mode: null + + +# PosgreSQL objects management +# Controls running tasks handling: engine specific objects like databases,users,tablespaces,ownerships,extensions,sqlquery executions +postgresql_manage_objects: true # Manage tablespaces postgresql_tablespaces: [] # - name: ssd @@ -199,8 +223,10 @@ postgresql_replication_slots: [] # Replication related variables # Activate postgresql replication postgresql_replication: false +# Controls running tasks handling: actual replication configuration +postgresql_configure_replication: true # Server role in the replication process -postgresql_replication_role: "" # primary/replica +postgresql_replication_role: "" # primary/replica postgresql_replication_user: replication_user postgresql_replication_password: password # Address/DNS name of the primary server used in the pg_basebackup @@ -342,3 +368,9 @@ postgresql_https_pkg_proxy: '' # Confirm twice that postgresql should be uninstalled postgresql_uninstall_1: false postgresql_uninstall_2: false + + +# Tells the role that the PostgreSQL instance is managed by Patroni therefore automatically disabling some features initialization,auto tuning,regular configuration, actual replication configuration +postgresql_is_patroni: false +# When combined with postgresql_install:true, this essentially skips all remaining tasks after packages installation +postgresql_only_install: false diff --git a/tasks/configure.yml b/tasks/configure.yml index 885f512..c833c98 100644 --- a/tasks/configure.yml +++ b/tasks/configure.yml @@ -59,9 +59,18 @@ - name: Retrieve settings requiring a restart community.postgresql.postgresql_query: query: select name from pg_settings where pending_restart='true'; - port: "{{ postgresql_port }}" - login_user: "{{ postgresql_user }}" - login_unix_socket: "{{ postgresql_unix_socket_directories[0] }}" + # connection options + ca_cert: "{{ postgresql_conn_vars.ca_cert | d(omit, true) }}" + connect_params: "{{ postgresql_conn_vars.connect_params | d(omit, true) }}" + login_host: "{{ postgresql_conn_vars.login_host | d(omit, true) }}" + login_password: "{{ postgresql_conn_vars.login_password | d(omit, true) }}" + login_unix_socket: "{{ postgresql_conn_vars.login_unix_socket | d(omit, true) }}" + login_user: "{{ postgresql_conn_vars.login_user | d(omit, true) }}" + login_port: "{{ postgresql_conn_vars.login_port | d(omit, true) }}" + session_role: "{{ postgresql_conn_vars.session_role | d(omit, true) }}" + ssl_cert: "{{ postgresql_conn_vars.ssl_cert | d(omit, true) }}" + ssl_key: "{{ postgresql_conn_vars.ssl_key | d(omit, true) }}" + ssl_mode: "{{ postgresql_conn_vars.ssl_mode | d(omit, true) }}" register: _postgresql_res_pending_params changed_when: postgresql_config_change_allow_restart and _postgresql_res_pending_params.rowcount > 0 become: true diff --git a/tasks/databases.yml b/tasks/databases.yml index 2f0ba29..e89a19d 100644 --- a/tasks/databases.yml +++ b/tasks/databases.yml @@ -6,16 +6,8 @@ lc_ctype: "{{ item.lc_ctype | default('en_US.UTF-8') }}" encoding: "{{ item.encoding | default('UTF-8') }}" template: "{{ item.template | default('template0') }}" - login_host: "{{ item.login_host | default('localhost') }}" - login_password: "{{ item.login_password | default(omit) }}" - login_user: "{{ item.login_user | default(postgresql_user) }}" - login_unix_socket: "{{ item.login_unix_socket | default(postgresql_unix_socket_directories[0]) }}" - port: "{{ postgresql_port }}" owner: "{{ item.owner | default(postgresql_user) }}" state: "{{ item.state | default('present') }}" - ssl_mode: "{{ item.ssl_mode | d(omit) }}" - ca_cert: "{{ item.ca_cert | d(omit) }}" - session_role: "{{ item.session_role | d(omit) }}" force: "{{ item.force | d(omit) }}" target: "{{ item.target | d(omit) }}" target_opts: "{{ item.target_opts | d(omit) }}" @@ -24,6 +16,18 @@ tablespace: "{{ item.tablespace | d(omit) }}" dump_extra_args: "{{ item.dump_extra_args | d(omit) }}" trust_input: "{{ item.trust_input | d(omit) }}" + # connection options + ca_cert: "{{ postgresql_conn_vars.ca_cert | d(omit, true) }}" + connect_params: "{{ postgresql_conn_vars.connect_params | d(omit, true) }}" + login_host: "{{ postgresql_conn_vars.login_host | d(omit, true) }}" + login_password: "{{ postgresql_conn_vars.login_password | d(omit, true) }}" + login_unix_socket: "{{ postgresql_conn_vars.login_unix_socket | d(omit, true) }}" + login_user: "{{ postgresql_conn_vars.login_user | d(omit, true) }}" + login_port: "{{ postgresql_conn_vars.login_port | d(omit, true) }}" + session_role: "{{ postgresql_conn_vars.session_role | d(omit, true) }}" + ssl_cert: "{{ postgresql_conn_vars.ssl_cert | d(omit, true) }}" + ssl_key: "{{ postgresql_conn_vars.ssl_key | d(omit, true) }}" + ssl_mode: "{{ postgresql_conn_vars.ssl_mode | d(omit, true) }}" loop: "{{ postgresql_databases }}" become: true become_user: "{{ postgresql_user }}" @@ -38,13 +42,19 @@ owner: "{{ item.owner | d(omit) }}" state: "{{ item.state | d(omit) }}" cascade_drop: "{{ item.cascade_drop | d(omit) }}" - port: "{{ postgresql_port }}" - login_user: "{{ item.login_user | default(postgresql_user) }}" - login_unix_socket: "{{ item.login_unix_socket | default(postgresql_unix_socket_directories[0]) }}" - ssl_mode: "{{ item.ssl_mode | d(omit) }}" - ca_cert: "{{ item.ca_cert | d(omit) }}" - session_role: "{{ item.session_role | d(omit) }}" trust_input: "{{ item.trust_input | d(omit) }}" + # connection options + ca_cert: "{{ postgresql_conn_vars.ca_cert | d(omit, true) }}" + connect_params: "{{ postgresql_conn_vars.connect_params | d(omit, true) }}" + login_host: "{{ postgresql_conn_vars.login_host | d(omit, true) }}" + login_password: "{{ postgresql_conn_vars.login_password | d(omit, true) }}" + login_unix_socket: "{{ postgresql_conn_vars.login_unix_socket | d(omit, true) }}" + login_user: "{{ postgresql_conn_vars.login_user | d(omit, true) }}" + login_port: "{{ postgresql_conn_vars.login_port | d(omit, true) }}" + session_role: "{{ postgresql_conn_vars.session_role | d(omit, true) }}" + ssl_cert: "{{ postgresql_conn_vars.ssl_cert | d(omit, true) }}" + ssl_key: "{{ postgresql_conn_vars.ssl_key | d(omit, true) }}" + ssl_mode: "{{ postgresql_conn_vars.ssl_mode | d(omit, true) }}" loop: "{{ postgresql_schemas }}" no_log: "{{ postgresql_users_no_log }}" become: true @@ -68,13 +78,19 @@ truncate: "{{ item.truncate | d(omit) }}" state: "{{ item.state | d(omit) }}" cascade: "{{ item.cascade | d(omit) }}" - port: "{{ postgresql_port }}" - login_user: "{{ item.login_user | default(postgresql_user) }}" - login_unix_socket: "{{ item.login_unix_socket | default(postgresql_unix_socket_directories[0]) }}" - ssl_mode: "{{ item.ssl_mode | d(omit) }}" - ca_cert: "{{ item.ca_cert | d(omit) }}" - session_role: "{{ item.session_role | d(omit) }}" trust_input: "{{ item.trust_input | d(omit) }}" + # connection options + ca_cert: "{{ postgresql_conn_vars.ca_cert | d(omit, true) }}" + connect_params: "{{ postgresql_conn_vars.connect_params | d(omit, true) }}" + login_host: "{{ postgresql_conn_vars.login_host | d(omit, true) }}" + login_password: "{{ postgresql_conn_vars.login_password | d(omit, true) }}" + login_unix_socket: "{{ postgresql_conn_vars.login_unix_socket | d(omit, true) }}" + login_user: "{{ postgresql_conn_vars.login_user | d(omit, true) }}" + login_port: "{{ postgresql_conn_vars.login_port | d(omit, true) }}" + session_role: "{{ postgresql_conn_vars.session_role | d(omit, true) }}" + ssl_cert: "{{ postgresql_conn_vars.ssl_cert | d(omit, true) }}" + ssl_key: "{{ postgresql_conn_vars.ssl_key | d(omit, true) }}" + ssl_mode: "{{ postgresql_conn_vars.ssl_mode | d(omit, true) }}" loop: "{{ postgresql_tables }}" no_log: "{{ postgresql_users_no_log }}" become: true diff --git a/tasks/debian/install.yml b/tasks/debian/install.yml index 7f78723..f958572 100644 --- a/tasks/debian/install.yml +++ b/tasks/debian/install.yml @@ -1,13 +1,13 @@ --- - name: Add postgresql repository ansible.builtin.template: - src: etc/apt/sources.list.d/pgdb.list.j2 + src: "{{ _postgresql_apt_repo_template_path }}" dest: /etc/apt/sources.list.d/pgdg.list owner: root group: root mode: "644" -- name: Add postgreqsl repository signing key +- name: Add postgresql repository signing key ansible.builtin.uri: url: https://www.postgresql.org/media/keys/ACCC4CF8.asc dest: /etc/apt/trusted.gpg.d/pgdb.asc diff --git a/tasks/extensions.yml b/tasks/extensions.yml index cd7050f..49a213e 100644 --- a/tasks/extensions.yml +++ b/tasks/extensions.yml @@ -3,19 +3,23 @@ community.postgresql.postgresql_ext: name: "{{ item.name }}" db: "{{ item.db }}" - login_host: "{{ item.login_host | default('localhost') }}" - login_password: "{{ item.login_password | default(omit) }}" - login_user: "{{ item.login_user | default(postgresql_user) }}" - login_unix_socket: "{{ item.login_unix_socket | default(postgresql_unix_socket_directories[0]) }}" - port: "{{ postgresql_port }}" state: "{{ item.state | d('present') }}" schema: "{{ item.schema | d('public') }}" - ssl_mode: "{{ item.ssl_mode | d(omit) }}" - ca_cert: "{{ item.ca_cert | d(omit) }}" - session_role: "{{ item.session_role | d(omit) }}" cascade: "{{ item.cascade | d(omit) }}" version: "{{ item.version | d(omit) }}" trust_input: "{{ item.trust_input | d(omit) }}" + # connection options + ca_cert: "{{ postgresql_conn_vars.ca_cert | d(omit, true) }}" + connect_params: "{{ postgresql_conn_vars.connect_params | d(omit, true) }}" + login_host: "{{ postgresql_conn_vars.login_host | d(omit, true) }}" + login_password: "{{ postgresql_conn_vars.login_password | d(omit, true) }}" + login_unix_socket: "{{ postgresql_conn_vars.login_unix_socket | d(omit, true) }}" + login_user: "{{ postgresql_conn_vars.login_user | d(omit, true) }}" + login_port: "{{ postgresql_conn_vars.login_port | d(omit, true) }}" + session_role: "{{ postgresql_conn_vars.session_role | d(omit, true) }}" + ssl_cert: "{{ postgresql_conn_vars.ssl_cert | d(omit, true) }}" + ssl_key: "{{ postgresql_conn_vars.ssl_key | d(omit, true) }}" + ssl_mode: "{{ postgresql_conn_vars.ssl_mode | d(omit, true) }}" register: _ext_mgmt_res changed_when: - _ext_mgmt_res.changed diff --git a/tasks/install.yml b/tasks/install.yml index d80e1b3..2d95dca 100644 --- a/tasks/install.yml +++ b/tasks/install.yml @@ -42,6 +42,7 @@ extra_args: --upgrade virtualenv: "{{ _postgresql_virtualenv_path }}" virtualenv_command: python3 -m venv + become: true become_user: "{{ postgresql_user }}" when: not ansible_check_mode environment: "{{ _postgresql_general_proxy_env | ansible.builtin.combine({'PATH': _postgresql_pythonized_path}) }}" @@ -53,5 +54,6 @@ ansible.builtin.pip: name: "{{ _postgresql_dependencies_pip_packages }}" virtualenv: "{{ _postgresql_virtualenv_path }}" + become: true become_user: "{{ postgresql_user }}" environment: "{{ _postgresql_general_proxy_env | ansible.builtin.combine({'PATH': _postgresql_pythonized_path}) }}" diff --git a/tasks/main.yml b/tasks/main.yml index 3351322..4bb3238 100644 --- a/tasks/main.yml +++ b/tasks/main.yml @@ -14,12 +14,23 @@ - name: Import installation tasks ansible.builtin.import_tasks: install.yml + when: + - postgresql_install | bool tags: - install - installation +- name: Set fact for ending role + ansible.builtin.set_fact: + _postgresql_end_role: "{{ postgresql_install and postgresql_only_install }}" + tags: always + - name: Import initialization tasks ansible.builtin.import_tasks: initialize.yml + when: + - not _postgresql_end_role + - not postgresql_is_patroni | bool + - postgresql_initialize | bool tags: - init - initialize @@ -27,13 +38,20 @@ - name: Import auto tunning tasks ansible.builtin.import_tasks: autotune.yml - when: postgresql_autotune | bool + when: + - not _postgresql_end_role + - not postgresql_is_patroni | bool + - postgresql_autotune | bool tags: - auto-tune - autotune - name: Import configuration tasks ansible.builtin.import_tasks: configure.yml + when: + - not _postgresql_end_role + - not postgresql_is_patroni | bool + - postgresql_configure | bool tags: - config - configure @@ -42,7 +60,9 @@ - name: Import primary replication tasks ansible.builtin.import_tasks: replication-primary.yml when: - - postgresql_replication + - not _postgresql_end_role + - not postgresql_is_patroni | bool + - postgresql_replication and postgresql_configure_replication - postgresql_replication_role == "primary" tags: - repli @@ -51,7 +71,9 @@ - name: Import replica replication tasks ansible.builtin.import_tasks: replication-replica.yml when: - - postgresql_replication + - not _postgresql_end_role + - not postgresql_is_patroni | bool + - postgresql_replication and postgresql_configure_replication - postgresql_replication_role == "replica" tags: - repli @@ -59,23 +81,33 @@ - name: Import backup tasks ansible.builtin.import_tasks: backup.yml - when: postgresql_backup | bool + when: + - not _postgresql_end_role + - postgresql_backup | bool tags: backup - name: Import vacuum tasks ansible.builtin.import_tasks: vacuum.yml - when: postgresql_vacuum | bool + when: + - not _postgresql_end_role + - postgresql_vacuum | bool tags: vacuum - name: Import user management tasks ansible.builtin.import_tasks: users.yml - when: not postgresql_replication or postgresql_replication_role == "primary" + when: + - not _postgresql_end_role + - postgresql_manage_objects + - not (postgresql_replication or postgresql_is_patroni) or postgresql_replication_role == "primary" tags: - user - users - name: Import tablespace tasks ansible.builtin.import_tasks: tablespaces.yml + when: + - not _postgresql_end_role + - postgresql_manage_objects tags: - tblspc - tablespace @@ -83,7 +115,10 @@ - name: Import databases tasks ansible.builtin.import_tasks: databases.yml - when: not postgresql_replication or postgresql_replication_role == "primary" + when: + - not _postgresql_end_role + - postgresql_manage_objects + - not (postgresql_replication or postgresql_is_patroni) or postgresql_replication_role == "primary" tags: - db - database @@ -91,7 +126,10 @@ - name: Import ownerships and privileges tasks ansible.builtin.import_tasks: ownerships.yml - when: not postgresql_replication or postgresql_replication_role == "primary" + when: + - not _postgresql_end_role + - postgresql_manage_objects + - not (postgresql_replication or postgresql_is_patroni) or postgresql_replication_role == "primary" tags: - owner - owners @@ -102,7 +140,10 @@ - name: Import extensions tasks ansible.builtin.import_tasks: extensions.yml - when: not postgresql_replication or postgresql_replication_role == "primary" + when: + - not _postgresql_end_role + - postgresql_manage_objects + - not (postgresql_replication or postgresql_is_patroni) or postgresql_replication_role == "primary" tags: - ext - extension @@ -110,7 +151,10 @@ - name: Import sql script and queries tasks ansible.builtin.import_tasks: sql.yml - when: not postgresql_replication or postgresql_replication_role == "primary" + when: + - not _postgresql_end_role + - postgresql_manage_objects + - not (postgresql_replication or postgresql_is_patroni) or postgresql_replication_role == "primary" tags: - query - script diff --git a/tasks/ownerships.yml b/tasks/ownerships.yml index 265950e..7f15a45 100644 --- a/tasks/ownerships.yml +++ b/tasks/ownerships.yml @@ -7,13 +7,19 @@ obj_type: "{{ item.obj_type | d(omit) }}" reassign_owned_by: "{{ item.reassign_owned_by | d(omit) }}" fail_on_role: "{{ item.fail_on_role | d(omit) }}" - port: "{{ postgresql_port }}" - login_user: "{{ item.login_user | default(postgresql_user) }}" - login_unix_socket: "{{ item.login_unix_socket | default(postgresql_unix_socket_directories[0]) }}" - ssl_mode: "{{ item.ssl_mode | d(omit) }}" - ca_cert: "{{ item.ca_cert | d(omit) }}" - session_role: "{{ item.session_role | d(omit) }}" trust_input: "{{ item.trust_input | d(omit) }}" + # connection options + ca_cert: "{{ postgresql_conn_vars.ca_cert | d(omit, true) }}" + connect_params: "{{ postgresql_conn_vars.connect_params | d(omit, true) }}" + login_host: "{{ postgresql_conn_vars.login_host | d(omit, true) }}" + login_password: "{{ postgresql_conn_vars.login_password | d(omit, true) }}" + login_unix_socket: "{{ postgresql_conn_vars.login_unix_socket | d(omit, true) }}" + login_user: "{{ postgresql_conn_vars.login_user | d(omit, true) }}" + login_port: "{{ postgresql_conn_vars.login_port | d(omit, true) }}" + session_role: "{{ postgresql_conn_vars.session_role | d(omit, true) }}" + ssl_cert: "{{ postgresql_conn_vars.ssl_cert | d(omit, true) }}" + ssl_key: "{{ postgresql_conn_vars.ssl_key | d(omit, true) }}" + ssl_mode: "{{ postgresql_conn_vars.ssl_mode | d(omit, true) }}" loop: "{{ postgresql_ownerships }}" no_log: "{{ postgresql_users_no_log }}" become: true @@ -34,14 +40,20 @@ db: "{{ item.db | d(omit) }}" target_roles: "{{ item.target_roles | d(omit) }}" state: "{{ item.state | default('present') }}" - port: "{{ postgresql_port }}" - login_user: "{{ item.login_user | default(postgresql_user) }}" - login_unix_socket: "{{ item.login_unix_socket | default(postgresql_unix_socket_directories[0]) }}" - ssl_mode: "{{ item.ssl_mode | d(omit) }}" - ca_cert: "{{ item.ca_cert | d(omit) }}" - fail_on_role: "{{ item.fail_on_user | d(omit) }}" - session_role: "{{ item.session_role | d(omit) }}" trust_input: "{{ item.trust_input | d(omit) }}" + fail_on_role: "{{ item.fail_on_user | d(omit) }}" + # connection options + ca_cert: "{{ postgresql_conn_vars.ca_cert | d(omit, true) }}" + connect_params: "{{ postgresql_conn_vars.connect_params | d(omit, true) }}" + login_host: "{{ postgresql_conn_vars.login_host | d(omit, true) }}" + login_password: "{{ postgresql_conn_vars.login_password | d(omit, true) }}" + login_unix_socket: "{{ postgresql_conn_vars.login_unix_socket | d(omit, true) }}" + login_user: "{{ postgresql_conn_vars.login_user | d(omit, true) }}" + login_port: "{{ postgresql_conn_vars.login_port | d(omit, true) }}" + session_role: "{{ postgresql_conn_vars.session_role | d(omit, true) }}" + ssl_cert: "{{ postgresql_conn_vars.ssl_cert | d(omit, true) }}" + ssl_key: "{{ postgresql_conn_vars.ssl_key | d(omit, true) }}" + ssl_mode: "{{ postgresql_conn_vars.ssl_mode | d(omit, true) }}" loop: "{{ postgresql_privs }}" no_log: "{{ postgresql_users_no_log }}" become: true diff --git a/tasks/redhat/install.yml b/tasks/redhat/install.yml index cbcd517..1aa4a71 100644 --- a/tasks/redhat/install.yml +++ b/tasks/redhat/install.yml @@ -55,7 +55,7 @@ ansible.builtin.dnf: name: gcc state: present - + - name: Ensure PostgreSQL packages (including locales) are installed. ansible.builtin.dnf: name: "{{ _postgresql_packages + postgresql_locale_packages }}" diff --git a/tasks/replication-primary.yml b/tasks/replication-primary.yml index 5873fe1..09646f7 100644 --- a/tasks/replication-primary.yml +++ b/tasks/replication-primary.yml @@ -12,6 +12,18 @@ expires: infinity role_attr_flags: REPLICATION state: present + # connection options + ca_cert: "{{ postgresql_conn_vars.ca_cert | d(omit, true) }}" + connect_params: "{{ postgresql_conn_vars.connect_params | d(omit, true) }}" + login_host: "{{ postgresql_conn_vars.login_host | d(omit, true) }}" + login_password: "{{ postgresql_conn_vars.login_password | d(omit, true) }}" + login_unix_socket: "{{ postgresql_conn_vars.login_unix_socket | d(omit, true) }}" + login_user: "{{ postgresql_conn_vars.login_user | d(omit, true) }}" + login_port: "{{ postgresql_conn_vars.login_port | d(omit, true) }}" + session_role: "{{ postgresql_conn_vars.session_role | d(omit, true) }}" + ssl_cert: "{{ postgresql_conn_vars.ssl_cert | d(omit, true) }}" + ssl_key: "{{ postgresql_conn_vars.ssl_key | d(omit, true) }}" + ssl_mode: "{{ postgresql_conn_vars.ssl_mode | d(omit, true) }}" no_log: "{{ postgresql_users_no_log }}" become: true become_user: "{{ postgresql_user }}" @@ -27,9 +39,19 @@ state: "{{ item.state | d(omit, true) }}" db: "{{ item.db | d(omit, true) }}" output_plugin: "{{ item.output_plugin | d(omit, true) }}" - port: "{{ postgresql_port }}" immediately_reserve: "{{ item.immediately_reserve | d(omit, true) }}" - login_unix_socket: "{{ postgresql_unix_socket_directories[0] }}" + # connection options + ca_cert: "{{ postgresql_conn_vars.ca_cert | d(omit, true) }}" + connect_params: "{{ postgresql_conn_vars.connect_params | d(omit, true) }}" + login_host: "{{ postgresql_conn_vars.login_host | d(omit, true) }}" + login_password: "{{ postgresql_conn_vars.login_password | d(omit, true) }}" + login_unix_socket: "{{ postgresql_conn_vars.login_unix_socket | d(omit, true) }}" + login_user: "{{ postgresql_conn_vars.login_user | d(omit, true) }}" + login_port: "{{ postgresql_conn_vars.login_port | d(omit, true) }}" + session_role: "{{ postgresql_conn_vars.session_role | d(omit, true) }}" + ssl_cert: "{{ postgresql_conn_vars.ssl_cert | d(omit, true) }}" + ssl_key: "{{ postgresql_conn_vars.ssl_key | d(omit, true) }}" + ssl_mode: "{{ postgresql_conn_vars.ssl_mode | d(omit, true) }}" become: true become_user: "{{ postgresql_user }}" vars: diff --git a/tasks/replication-replica.yml b/tasks/replication-replica.yml index 126b8b3..8bf4ce6 100644 --- a/tasks/replication-replica.yml +++ b/tasks/replication-replica.yml @@ -2,8 +2,18 @@ - name: Check replication status on replica community.postgresql.postgresql_query: query: select * from pg_stat_wal_receiver - login_unix_socket: "{{ item.login_unix_socket | default(postgresql_unix_socket_directories[0]) }}" - port: "{{ postgresql_port | default(omit) }}" + # connection options + ca_cert: "{{ postgresql_conn_vars.ca_cert | d(omit, true) }}" + connect_params: "{{ postgresql_conn_vars.connect_params | d(omit, true) }}" + login_host: "{{ postgresql_conn_vars.login_host | d(omit, true) }}" + login_password: "{{ postgresql_conn_vars.login_password | d(omit, true) }}" + login_unix_socket: "{{ postgresql_conn_vars.login_unix_socket | d(omit, true) }}" + login_user: "{{ postgresql_conn_vars.login_user | d(omit, true) }}" + login_port: "{{ postgresql_conn_vars.login_port | d(omit, true) }}" + session_role: "{{ postgresql_conn_vars.session_role | d(omit, true) }}" + ssl_cert: "{{ postgresql_conn_vars.ssl_cert | d(omit, true) }}" + ssl_key: "{{ postgresql_conn_vars.ssl_key | d(omit, true) }}" + ssl_mode: "{{ postgresql_conn_vars.ssl_mode | d(omit, true) }}" register: _postgresql_replication_check become: true become_user: "{{ postgresql_user }}" @@ -71,8 +81,18 @@ name: "{{ postgresql_replication_slot }}" slot_type: physical state: present - port: "{{ postgresql_replication_primary_port }}" - login_unix_socket: "{{ postgresql_unix_socket_directories[0] }}" + # connection options, possibly lookup the conn_vars for the primary to use the actual primary conn vars and not assume they will largely be similar + ca_cert: "{{ hostvars[postgresql_replication_primary_inventory_name].postgresql_conn_vars.ca_cert | d(omit, true) }}" + connect_params: "{{ hostvars[postgresql_replication_primary_inventory_name].postgresql_conn_vars.connect_params | d(omit, true) }}" + login_host: "{{ hostvars[postgresql_replication_primary_inventory_name].postgresql_conn_vars.login_host | d(omit, true) }}" + login_password: "{{ hostvars[postgresql_replication_primary_inventory_name].postgresql_conn_vars.login_password | d(omit, true) }}" + login_unix_socket: "{{ hostvars[postgresql_replication_primary_inventory_name].postgresql_conn_vars.login_unix_socket | d(omit, true) }}" + login_user: "{{ hostvars[postgresql_replication_primary_inventory_name].postgresql_conn_vars.login_user | d(omit, true) }}" + session_role: "{{ hostvars[postgresql_replication_primary_inventory_name].postgresql_conn_vars.session_role | d(omit, true) }}" + ssl_cert: "{{ hostvars[postgresql_replication_primary_inventory_name].postgresql_conn_vars.ssl_cert | d(omit, true) }}" + ssl_key: "{{ hostvars[postgresql_replication_primary_inventory_name].postgresql_conn_vars.ssl_key | d(omit, true) }}" + ssl_mode: "{{ hostvars[postgresql_replication_primary_inventory_name].postgresql_conn_vars.ssl_mode | d(omit, true) }}" + login_port: "{{ postgresql_replication_primary_port }}" delegate_to: "{{ postgresql_replication_primary_inventory_name | d(omit, true) }}" become: true become_user: "{{ postgresql_user }}" diff --git a/tasks/setup-vars.yml b/tasks/setup-vars.yml index 5ca4a7b..15156d1 100644 --- a/tasks/setup-vars.yml +++ b/tasks/setup-vars.yml @@ -36,3 +36,8 @@ when: - postgresql_replication - postgresql_replication_hba_entries | d([], true) | length == 0 + +- name: Set postgresql_conn_vars to make it available later in hostvars + ansible.builtin.set_fact: + postgresql_conn_vars: "{{ postgresql_conn_vars }}" + no_log: "{{ postgresql_debug }}" diff --git a/tasks/sql.yml b/tasks/sql.yml index 5cd49d9..3269ac1 100644 --- a/tasks/sql.yml +++ b/tasks/sql.yml @@ -8,13 +8,19 @@ autocommit: "{{ item.autocommit | d(omit) }}" encoding: "{{ item.encoding | d(omit) }}" search_path: "{{ item.search_path | d(omit) }}" - port: "{{ postgresql_port }}" - login_user: "{{ item.login_user | default(postgresql_user) }}" - login_unix_socket: "{{ item.login_unix_socket | default(postgresql_unix_socket_directories[0]) }}" - ssl_mode: "{{ item.ssl_mode | d(omit) }}" - ca_cert: "{{ item.ca_cert | d(omit) }}" - session_role: "{{ item.session_role | d(omit) }}" trust_input: "{{ item.trust_input | d(omit) }}" + # connection options + ca_cert: "{{ postgresql_conn_vars.ca_cert | d(omit, true) }}" + connect_params: "{{ postgresql_conn_vars.connect_params | d(omit, true) }}" + login_host: "{{ postgresql_conn_vars.login_host | d(omit, true) }}" + login_password: "{{ postgresql_conn_vars.login_password | d(omit, true) }}" + login_unix_socket: "{{ postgresql_conn_vars.login_unix_socket | d(omit, true) }}" + login_user: "{{ postgresql_conn_vars.login_user | d(omit, true) }}" + login_port: "{{ postgresql_conn_vars.login_port | d(omit, true) }}" + session_role: "{{ postgresql_conn_vars.session_role | d(omit, true) }}" + ssl_cert: "{{ postgresql_conn_vars.ssl_cert | d(omit, true) }}" + ssl_key: "{{ postgresql_conn_vars.ssl_key | d(omit, true) }}" + ssl_mode: "{{ postgresql_conn_vars.ssl_mode | d(omit, true) }}" loop: "{{ postgresql_queries }}" no_log: "{{ postgresql_users_no_log }}" become: true @@ -32,13 +38,19 @@ positional_args: "{{ item.positional_args | d(omit) }}" encoding: "{{ item.encoding | d(omit) }}" search_path: "{{ item.search_path | d(omit) }}" - port: "{{ postgresql_port }}" - login_user: "{{ item.login_user | default(postgresql_user) }}" - login_unix_socket: "{{ item.login_unix_socket | default(postgresql_unix_socket_directories[0]) }}" - ssl_mode: "{{ item.ssl_mode | d(omit) }}" - ca_cert: "{{ item.ca_cert | d(omit) }}" - session_role: "{{ item.session_role | d(omit) }}" trust_input: "{{ item.trust_input | d(omit) }}" + # connection options + ca_cert: "{{ postgresql_conn_vars.ca_cert | d(omit, true) }}" + connect_params: "{{ postgresql_conn_vars.connect_params | d(omit, true) }}" + login_host: "{{ postgresql_conn_vars.login_host | d(omit, true) }}" + login_password: "{{ postgresql_conn_vars.login_password | d(omit, true) }}" + login_unix_socket: "{{ postgresql_conn_vars.login_unix_socket | d(omit, true) }}" + login_user: "{{ postgresql_conn_vars.login_user | d(omit, true) }}" + login_port: "{{ postgresql_conn_vars.login_port | d(omit, true) }}" + session_role: "{{ postgresql_conn_vars.session_role | d(omit, true) }}" + ssl_cert: "{{ postgresql_conn_vars.ssl_cert | d(omit, true) }}" + ssl_key: "{{ postgresql_conn_vars.ssl_key | d(omit, true) }}" + ssl_mode: "{{ postgresql_conn_vars.ssl_mode | d(omit, true) }}" loop: "{{ postgresql_scripts }}" no_log: "{{ postgresql_users_no_log }}" changed_when: false diff --git a/tasks/tablespaces.yml b/tasks/tablespaces.yml index 188ced3..16c46b0 100644 --- a/tasks/tablespaces.yml +++ b/tasks/tablespaces.yml @@ -1,3 +1,4 @@ +--- - name: Manage tablespaces location. ansible.builtin.file: path: "{{ item.location }}" @@ -27,13 +28,19 @@ set: "{{ ((item.state | d('present')) == 'present') | ternary(item.set | d(omit), omit) }}" owner: "{{ ((item.state | d('present')) == 'present') | ternary(item.owner | d(omit), omit) }}" location: "{{ ((item.state | d('present')) == 'present') | ternary(item.location | d(omit), omit) }}" - port: "{{ postgresql_port }}" - login_user: "{{ item.login_user | default(postgresql_user) }}" - login_unix_socket: "{{ item.login_unix_socket | default(postgresql_unix_socket_directories[0]) }}" - ssl_mode: "{{ item.ssl_mode | d(omit) }}" - ca_cert: "{{ item.ca_cert | d(omit) }}" - session_role: "{{ item.session_role | d(omit) }}" trust_input: "{{ item.trust_input | d(omit) }}" + # connection options + ca_cert: "{{ postgresql_conn_vars.ca_cert | d(omit, true) }}" + connect_params: "{{ postgresql_conn_vars.connect_params | d(omit, true) }}" + login_host: "{{ postgresql_conn_vars.login_host | d(omit, true) }}" + login_password: "{{ postgresql_conn_vars.login_password | d(omit, true) }}" + login_unix_socket: "{{ postgresql_conn_vars.login_unix_socket | d(omit, true) }}" + login_user: "{{ postgresql_conn_vars.login_user | d(omit, true) }}" + login_port: "{{ postgresql_conn_vars.login_port | d(omit, true) }}" + session_role: "{{ postgresql_conn_vars.session_role | d(omit, true) }}" + ssl_cert: "{{ postgresql_conn_vars.ssl_cert | d(omit, true) }}" + ssl_key: "{{ postgresql_conn_vars.ssl_key | d(omit, true) }}" + ssl_mode: "{{ postgresql_conn_vars.ssl_mode | d(omit, true) }}" register: tbspc_mgmt_res failed_when: - tbspc_mgmt_res.failed diff --git a/tasks/users.yml b/tasks/users.yml index d39f88a..fd837f2 100644 --- a/tasks/users.yml +++ b/tasks/users.yml @@ -3,22 +3,28 @@ community.postgresql.postgresql_user: name: "{{ item.name }}" password: "{{ item.password | default(omit) }}" - port: "{{ postgresql_port }}" - login_user: "{{ item.login_user | default(postgresql_user) }}" - login_unix_socket: "{{ item.login_unix_socket | default(postgresql_unix_socket_directories[0]) }}" encrypted: "{{ item.encrypted | default(omit) }}" role_attr_flags: "{{ item.role_attr_flags | default(omit) }}" db: "{{ item.db | default(omit) }}" state: "{{ item.state | default('present') }}" - ssl_mode: "{{ item.ssl_mode | d(omit) }}" - ca_cert: "{{ item.ca_cert | d(omit) }}" fail_on_user: "{{ item.fail_on_user | d(omit) }}" - session_role: "{{ item.session_role | d(omit) }}" expires: "{{ item.expires | d(omit) }}" no_password_changes: "{{ item.no_password_changes | d(omit) }}" conn_limit: "{{ item.conn_limit | d(omit) }}" comment: "{{ item.comment | d(omit) }}" trust_input: "{{ item.trust_input | d(omit) }}" + # Connection options + ca_cert: "{{ postgresql_conn_vars.ca_cert | d(omit, true) }}" + connect_params: "{{ postgresql_conn_vars.connect_params | d(omit, true) }}" + login_host: "{{ postgresql_conn_vars.login_host | d(omit, true) }}" + login_password: "{{ postgresql_conn_vars.login_password | d(omit, true) }}" + login_unix_socket: "{{ postgresql_conn_vars.login_unix_socket | d(omit, true) }}" + login_user: "{{ postgresql_conn_vars.login_user | d(omit, true) }}" + login_port: "{{ postgresql_conn_vars.login_port | d(omit, true) }}" + session_role: "{{ postgresql_conn_vars.session_role | d(omit, true) }}" + ssl_cert: "{{ postgresql_conn_vars.ssl_cert | d(omit, true) }}" + ssl_key: "{{ postgresql_conn_vars.ssl_key | d(omit, true) }}" + ssl_mode: "{{ postgresql_conn_vars.ssl_mode | d(omit, true) }}" loop: "{{ postgresql_users }}" loop_control: label: "{{ item.name }}" @@ -37,15 +43,21 @@ groups: "{{ item.groups }}" target_roles: "{{ item.target_roles }}" state: "{{ item.state | default('present') }}" - port: "{{ postgresql_port }}" - login_user: "{{ item.login_user | default(postgresql_user) }}" - login_unix_socket: "{{ item.login_unix_socket | default(postgresql_unix_socket_directories[0]) }}" db: "{{ item.db | default(omit) }}" - ssl_mode: "{{ item.ssl_mode | d(omit) }}" - ca_cert: "{{ item.ca_cert | d(omit) }}" fail_on_role: "{{ item.fail_on_user | d(omit) }}" - session_role: "{{ item.session_role | d(omit) }}" trust_input: "{{ item.trust_input | d(omit) }}" + # connection options + ca_cert: "{{ postgresql_conn_vars.ca_cert | d(omit, true) }}" + connect_params: "{{ postgresql_conn_vars.connect_params | d(omit, true) }}" + login_host: "{{ postgresql_conn_vars.login_host | d(omit, true) }}" + login_password: "{{ postgresql_conn_vars.login_password | d(omit, true) }}" + login_unix_socket: "{{ postgresql_conn_vars.login_unix_socket | d(omit, true) }}" + login_user: "{{ postgresql_conn_vars.login_user | d(omit, true) }}" + login_port: "{{ postgresql_conn_vars.login_port | d(omit, true) }}" + session_role: "{{ postgresql_conn_vars.session_role | d(omit, true) }}" + ssl_cert: "{{ postgresql_conn_vars.ssl_cert | d(omit, true) }}" + ssl_key: "{{ postgresql_conn_vars.ssl_key | d(omit, true) }}" + ssl_mode: "{{ postgresql_conn_vars.ssl_mode | d(omit, true) }}" loop: "{{ postgresql_memberships }}" no_log: "{{ postgresql_users_no_log }}" become: true diff --git a/vars/main.yml b/vars/main.yml index 6018f02..f1a85dd 100644 --- a/vars/main.yml +++ b/vars/main.yml @@ -30,6 +30,7 @@ _postgresql_config_change_handler_state: reloaded _postgresql_service_state: started _postgresql_apt_mirror_url: http://apt.postgresql.org/pub/repos/apt +_postgresql_apt_repo_template_path: templates/etc/apt/sources.list.d/pgdb.list.j2 _postgresql_repo_rpm_url: "https://download.postgresql.org/pub/repos/yum/reporpms/{{ (ansible_distro == 'fedora') | ternary('F', 'EL') }}-{{ ansible_distribution_major_version }}-x86_64/pgdg-{{ (ansible_distro == 'fedora') | ternary('fedora', 'redhat') }}-repo-latest.noarch.rpm" _postgresql_unix_socket_directories_mode: "{{ postgresql_unix_socket_directories_mode | d('2775', true) }}" _postgresql_service_path: "{{ postgresql_service_path | d('', true) }}"