postgresql_privs: add support a type parameter option for types (#63555)
* postgresql_privs: add support a type parameter option for types * postgresql_privs: add support a type parameter option for types, add changelog fragment * postgresql_privs: add support a type parameter option for types, add schema handling * postgresql_privs: add support a type parameter option for types, fix typo * postgresql_privs: add support a type parameter option for types, add comment
This commit is contained in:
parent
ae16a840f6
commit
7dd46f7b2d
3 changed files with 306 additions and 8 deletions
|
@ -0,0 +1,2 @@
|
|||
minor_changes:
|
||||
- postgresql_privs - add support for TYPE as object types in postgresql_privs module (https://github.com/ansible/ansible/issues/62432).
|
|
@ -45,12 +45,13 @@ options:
|
|||
type:
|
||||
description:
|
||||
- Type of database object to set privileges on.
|
||||
- The `default_privs` choice is available starting at version 2.7.
|
||||
- The 'foreign_data_wrapper' and 'foreign_server' object types are available from Ansible version '2.8'.
|
||||
- The C(default_privs) choice is available starting at version 2.7.
|
||||
- The C(foreign_data_wrapper) and C(foreign_server) object types are available from Ansible version '2.8'.
|
||||
- The C(type) choice is available from Ansible version '2.10'.
|
||||
type: str
|
||||
default: table
|
||||
choices: [ database, default_privs, foreign_data_wrapper, foreign_server, function,
|
||||
group, language, table, tablespace, schema, sequence ]
|
||||
group, language, table, tablespace, schema, sequence, type ]
|
||||
objs:
|
||||
description:
|
||||
- Comma separated list of database objects to set privileges on.
|
||||
|
@ -69,8 +70,10 @@ options:
|
|||
schema:
|
||||
description:
|
||||
- Schema that contains the database objects specified via I(objs).
|
||||
- May only be provided if I(type) is C(table), C(sequence), C(function)
|
||||
or C(default_privs). Defaults to C(public) in these cases.
|
||||
- May only be provided if I(type) is C(table), C(sequence), C(function), C(type),
|
||||
or C(default_privs). Defaults to C(public) in these cases.
|
||||
- Pay attention, for embedded types when I(type=type)
|
||||
I(schema) can be C(pg_catalog) or C(information_schema) respectively.
|
||||
type: str
|
||||
roles:
|
||||
description:
|
||||
|
@ -326,6 +329,15 @@ EXAMPLES = r'''
|
|||
type: foreign_data_wrapper
|
||||
role: reader
|
||||
|
||||
# Available since version 2.10
|
||||
- name: GRANT ALL PRIVILEGES ON TYPE customtype TO reader
|
||||
postgresql_privs:
|
||||
db: test
|
||||
objs: customtype
|
||||
privs: ALL
|
||||
type: type
|
||||
role: reader
|
||||
|
||||
# Available since version 2.8
|
||||
- name: GRANT ALL PRIVILEGES ON FOREIGN SERVER fdw_server TO reader
|
||||
postgresql_privs:
|
||||
|
@ -376,6 +388,16 @@ EXAMPLES = r'''
|
|||
type: default_privs
|
||||
role: reader
|
||||
target_roles: librarian
|
||||
|
||||
# Available since version 2.10
|
||||
- name: Grant type privileges for pg_catalog.numeric type to alice
|
||||
postgresql_privs:
|
||||
type: type
|
||||
roles: alice
|
||||
privs: ALL
|
||||
objs: numeric
|
||||
schema: pg_catalog
|
||||
db: acme
|
||||
'''
|
||||
|
||||
RETURN = r'''
|
||||
|
@ -622,6 +644,13 @@ class Connection(object):
|
|||
self.cursor.execute(query, (fs,))
|
||||
return [t[0] for t in self.cursor.fetchall()]
|
||||
|
||||
def get_type_acls(self, schema, types):
|
||||
query = """SELECT t.typacl FROM pg_catalog.pg_type t
|
||||
JOIN pg_catalog.pg_namespace n ON n.oid = t.typnamespace
|
||||
WHERE n.nspname = %s AND t.typname = ANY (%s) ORDER BY typname"""
|
||||
self.cursor.execute(query, (schema, types))
|
||||
return [t[0] for t in self.cursor.fetchall()]
|
||||
|
||||
# Manipulating privileges
|
||||
|
||||
def manipulate_privs(self, obj_type, privs, objs, roles, target_roles,
|
||||
|
@ -669,6 +698,8 @@ class Connection(object):
|
|||
get_status = self.get_foreign_data_wrapper_acls
|
||||
elif obj_type == 'foreign_server':
|
||||
get_status = self.get_foreign_server_acls
|
||||
elif obj_type == 'type':
|
||||
get_status = partial(self.get_type_acls, schema_qualifier)
|
||||
else:
|
||||
raise Error('Unsupported database object type "%s".' % obj_type)
|
||||
|
||||
|
@ -685,7 +716,7 @@ class Connection(object):
|
|||
except Exception:
|
||||
raise Error('Illegal function signature: "%s".' % obj)
|
||||
obj_ids.append('"%s"."%s"(%s' % (schema_qualifier, f, args))
|
||||
elif obj_type in ['table', 'sequence']:
|
||||
elif obj_type in ['table', 'sequence', 'type']:
|
||||
obj_ids = ['"%s"."%s"' % (schema_qualifier, o) for o in objs]
|
||||
else:
|
||||
obj_ids = ['"%s"' % o for o in objs]
|
||||
|
@ -892,7 +923,8 @@ def main():
|
|||
'group',
|
||||
'default_privs',
|
||||
'foreign_data_wrapper',
|
||||
'foreign_server']),
|
||||
'foreign_server',
|
||||
'type', ]),
|
||||
objs=dict(required=False, aliases=['obj']),
|
||||
schema=dict(required=False),
|
||||
roles=dict(required=True, aliases=['role']),
|
||||
|
@ -917,7 +949,7 @@ def main():
|
|||
# Create type object as namespace for module params
|
||||
p = type('Params', (), module.params)
|
||||
# param "schema": default, allowed depends on param "type"
|
||||
if p.type in ['table', 'sequence', 'function', 'default_privs']:
|
||||
if p.type in ['table', 'sequence', 'function', 'type', 'default_privs']:
|
||||
p.schema = p.schema or 'public'
|
||||
elif p.schema:
|
||||
module.fail_json(msg='Argument "schema" is not allowed '
|
||||
|
|
|
@ -677,9 +677,271 @@
|
|||
login_password: password
|
||||
ignore_errors: yes
|
||||
when: postgres_version_resp.stdout is version('10', '>=')
|
||||
|
||||
###########################################
|
||||
# Test for 'type' value of type parameter #
|
||||
###########################################
|
||||
|
||||
# Test
|
||||
- name: Grant type privileges
|
||||
become: yes
|
||||
become_user: "{{ pg_user }}"
|
||||
postgresql_privs:
|
||||
state: present
|
||||
type: type
|
||||
roles: "{{ db_user2 }}"
|
||||
privs: ALL
|
||||
objs: numeric
|
||||
schema: pg_catalog
|
||||
db: "{{ db_name }}"
|
||||
login_user: "{{ pg_user }}"
|
||||
register: result
|
||||
when: postgres_version_resp.stdout is version('10', '>=')
|
||||
|
||||
# Checks
|
||||
- assert:
|
||||
that:
|
||||
- result is changed
|
||||
when: postgres_version_resp.stdout is version('10', '>=')
|
||||
|
||||
- name: Get type privileges
|
||||
become: yes
|
||||
become_user: "{{ pg_user }}"
|
||||
postgresql_query:
|
||||
login_user: "{{ pg_user }}"
|
||||
login_db: "{{ db_name }}"
|
||||
query: SELECT typacl FROM pg_catalog.pg_type WHERE typname = 'numeric';
|
||||
register: typ_result
|
||||
when: postgres_version_resp.stdout is version('10', '>=')
|
||||
|
||||
- assert:
|
||||
that:
|
||||
- "'{{ db_user2 }}' in typ_result.query_result[0].typacl"
|
||||
when: postgres_version_resp.stdout is version('10', '>=')
|
||||
|
||||
- name: Grant type privileges again using check_mode
|
||||
become: yes
|
||||
become_user: "{{ pg_user }}"
|
||||
postgresql_privs:
|
||||
state: present
|
||||
type: type
|
||||
roles: "{{ db_user2 }}"
|
||||
privs: ALL
|
||||
objs: numeric
|
||||
schema: pg_catalog
|
||||
db: "{{ db_name }}"
|
||||
login_user: "{{ pg_user }}"
|
||||
register: result
|
||||
check_mode: yes
|
||||
when: postgres_version_resp.stdout is version('10', '>=')
|
||||
|
||||
# Checks
|
||||
- assert:
|
||||
that:
|
||||
- result is not changed
|
||||
when: postgres_version_resp.stdout is version('10', '>=')
|
||||
|
||||
- name: Get type privileges
|
||||
become: yes
|
||||
become_user: "{{ pg_user }}"
|
||||
postgresql_query:
|
||||
login_user: "{{ pg_user }}"
|
||||
login_db: "{{ db_name }}"
|
||||
query: SELECT typacl FROM pg_catalog.pg_type WHERE typname = 'numeric';
|
||||
register: typ_result
|
||||
when: postgres_version_resp.stdout is version('10', '>=')
|
||||
|
||||
- assert:
|
||||
that:
|
||||
- "'{{ db_user2 }}' in typ_result.query_result[0].typacl"
|
||||
when: postgres_version_resp.stdout is version('10', '>=')
|
||||
|
||||
- name: Grant type privileges again
|
||||
become: yes
|
||||
become_user: "{{ pg_user }}"
|
||||
postgresql_privs:
|
||||
state: present
|
||||
type: type
|
||||
roles: "{{ db_user2 }}"
|
||||
privs: ALL
|
||||
objs: numeric
|
||||
schema: pg_catalog
|
||||
db: "{{ db_name }}"
|
||||
login_user: "{{ pg_user }}"
|
||||
register: result
|
||||
when: postgres_version_resp.stdout is version('10', '>=')
|
||||
|
||||
# Checks
|
||||
- assert:
|
||||
that:
|
||||
- result is not changed
|
||||
when: postgres_version_resp.stdout is version('10', '>=')
|
||||
|
||||
- name: Get type privileges
|
||||
become: yes
|
||||
become_user: "{{ pg_user }}"
|
||||
postgresql_query:
|
||||
login_user: "{{ pg_user }}"
|
||||
login_db: "{{ db_name }}"
|
||||
query: SELECT typacl FROM pg_catalog.pg_type WHERE typname = 'numeric';
|
||||
register: typ_result
|
||||
when: postgres_version_resp.stdout is version('10', '>=')
|
||||
|
||||
- assert:
|
||||
that:
|
||||
- "'{{ db_user2 }}' in typ_result.query_result[0].typacl"
|
||||
when: postgres_version_resp.stdout is version('10', '>=')
|
||||
|
||||
- name: Revoke type privileges in check_mode
|
||||
become: yes
|
||||
become_user: "{{ pg_user }}"
|
||||
postgresql_privs:
|
||||
state: absent
|
||||
type: type
|
||||
roles: "{{ db_user2 }}"
|
||||
privs: ALL
|
||||
objs: numeric
|
||||
schema: pg_catalog
|
||||
db: "{{ db_name }}"
|
||||
login_user: "{{ pg_user }}"
|
||||
register: result
|
||||
check_mode: yes
|
||||
when: postgres_version_resp.stdout is version('10', '>=')
|
||||
|
||||
# Checks
|
||||
- assert:
|
||||
that:
|
||||
- result is changed
|
||||
when: postgres_version_resp.stdout is version('10', '>=')
|
||||
|
||||
- name: Get type privileges
|
||||
become: yes
|
||||
become_user: "{{ pg_user }}"
|
||||
postgresql_query:
|
||||
login_user: "{{ pg_user }}"
|
||||
login_db: "{{ db_name }}"
|
||||
query: SELECT typacl FROM pg_catalog.pg_type WHERE typname = 'numeric';
|
||||
register: typ_result
|
||||
when: postgres_version_resp.stdout is version('10', '>=')
|
||||
|
||||
- assert:
|
||||
that:
|
||||
- "'{{ db_user2 }}' in typ_result.query_result[0].typacl"
|
||||
when: postgres_version_resp.stdout is version('10', '>=')
|
||||
|
||||
- name: Revoke type privileges
|
||||
become: yes
|
||||
become_user: "{{ pg_user }}"
|
||||
postgresql_privs:
|
||||
state: absent
|
||||
type: type
|
||||
roles: "{{ db_user2 }}"
|
||||
privs: ALL
|
||||
objs: numeric
|
||||
schema: pg_catalog
|
||||
db: "{{ db_name }}"
|
||||
login_user: "{{ pg_user }}"
|
||||
register: result
|
||||
when: postgres_version_resp.stdout is version('10', '>=')
|
||||
|
||||
# Checks
|
||||
- assert:
|
||||
that:
|
||||
- result is changed
|
||||
when: postgres_version_resp.stdout is version('10', '>=')
|
||||
|
||||
- name: Get type privileges
|
||||
become: yes
|
||||
become_user: "{{ pg_user }}"
|
||||
postgresql_query:
|
||||
login_user: "{{ pg_user }}"
|
||||
login_db: "{{ db_name }}"
|
||||
query: SELECT typacl FROM pg_catalog.pg_type WHERE typname = 'numeric';
|
||||
register: typ_result
|
||||
when: postgres_version_resp.stdout is version('10', '>=')
|
||||
|
||||
- assert:
|
||||
that:
|
||||
- "'{{ db_user2 }}' not in typ_result.query_result[0].typacl"
|
||||
when: postgres_version_resp.stdout is version('10', '>=')
|
||||
|
||||
# type with default schema (public):
|
||||
- name: Create custom type in schema public
|
||||
become: yes
|
||||
become_user: "{{ pg_user }}"
|
||||
postgresql_query:
|
||||
login_user: "{{ pg_user }}"
|
||||
login_db: "{{ db_name }}"
|
||||
query: "CREATE TYPE compfoo AS (f1 int, f2 text)"
|
||||
when: postgres_version_resp.stdout is version('10', '>=')
|
||||
|
||||
# Test
|
||||
- name: Grant type privileges with default schema
|
||||
become: yes
|
||||
become_user: "{{ pg_user }}"
|
||||
postgresql_privs:
|
||||
state: present
|
||||
type: type
|
||||
roles: "{{ db_user2 }}"
|
||||
privs: ALL
|
||||
objs: compfoo
|
||||
db: "{{ db_name }}"
|
||||
login_user: "{{ pg_user }}"
|
||||
register: result
|
||||
when: postgres_version_resp.stdout is version('10', '>=')
|
||||
|
||||
# Checks
|
||||
- assert:
|
||||
that:
|
||||
- result is changed
|
||||
when: postgres_version_resp.stdout is version('10', '>=')
|
||||
|
||||
- name: Get type privileges
|
||||
become: yes
|
||||
become_user: "{{ pg_user }}"
|
||||
postgresql_query:
|
||||
login_user: "{{ pg_user }}"
|
||||
login_db: "{{ db_name }}"
|
||||
query: >
|
||||
SELECT t.typacl FROM pg_catalog.pg_type t JOIN pg_catalog.pg_namespace n
|
||||
ON n.oid = t.typnamespace WHERE t.typname = 'compfoo' AND n.nspname = 'public';
|
||||
register: typ_result
|
||||
when: postgres_version_resp.stdout is version('10', '>=')
|
||||
|
||||
- assert:
|
||||
that:
|
||||
- "'{{ db_user2 }}' in typ_result.query_result[0].typacl"
|
||||
when: postgres_version_resp.stdout is version('10', '>=')
|
||||
|
||||
# Cleanup
|
||||
- name: Remove privs
|
||||
become: yes
|
||||
become_user: "{{ pg_user }}"
|
||||
postgresql_privs:
|
||||
state: absent
|
||||
type: type
|
||||
roles: "{{ db_user2 }}"
|
||||
privs: ALL
|
||||
objs: compfoo
|
||||
db: "{{ db_name }}"
|
||||
login_user: "{{ pg_user }}"
|
||||
when: postgres_version_resp.stdout is version('10', '>=')
|
||||
|
||||
- name: Reassign ownership
|
||||
become_user: "{{ pg_user }}"
|
||||
become: yes
|
||||
postgresql_owner:
|
||||
login_user: "{{ pg_user }}"
|
||||
db: "{{ db_name }}"
|
||||
new_owner: "{{ pg_user }}"
|
||||
reassign_owned_by: "{{ item }}"
|
||||
loop:
|
||||
- "{{ db_user2 }}"
|
||||
- "{{ db_user3 }}"
|
||||
|
||||
- name: Remove user given permissions
|
||||
become: yes
|
||||
become_user: "{{ pg_user }}"
|
||||
postgresql_user:
|
||||
name: "{{ db_user2 }}"
|
||||
state: absent
|
||||
|
@ -687,6 +949,8 @@
|
|||
login_user: "{{ pg_user }}"
|
||||
|
||||
- name: Remove user owner of objects
|
||||
become: yes
|
||||
become_user: "{{ pg_user }}"
|
||||
postgresql_user:
|
||||
name: "{{ db_user3 }}"
|
||||
state: absent
|
||||
|
|
Loading…
Reference in a new issue