mirror of
https://github.com/ansible-collections/community.general.git
synced 2024-09-14 20:13:21 +02:00
postgresql_privs: Support FOREIGN DATA WRAPPER and FOREIGN SERVER (#38803)
* Support FOREIGN DATA WRAPPER and FOREIGN SERVER in postgresql_privs module * Added available from note to fdw and fs object types * Integration tests, examples in documentation * Complete integration tests
This commit is contained in:
parent
f5faf8211d
commit
6e198487c9
4 changed files with 285 additions and 3 deletions
|
@ -0,0 +1,3 @@
|
||||||
|
---
|
||||||
|
minor_changes:
|
||||||
|
- "postgresql_privs - introduces support for FOREIGN DATA WRAPPER and FOREIGN SERVER as object types in postgresql_privs module. (https://github.com/ansible/ansible/issues/38801)"
|
|
@ -41,10 +41,11 @@ options:
|
||||||
description:
|
description:
|
||||||
- Type of database object to set privileges on.
|
- Type of database object to set privileges on.
|
||||||
- The `default_prives` choice is available starting at version 2.7.
|
- The `default_prives` choice is available starting at version 2.7.
|
||||||
|
- The 'foreign_data_wrapper' and 'foreign_server' object types are available from Ansible version '2.8'.
|
||||||
default: table
|
default: table
|
||||||
choices: [table, sequence, function, database,
|
choices: [table, sequence, function, database,
|
||||||
schema, language, tablespace, group,
|
schema, language, tablespace, group,
|
||||||
default_privs]
|
default_privs, foreign_data_wrapper, foreign_server]
|
||||||
objs:
|
objs:
|
||||||
description:
|
description:
|
||||||
- Comma separated list of database objects to set privileges on.
|
- Comma separated list of database objects to set privileges on.
|
||||||
|
@ -272,6 +273,23 @@ EXAMPLES = """
|
||||||
type: default_privs
|
type: default_privs
|
||||||
role: reader
|
role: reader
|
||||||
|
|
||||||
|
# Available since version 2.8
|
||||||
|
# GRANT ALL PRIVILEGES ON FOREIGN DATA WRAPPER fdw TO reader
|
||||||
|
- postgresql_privs:
|
||||||
|
db: test
|
||||||
|
objs: fdw
|
||||||
|
privs: ALL
|
||||||
|
type: foreign_data_wrapper
|
||||||
|
role: reader
|
||||||
|
|
||||||
|
# GRANT ALL PRIVILEGES ON FOREIGN SERVER fdw_server TO reader
|
||||||
|
- postgresql_privs:
|
||||||
|
db: test
|
||||||
|
objs: fdw_server
|
||||||
|
privs: ALL
|
||||||
|
type: foreign_server
|
||||||
|
role: reader
|
||||||
|
|
||||||
"""
|
"""
|
||||||
|
|
||||||
import traceback
|
import traceback
|
||||||
|
@ -484,6 +502,18 @@ class Connection(object):
|
||||||
self.cursor.execute(query, (schema,))
|
self.cursor.execute(query, (schema,))
|
||||||
return [t[0] for t in self.cursor.fetchall()]
|
return [t[0] for t in self.cursor.fetchall()]
|
||||||
|
|
||||||
|
def get_foreign_data_wrapper_acls(self, fdws):
|
||||||
|
query = """SELECT fdwacl FROM pg_catalog.pg_foreign_data_wrapper
|
||||||
|
WHERE fdwname = ANY (%s) ORDER BY fdwname"""
|
||||||
|
self.cursor.execute(query, (fdws,))
|
||||||
|
return [t[0] for t in self.cursor.fetchall()]
|
||||||
|
|
||||||
|
def get_foreign_server_acls(self, fs):
|
||||||
|
query = """SELECT srvacl FROM pg_catalog.pg_foreign_server
|
||||||
|
WHERE srvname = ANY (%s) ORDER BY srvname"""
|
||||||
|
self.cursor.execute(query, (fs,))
|
||||||
|
return [t[0] for t in self.cursor.fetchall()]
|
||||||
|
|
||||||
# Manipulating privileges
|
# Manipulating privileges
|
||||||
|
|
||||||
def manipulate_privs(self, obj_type, privs, objs, roles,
|
def manipulate_privs(self, obj_type, privs, objs, roles,
|
||||||
|
@ -525,6 +555,10 @@ class Connection(object):
|
||||||
get_status = self.get_group_memberships
|
get_status = self.get_group_memberships
|
||||||
elif obj_type == 'default_privs':
|
elif obj_type == 'default_privs':
|
||||||
get_status = partial(self.get_default_privs, schema_qualifier)
|
get_status = partial(self.get_default_privs, schema_qualifier)
|
||||||
|
elif obj_type == 'foreign_data_wrapper':
|
||||||
|
get_status = self.get_foreign_data_wrapper_acls
|
||||||
|
elif obj_type == 'foreign_server':
|
||||||
|
get_status = self.get_foreign_server_acls
|
||||||
else:
|
else:
|
||||||
raise Error('Unsupported database object type "%s".' % obj_type)
|
raise Error('Unsupported database object type "%s".' % obj_type)
|
||||||
|
|
||||||
|
@ -559,7 +593,8 @@ class Connection(object):
|
||||||
obj_ids = [pg_quote_identifier(i, 'table') for i in obj_ids]
|
obj_ids = [pg_quote_identifier(i, 'table') for i in obj_ids]
|
||||||
# Note: obj_type has been checked against a set of string literals
|
# Note: obj_type has been checked against a set of string literals
|
||||||
# and privs was escaped when it was parsed
|
# and privs was escaped when it was parsed
|
||||||
set_what = '%s ON %s %s' % (','.join(privs), obj_type,
|
# Note: Underscores are replaced with spaces to support multi-word obj_type
|
||||||
|
set_what = '%s ON %s %s' % (','.join(privs), obj_type.replace('_', ' '),
|
||||||
','.join(obj_ids))
|
','.join(obj_ids))
|
||||||
|
|
||||||
# for_whom: SQL-fragment specifying for whom to set the above
|
# for_whom: SQL-fragment specifying for whom to set the above
|
||||||
|
@ -706,7 +741,9 @@ def main():
|
||||||
'language',
|
'language',
|
||||||
'tablespace',
|
'tablespace',
|
||||||
'group',
|
'group',
|
||||||
'default_privs']),
|
'default_privs',
|
||||||
|
'foreign_data_wrapper',
|
||||||
|
'foreign_server']),
|
||||||
objs=dict(required=False, aliases=['obj']),
|
objs=dict(required=False, aliases=['obj']),
|
||||||
schema=dict(required=False),
|
schema=dict(required=False),
|
||||||
roles=dict(required=True, aliases=['role']),
|
roles=dict(required=True, aliases=['role']),
|
||||||
|
|
|
@ -777,6 +777,9 @@
|
||||||
# Test postgresql_tablespace module
|
# Test postgresql_tablespace module
|
||||||
- include: postgresql_tablespace.yml
|
- include: postgresql_tablespace.yml
|
||||||
|
|
||||||
|
# Test postgresql_privs
|
||||||
|
- include: postgresql_privs.yml
|
||||||
|
|
||||||
# dump/restore tests per format
|
# dump/restore tests per format
|
||||||
# ============================================================
|
# ============================================================
|
||||||
- include: state_dump_restore.yml test_fixture=user file=dbdata.sql
|
- include: state_dump_restore.yml test_fixture=user file=dbdata.sql
|
||||||
|
|
239
test/integration/targets/postgresql/tasks/postgresql_privs.yml
Normal file
239
test/integration/targets/postgresql/tasks/postgresql_privs.yml
Normal file
|
@ -0,0 +1,239 @@
|
||||||
|
---
|
||||||
|
|
||||||
|
######################################################
|
||||||
|
# Test foreign data wrapper and foreign server privs #
|
||||||
|
######################################################
|
||||||
|
|
||||||
|
- name: Create DB
|
||||||
|
become_user: "{{ pg_user }}"
|
||||||
|
become: True
|
||||||
|
postgresql_db:
|
||||||
|
state: present
|
||||||
|
name: "{{ db_name }}"
|
||||||
|
login_user: "{{ pg_user }}"
|
||||||
|
register: result
|
||||||
|
|
||||||
|
- name: Create test role
|
||||||
|
become: True
|
||||||
|
become_user: "{{ pg_user }}"
|
||||||
|
shell: echo "CREATE ROLE fdw_test" | psql -d "{{ db_name }}"
|
||||||
|
|
||||||
|
- name: Create fdw extension
|
||||||
|
become: True
|
||||||
|
become_user: "{{ pg_user }}"
|
||||||
|
shell: echo "CREATE EXTENSION postgres_fdw" | psql -d "{{ db_name }}"
|
||||||
|
|
||||||
|
- name: Create foreign data wrapper
|
||||||
|
become: True
|
||||||
|
become_user: "{{ pg_user }}"
|
||||||
|
shell: echo "CREATE FOREIGN DATA WRAPPER dummy" | psql -d "{{ db_name }}"
|
||||||
|
|
||||||
|
- name: Create foreign server
|
||||||
|
become: True
|
||||||
|
become_user: "{{ pg_user }}"
|
||||||
|
shell: echo "CREATE SERVER dummy_server FOREIGN DATA WRAPPER dummy" | psql -d "{{ db_name }}"
|
||||||
|
|
||||||
|
- name: Grant foreign data wrapper privileges
|
||||||
|
postgresql_privs:
|
||||||
|
state: present
|
||||||
|
type: foreign_data_wrapper
|
||||||
|
roles: fdw_test
|
||||||
|
privs: ALL
|
||||||
|
objs: dummy
|
||||||
|
db: "{{ db_name }}"
|
||||||
|
login_user: "{{ pg_user }}"
|
||||||
|
register: result
|
||||||
|
ignore_errors: yes
|
||||||
|
|
||||||
|
- assert:
|
||||||
|
that:
|
||||||
|
- "result.changed == true"
|
||||||
|
|
||||||
|
- name: Get foreign data wrapper privileges
|
||||||
|
become: True
|
||||||
|
become_user: "{{ pg_user }}"
|
||||||
|
shell: echo "{{ fdw_query }}" | psql -d "{{ db_name }}"
|
||||||
|
vars:
|
||||||
|
fdw_query: >
|
||||||
|
SELECT fdwacl FROM pg_catalog.pg_foreign_data_wrapper
|
||||||
|
WHERE fdwname = ANY (ARRAY['dummy']) ORDER BY fdwname
|
||||||
|
register: fdw_result
|
||||||
|
|
||||||
|
- assert:
|
||||||
|
that:
|
||||||
|
- "fdw_result.stdout_lines[-1] == '(1 row)'"
|
||||||
|
- "'fdw_test' in fdw_result.stdout_lines[-2]"
|
||||||
|
|
||||||
|
- name: Grant foreign data wrapper privileges second time
|
||||||
|
postgresql_privs:
|
||||||
|
state: present
|
||||||
|
type: foreign_data_wrapper
|
||||||
|
roles: fdw_test
|
||||||
|
privs: ALL
|
||||||
|
objs: dummy
|
||||||
|
db: "{{ db_name }}"
|
||||||
|
login_user: "{{ pg_user }}"
|
||||||
|
register: result
|
||||||
|
ignore_errors: yes
|
||||||
|
|
||||||
|
- assert:
|
||||||
|
that:
|
||||||
|
- "result.changed == false"
|
||||||
|
|
||||||
|
- name: Revoke foreign data wrapper privileges
|
||||||
|
postgresql_privs:
|
||||||
|
state: absent
|
||||||
|
type: foreign_data_wrapper
|
||||||
|
roles: fdw_test
|
||||||
|
privs: ALL
|
||||||
|
objs: dummy
|
||||||
|
db: "{{ db_name }}"
|
||||||
|
login_user: "{{ pg_user }}"
|
||||||
|
register: result
|
||||||
|
ignore_errors: yes
|
||||||
|
|
||||||
|
- assert:
|
||||||
|
that:
|
||||||
|
- "result.changed == true"
|
||||||
|
|
||||||
|
- name: Get foreign data wrapper privileges
|
||||||
|
become: True
|
||||||
|
become_user: "{{ pg_user }}"
|
||||||
|
shell: echo "{{ fdw_query }}" | psql -d "{{ db_name }}"
|
||||||
|
vars:
|
||||||
|
fdw_query: >
|
||||||
|
SELECT fdwacl FROM pg_catalog.pg_foreign_data_wrapper
|
||||||
|
WHERE fdwname = ANY (ARRAY['dummy']) ORDER BY fdwname
|
||||||
|
register: fdw_result
|
||||||
|
|
||||||
|
- assert:
|
||||||
|
that:
|
||||||
|
- "fdw_result.stdout_lines[-1] == '(1 row)'"
|
||||||
|
- "'fdw_test' not in fdw_result.stdout_lines[-2]"
|
||||||
|
|
||||||
|
- name: Revoke foreign data wrapper privileges for second time
|
||||||
|
postgresql_privs:
|
||||||
|
state: absent
|
||||||
|
type: foreign_data_wrapper
|
||||||
|
roles: fdw_test
|
||||||
|
privs: ALL
|
||||||
|
objs: dummy
|
||||||
|
db: "{{ db_name }}"
|
||||||
|
login_user: "{{ pg_user }}"
|
||||||
|
register: result
|
||||||
|
ignore_errors: yes
|
||||||
|
|
||||||
|
- assert:
|
||||||
|
that:
|
||||||
|
- "result.changed == false"
|
||||||
|
|
||||||
|
- name: Grant foreign server privileges
|
||||||
|
postgresql_privs:
|
||||||
|
state: present
|
||||||
|
type: foreign_server
|
||||||
|
roles: fdw_test
|
||||||
|
privs: ALL
|
||||||
|
objs: dummy_server
|
||||||
|
db: "{{ db_name }}"
|
||||||
|
login_user: "{{ pg_user }}"
|
||||||
|
register: result
|
||||||
|
ignore_errors: yes
|
||||||
|
|
||||||
|
- assert:
|
||||||
|
that:
|
||||||
|
- "result.changed == true"
|
||||||
|
|
||||||
|
- name: Get foreign server privileges
|
||||||
|
become: True
|
||||||
|
become_user: "{{ pg_user }}"
|
||||||
|
shell: echo "{{ fdw_query }}" | psql -d "{{ db_name }}"
|
||||||
|
vars:
|
||||||
|
fdw_query: >
|
||||||
|
SELECT srvacl FROM pg_catalog.pg_foreign_server
|
||||||
|
WHERE srvname = ANY (ARRAY['dummy_server']) ORDER BY srvname
|
||||||
|
register: fs_result
|
||||||
|
|
||||||
|
- assert:
|
||||||
|
that:
|
||||||
|
- "fs_result.stdout_lines[-1] == '(1 row)'"
|
||||||
|
- "'fdw_test' in fs_result.stdout_lines[-2]"
|
||||||
|
|
||||||
|
- name: Grant foreign server privileges for second time
|
||||||
|
postgresql_privs:
|
||||||
|
state: present
|
||||||
|
type: foreign_server
|
||||||
|
roles: fdw_test
|
||||||
|
privs: ALL
|
||||||
|
objs: dummy_server
|
||||||
|
db: "{{ db_name }}"
|
||||||
|
login_user: "{{ pg_user }}"
|
||||||
|
register: result
|
||||||
|
ignore_errors: yes
|
||||||
|
|
||||||
|
- assert:
|
||||||
|
that:
|
||||||
|
- "result.changed == false"
|
||||||
|
|
||||||
|
- name: Revoke foreign server privileges
|
||||||
|
postgresql_privs:
|
||||||
|
state: absent
|
||||||
|
type: foreign_server
|
||||||
|
roles: fdw_test
|
||||||
|
privs: ALL
|
||||||
|
objs: dummy_server
|
||||||
|
db: "{{ db_name }}"
|
||||||
|
login_user: "{{ pg_user }}"
|
||||||
|
register: result
|
||||||
|
ignore_errors: yes
|
||||||
|
|
||||||
|
- assert:
|
||||||
|
that:
|
||||||
|
- "result.changed == true"
|
||||||
|
|
||||||
|
- name: Get foreign server privileges
|
||||||
|
become: True
|
||||||
|
become_user: "{{ pg_user }}"
|
||||||
|
shell: echo "{{ fdw_query }}" | psql -d "{{ db_name }}"
|
||||||
|
vars:
|
||||||
|
fdw_query: >
|
||||||
|
SELECT srvacl FROM pg_catalog.pg_foreign_server
|
||||||
|
WHERE srvname = ANY (ARRAY['dummy_server']) ORDER BY srvname
|
||||||
|
register: fs_result
|
||||||
|
|
||||||
|
- assert:
|
||||||
|
that:
|
||||||
|
- "fs_result.stdout_lines[-1] == '(1 row)'"
|
||||||
|
- "'fdw_test' not in fs_result.stdout_lines[-2]"
|
||||||
|
|
||||||
|
- name: Revoke foreign server privileges for second time
|
||||||
|
postgresql_privs:
|
||||||
|
state: absent
|
||||||
|
type: foreign_server
|
||||||
|
roles: fdw_test
|
||||||
|
privs: ALL
|
||||||
|
objs: dummy_server
|
||||||
|
db: "{{ db_name }}"
|
||||||
|
login_user: "{{ pg_user }}"
|
||||||
|
register: result
|
||||||
|
ignore_errors: yes
|
||||||
|
|
||||||
|
- assert:
|
||||||
|
that:
|
||||||
|
- "result.changed == false"
|
||||||
|
|
||||||
|
- name: Cleanup
|
||||||
|
become: True
|
||||||
|
become_user: "{{ pg_user }}"
|
||||||
|
shell: echo "{{ item }}" | psql -d "{{ db_name }}"
|
||||||
|
with_items:
|
||||||
|
- DROP ROLE fdw_test
|
||||||
|
- DROP FOREIGN DATA WRAPPER dummy
|
||||||
|
- DROP SERVER dummy_server
|
||||||
|
|
||||||
|
- name: Destroy DB
|
||||||
|
become_user: "{{ pg_user }}"
|
||||||
|
become: True
|
||||||
|
postgresql_db:
|
||||||
|
state: absent
|
||||||
|
name: "{{ db_name }}"
|
||||||
|
login_user: "{{ pg_user }}"
|
Loading…
Reference in a new issue