postgresql_info: add subscription info (#67464)
* postgresql_info: add subscription info * add changelog
This commit is contained in:
parent
23995fef48
commit
0dc08f6b97
8 changed files with 236 additions and 79 deletions
|
@ -0,0 +1,2 @@
|
|||
minor_changes:
|
||||
- postgresql_info - add collection info about replication subscriptions (https://github.com/ansible/ansible/pull/67464).
|
|
@ -26,7 +26,7 @@ options:
|
|||
- Limit the collected information by comma separated string or YAML list.
|
||||
- Allowable values are C(version),
|
||||
C(databases), C(settings), C(tablespaces), C(roles),
|
||||
C(replications), C(repl_slots).
|
||||
C(replications), C(repl_slots), C(subscriptions) (since 2.10).
|
||||
- By default, collects all subsets.
|
||||
- You can use shell-style (fnmatch) wildcard to pass groups of values (see Examples).
|
||||
- You can use '!' before value (for example, C(!settings)) to exclude it from the information.
|
||||
|
@ -453,6 +453,15 @@ settings:
|
|||
returned: always
|
||||
type: bool
|
||||
sample: false
|
||||
subscriptions:
|
||||
description:
|
||||
- Information about replication subscriptions (available for PostgreSQL 10 and higher)
|
||||
U(https://www.postgresql.org/docs/current/logical-replication-subscription.html).
|
||||
- Content depends on PostgreSQL server version.
|
||||
returned: if configured
|
||||
type: dict
|
||||
sample:
|
||||
- {"acme_db": {"my_subscription": {"ownername": "postgres", "subenabled": true, "subpublications": ["first_publication"]}}}
|
||||
'''
|
||||
|
||||
from fnmatch import fnmatch
|
||||
|
@ -470,6 +479,7 @@ from ansible.module_utils.postgres import (
|
|||
get_conn_params,
|
||||
postgres_common_argument_spec,
|
||||
)
|
||||
from ansible.module_utils.six import iteritems
|
||||
from ansible.module_utils._text import to_native
|
||||
|
||||
|
||||
|
@ -533,6 +543,7 @@ class PgClusterInfo(object):
|
|||
"repl_slots": {},
|
||||
"settings": {},
|
||||
"roles": {},
|
||||
"subscriptions": {},
|
||||
"pending_restart_settings": [],
|
||||
}
|
||||
|
||||
|
@ -546,6 +557,7 @@ class PgClusterInfo(object):
|
|||
"repl_slots": self.get_rslot_info,
|
||||
"settings": self.get_settings,
|
||||
"roles": self.get_role_info,
|
||||
"subscriptions": self.get_subscr_info,
|
||||
}
|
||||
|
||||
incl_list = []
|
||||
|
@ -588,6 +600,36 @@ class PgClusterInfo(object):
|
|||
|
||||
return self.pg_info
|
||||
|
||||
def get_subscr_info(self):
|
||||
"""Get subscription statistics and fill out self.pg_info dictionary."""
|
||||
if self.cursor.connection.server_version < 10000:
|
||||
return
|
||||
|
||||
query = ("SELECT s.*, r.rolname AS ownername, d.datname AS dbname "
|
||||
"FROM pg_catalog.pg_subscription s "
|
||||
"JOIN pg_catalog.pg_database d "
|
||||
"ON s.subdbid = d.oid "
|
||||
"JOIN pg_catalog.pg_roles AS r "
|
||||
"ON s.subowner = r.oid")
|
||||
|
||||
result = self.__exec_sql(query)
|
||||
|
||||
if result:
|
||||
result = [dict(row) for row in result]
|
||||
else:
|
||||
return
|
||||
|
||||
for elem in result:
|
||||
if not self.pg_info['subscriptions'].get(elem['dbname']):
|
||||
self.pg_info['subscriptions'][elem['dbname']] = {}
|
||||
|
||||
if not self.pg_info['subscriptions'][elem['dbname']].get(elem['subname']):
|
||||
self.pg_info['subscriptions'][elem['dbname']][elem['subname']] = {}
|
||||
|
||||
for key, val in iteritems(elem):
|
||||
if key not in ('subname', 'dbname'):
|
||||
self.pg_info['subscriptions'][elem['dbname']][elem['subname']][key] = val
|
||||
|
||||
def get_tablespaces(self):
|
||||
"""Get information about tablespaces."""
|
||||
# Check spcoption exists:
|
||||
|
|
|
@ -1,4 +1,9 @@
|
|||
destructive
|
||||
shippable/posix/group4
|
||||
shippable/posix/group1
|
||||
skip/aix
|
||||
skip/osx
|
||||
skip/centos
|
||||
skip/freebsd
|
||||
skip/rhel
|
||||
skip/opensuse
|
||||
skip/fedora
|
||||
|
|
|
@ -1,2 +1,15 @@
|
|||
---
|
||||
pg_user: postgres
|
||||
db_default: postgres
|
||||
master_port: 5433
|
||||
replica_port: 5434
|
||||
|
||||
test_table1: acme1
|
||||
test_pub: first_publication
|
||||
test_pub2: second_publication
|
||||
replication_role: logical_replication
|
||||
replication_pass: alsdjfKJKDf1#
|
||||
test_db: acme_db
|
||||
test_subscription: test
|
||||
test_subscription2: test2
|
||||
conn_timeout: 100
|
||||
|
|
|
@ -1,2 +1,2 @@
|
|||
dependencies:
|
||||
- setup_postgresql_db
|
||||
- setup_postgresql_replication
|
||||
|
|
|
@ -1,2 +1,7 @@
|
|||
# For testing getting publication and subscription info
|
||||
- import_tasks: setup_publication.yml
|
||||
when: ansible_distribution == 'Ubuntu' and ansible_distribution_major_version >= '18'
|
||||
|
||||
# Initial CI tests of postgresql_info module
|
||||
- import_tasks: postgresql_info_initial.yml
|
||||
when: ansible_distribution == 'Ubuntu' and ansible_distribution_major_version >= '18'
|
||||
|
|
|
@ -1,25 +1,64 @@
|
|||
# Test code for the postgresql_info module
|
||||
# Copyright: (c) 2019, Andrew Klychkov (@Andersson007) <aaklychkov@mail.ru>
|
||||
# Copyright: (c) 2020, Andrew Klychkov (@Andersson007) <aaklychkov@mail.ru>
|
||||
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||
|
||||
- name: postgresql_info - create role to check session_role
|
||||
become_user: "{{ pg_user }}"
|
||||
- vars:
|
||||
task_parameters: &task_parameters
|
||||
become_user: '{{ pg_user }}'
|
||||
become: yes
|
||||
register: result
|
||||
pg_parameters: &pg_parameters
|
||||
login_user: '{{ pg_user }}'
|
||||
login_db: '{{ db_default }}'
|
||||
|
||||
block:
|
||||
|
||||
- name: Create test subscription
|
||||
<<: *task_parameters
|
||||
postgresql_subscription:
|
||||
<<: *pg_parameters
|
||||
login_port: '{{ replica_port }}'
|
||||
name: '{{ test_subscription }}'
|
||||
login_db: '{{ test_db }}'
|
||||
state: present
|
||||
publications: '{{ test_pub }}'
|
||||
connparams:
|
||||
host: 127.0.0.1
|
||||
port: '{{ master_port }}'
|
||||
user: '{{ replication_role }}'
|
||||
password: '{{ replication_pass }}'
|
||||
dbname: '{{ test_db }}'
|
||||
|
||||
- name: Create test subscription
|
||||
<<: *task_parameters
|
||||
postgresql_subscription:
|
||||
<<: *pg_parameters
|
||||
login_port: '{{ replica_port }}'
|
||||
name: '{{ test_subscription2 }}'
|
||||
login_db: '{{ test_db }}'
|
||||
state: present
|
||||
publications: '{{ test_pub2 }}'
|
||||
connparams:
|
||||
host: 127.0.0.1
|
||||
port: '{{ master_port }}'
|
||||
user: '{{ replication_role }}'
|
||||
password: '{{ replication_pass }}'
|
||||
dbname: '{{ test_db }}'
|
||||
|
||||
- name: postgresql_info - create role to check session_role
|
||||
<<: *task_parameters
|
||||
postgresql_user:
|
||||
db: "{{ db_default }}"
|
||||
<<: *pg_parameters
|
||||
login_port: '{{ replica_port }}'
|
||||
login_user: "{{ pg_user }}"
|
||||
name: session_superuser
|
||||
role_attr_flags: SUPERUSER
|
||||
|
||||
- name: postgresql_info - test return values and session_role param
|
||||
become_user: "{{ pg_user }}"
|
||||
become: yes
|
||||
<<: *task_parameters
|
||||
postgresql_info:
|
||||
db: "{{ db_default }}"
|
||||
login_user: "{{ pg_user }}"
|
||||
<<: *pg_parameters
|
||||
login_port: '{{ replica_port }}'
|
||||
session_role: session_superuser
|
||||
register: result
|
||||
ignore_errors: yes
|
||||
|
||||
- assert:
|
||||
that:
|
||||
|
@ -31,23 +70,25 @@
|
|||
- result.settings
|
||||
- result.tablespaces
|
||||
- result.roles
|
||||
- result.subscriptions.{{ test_db }}.{{ test_subscription }}
|
||||
- result.subscriptions.{{ test_db }}.{{ test_subscription2 }}
|
||||
|
||||
- name: postgresql_info - check filter param passed by list
|
||||
become_user: "{{ pg_user }}"
|
||||
become: yes
|
||||
<<: *task_parameters
|
||||
postgresql_info:
|
||||
db: "{{ db_default }}"
|
||||
login_user: "{{ pg_user }}"
|
||||
<<: *pg_parameters
|
||||
login_port: '{{ replica_port }}'
|
||||
filter:
|
||||
- ver*
|
||||
- rol*
|
||||
register: result
|
||||
ignore_errors: yes
|
||||
- subscr*
|
||||
|
||||
- assert:
|
||||
that:
|
||||
- result.version != {}
|
||||
- result.roles
|
||||
- result.subscriptions.{{ test_db }}.{{ test_subscription }} != {}
|
||||
- result.subscriptions.{{ test_db }}.{{ test_subscription2 }} != {}
|
||||
- result.databases == {}
|
||||
- result.repl_slots == {}
|
||||
- result.replications == {}
|
||||
|
@ -55,14 +96,10 @@
|
|||
- result.tablespaces == {}
|
||||
|
||||
- name: postgresql_info - check filter param passed by string
|
||||
become_user: "{{ pg_user }}"
|
||||
become: yes
|
||||
<<: *task_parameters
|
||||
postgresql_info:
|
||||
db: "{{ db_default }}"
|
||||
<<: *pg_parameters
|
||||
filter: ver*,role*
|
||||
login_user: "{{ pg_user }}"
|
||||
register: result
|
||||
ignore_errors: yes
|
||||
|
||||
- assert:
|
||||
that:
|
||||
|
@ -75,14 +112,10 @@
|
|||
- result.tablespaces == {}
|
||||
|
||||
- name: postgresql_info - check filter param passed by string
|
||||
become_user: "{{ pg_user }}"
|
||||
become: yes
|
||||
<<: *task_parameters
|
||||
postgresql_info:
|
||||
db: "{{ db_default }}"
|
||||
<<: *pg_parameters
|
||||
filter: ver*
|
||||
login_user: "{{ pg_user }}"
|
||||
register: result
|
||||
ignore_errors: yes
|
||||
|
||||
- assert:
|
||||
that:
|
||||
|
@ -90,16 +123,12 @@
|
|||
- result.roles == {}
|
||||
|
||||
- name: postgresql_info - check excluding filter param passed by list
|
||||
become_user: "{{ pg_user }}"
|
||||
become: yes
|
||||
<<: *task_parameters
|
||||
postgresql_info:
|
||||
db: "{{ db_default }}"
|
||||
<<: *pg_parameters
|
||||
filter:
|
||||
- "!ver*"
|
||||
- "!rol*"
|
||||
login_user: "{{ pg_user }}"
|
||||
register: result
|
||||
ignore_errors: yes
|
||||
|
||||
- assert:
|
||||
that:
|
||||
|
|
|
@ -0,0 +1,61 @@
|
|||
# Copyright: (c) 2019, Andrew Klychkov (@Andersson007) <aaklychkov@mail.ru>
|
||||
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
|
||||
# Preparation for further tests of postgresql_subscription module.
|
||||
|
||||
- vars:
|
||||
task_parameters: &task_parameters
|
||||
become_user: '{{ pg_user }}'
|
||||
become: yes
|
||||
register: result
|
||||
pg_parameters: &pg_parameters
|
||||
login_user: '{{ pg_user }}'
|
||||
login_db: '{{ test_db }}'
|
||||
|
||||
block:
|
||||
- name: Create test db
|
||||
<<: *task_parameters
|
||||
postgresql_db:
|
||||
login_user: '{{ pg_user }}'
|
||||
login_port: '{{ master_port }}'
|
||||
maintenance_db: '{{ db_default }}'
|
||||
name: '{{ test_db }}'
|
||||
|
||||
- name: Create test role
|
||||
<<: *task_parameters
|
||||
postgresql_user:
|
||||
<<: *pg_parameters
|
||||
login_port: '{{ master_port }}'
|
||||
name: '{{ replication_role }}'
|
||||
password: '{{ replication_pass }}'
|
||||
role_attr_flags: LOGIN,REPLICATION
|
||||
|
||||
- name: Create test table
|
||||
<<: *task_parameters
|
||||
postgresql_table:
|
||||
<<: *pg_parameters
|
||||
login_port: '{{ master_port }}'
|
||||
name: '{{ test_table1 }}'
|
||||
columns:
|
||||
- id int
|
||||
|
||||
- name: Master - dump schema
|
||||
<<: *task_parameters
|
||||
shell: pg_dumpall -p '{{ master_port }}' -s > /tmp/schema.sql
|
||||
|
||||
- name: Replicat restore schema
|
||||
<<: *task_parameters
|
||||
shell: psql -p '{{ replica_port }}' -f /tmp/schema.sql
|
||||
|
||||
- name: Create publication
|
||||
<<: *task_parameters
|
||||
postgresql_publication:
|
||||
<<: *pg_parameters
|
||||
login_port: '{{ master_port }}'
|
||||
name: '{{ test_pub }}'
|
||||
|
||||
- name: Create publication
|
||||
<<: *task_parameters
|
||||
postgresql_publication:
|
||||
<<: *pg_parameters
|
||||
login_port: '{{ master_port }}'
|
||||
name: '{{ test_pub2 }}'
|
Loading…
Reference in a new issue