postgresql_info: add subscription info (#67464)

* postgresql_info: add subscription info

* add changelog
This commit is contained in:
Andrew Klychkov 2020-02-20 11:59:45 +03:00 committed by GitHub
parent 23995fef48
commit 0dc08f6b97
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
8 changed files with 236 additions and 79 deletions

View file

@ -0,0 +1,2 @@
minor_changes:
- postgresql_info - add collection info about replication subscriptions (https://github.com/ansible/ansible/pull/67464).

View file

@ -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:

View file

@ -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

View file

@ -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

View file

@ -1,2 +1,2 @@
dependencies:
- setup_postgresql_db
- setup_postgresql_replication

View file

@ -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'

View file

@ -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:

View file

@ -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 }}'