diff --git a/changelogs/fragments/54517-include-partition-table-postgresql-privs.yaml b/changelogs/fragments/54517-include-partition-table-postgresql-privs.yaml new file mode 100644 index 0000000000..cdd0fcebaf --- /dev/null +++ b/changelogs/fragments/54517-include-partition-table-postgresql-privs.yaml @@ -0,0 +1,2 @@ +bugfixes: +- "Include partition tables in the ALL_IN_SCHEMA option for postgresql-privs (https://github.com/ansible/ansible/issues/54516)" \ No newline at end of file diff --git a/lib/ansible/modules/database/postgresql/postgresql_privs.py b/lib/ansible/modules/database/postgresql/postgresql_privs.py index 557511c241..4bd321748d 100644 --- a/lib/ansible/modules/database/postgresql/postgresql_privs.py +++ b/lib/ansible/modules/database/postgresql/postgresql_privs.py @@ -54,11 +54,11 @@ options: objs: description: - Comma separated list of database objects to set privileges on. - - If I(type) is C(table), C(sequence) or C(function), the special value - C(ALL_IN_SCHEMA) can be provided instead to specify all database - objects of type I(type) in the schema specified via I(schema). (This - also works with PostgreSQL < 9.0.) (C(ALL_IN_SCHEMA) is available for - C(function) from version 2.8) + - If I(type) is C(table), C(partition table), C(sequence) or C(function), + the special valueC(ALL_IN_SCHEMA) can be provided instead to specify all + database objects of type I(type) in the schema specified via I(schema). + (This also works with PostgreSQL < 9.0.) (C(ALL_IN_SCHEMA) is available + for C(function) and C(partition table) from version 2.8) - If I(type) is C(database), this parameter can be omitted, in which case privileges are set for the database specified via I(database). - 'If I(type) is I(function), colons (":") in object names will be @@ -541,7 +541,7 @@ class Connection(object): query = """SELECT relacl FROM pg_catalog.pg_class c JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace - WHERE nspname = %s AND relkind = 'r' AND relname = ANY (%s) + WHERE nspname = %s AND relkind in ('r','p') AND relname = ANY (%s) ORDER BY relname""" self.cursor.execute(query, (schema, tables)) return [t[0] for t in self.cursor.fetchall()] diff --git a/test/integration/targets/postgresql/tasks/postgresql_privs.yml b/test/integration/targets/postgresql/tasks/postgresql_privs.yml index 8de1b28018..a9a22c6a35 100644 --- a/test/integration/targets/postgresql/tasks/postgresql_privs.yml +++ b/test/integration/targets/postgresql/tasks/postgresql_privs.yml @@ -371,6 +371,189 @@ login_user: "{{ db_user3 }}" login_password: password +################################################# +# Test ALL_IN_SCHEMA for 'partioned tables type # +################################################# + +# Partioning tables is a feature introduced in Postgresql 10. +# (see https://www.postgresql.org/docs/10/ddl-partitioning.html ) +# The test below check for this version + +# Function ALL_IN_SCHEMA Setup +- name: Create partioned table for test purpose + postgresql_query: + query: CREATE TABLE public.testpt (id int not null, logdate date not null) PARTITION BY RANGE (logdate); + db: "{{ db_name }}" + login_user: "{{ db_user3 }}" + login_password: password + when: postgres_version_resp.stdout is version('10', '>=') + +# Test +- name: Grant execute to all tables in check mode + postgresql_privs: + type: table + state: present + privs: SELECT + roles: "{{ db_user2 }}" + objs: ALL_IN_SCHEMA + schema: public + db: "{{ db_name }}" + login_user: "{{ db_user3 }}" + login_password: password + register: result + ignore_errors: yes + when: postgres_version_resp.stdout is version('10', '>=') + check_mode: yes + +# Checks +- name: Check that all partitioned tables don't have select privileges after the check mode task + postgresql_query: + query: SELECT grantee, privilege_type FROM information_schema.role_table_grants WHERE table_name='testpt' and privilege_type='SELECT' and grantee = %(grantuser)s + db: "{{ db_name }}" + login_user: '{{ db_user2 }}' + login_password: password + named_args: + grantuser: '{{ db_user2 }}' + become: yes + become_user: "{{ pg_user }}" + register: result + when: postgres_version_resp.stdout is version('10', '>=') + +- assert: + that: + - result.rowcount == 0 + when: postgres_version_resp.stdout is version('10', '>=') + + +# Test +- name: Grant execute to all tables + postgresql_privs: + type: table + state: present + privs: SELECT + roles: "{{ db_user2 }}" + objs: ALL_IN_SCHEMA + schema: public + db: "{{ db_name }}" + login_user: "{{ db_user3 }}" + login_password: password + register: result + ignore_errors: yes + when: postgres_version_resp.stdout is version('10', '>=') + +# Checks +- assert: + that: result.changed == true + when: postgres_version_resp.stdout is version('10', '>=') + +- name: Check that all partitioned tables have select privileges + postgresql_query: + query: SELECT grantee, privilege_type FROM information_schema.role_table_grants WHERE table_name='testpt' and privilege_type='SELECT' and grantee = %(grantuser)s + db: "{{ db_name }}" + login_user: '{{ db_user2 }}' + login_password: password + named_args: + grantuser: '{{ db_user2 }}' + become: yes + become_user: "{{ pg_user }}" + register: result + when: postgres_version_resp.stdout is version('10', '>=') + +- assert: + that: + - result.rowcount == 1 + when: postgres_version_resp.stdout is version('10', '>=') + +# Test +- name: Grant execute to all tables again to see no changes are reported + postgresql_privs: + type: table + state: present + privs: SELECT + roles: "{{ db_user2 }}" + objs: ALL_IN_SCHEMA + schema: public + db: "{{ db_name }}" + login_user: "{{ db_user3 }}" + login_password: password + register: result + ignore_errors: yes + when: postgres_version_resp.stdout is version('10', '>=') + +# Checks +- assert: + that: result.changed == false + when: postgres_version_resp.stdout is version('10', '>=') + +# Test +- name: Revoke SELECT to all tables + postgresql_privs: + type: table + state: absent + privs: SELECT + roles: "{{ db_user2 }}" + objs: ALL_IN_SCHEMA + schema: public + db: "{{ db_name }}" + login_user: "{{ db_user3 }}" + login_password: password + register: result + ignore_errors: yes + when: postgres_version_resp.stdout is version('10', '>=') + +# Checks +- assert: + that: result.changed == true + when: postgres_version_resp.stdout is version('10', '>=') + +- name: Check that all partitioned tables don't have select privileges + postgresql_query: + query: SELECT grantee, privilege_type FROM information_schema.role_table_grants WHERE table_name='testpt' and privilege_type='SELECT' and grantee = %(grantuser)s + db: "{{ db_name }}" + login_user: '{{ db_user2 }}' + login_password: password + named_args: + grantuser: '{{ db_user2 }}' + become: yes + become_user: "{{ pg_user }}" + register: result + when: postgres_version_resp.stdout is version('10', '>=') + +- assert: + that: + - result.rowcount == 0 + when: postgres_version_resp.stdout is version('10', '>=') + +# Test +- name: Revoke SELECT to all tables and no changes are reported + postgresql_privs: + type: table + state: absent + privs: SELECT + roles: "{{ db_user2 }}" + objs: ALL_IN_SCHEMA + schema: public + db: "{{ db_name }}" + login_user: "{{ db_user3 }}" + login_password: password + register: result + ignore_errors: yes + when: postgres_version_resp.stdout is version('10', '>=') + +- assert: + that: result.changed == false + when: postgres_version_resp.stdout is version('10', '>=') + +# Table ALL_IN_SCHEMA cleanup +- name: Remove table for test + postgresql_query: + query: DROP TABLE public.testpt; + db: "{{ db_name }}" + login_user: "{{ db_user3 }}" + login_password: password + ignore_errors: yes + when: postgres_version_resp.stdout is version('10', '>=') + # Cleanup - name: Remove user given permissions postgresql_user: