Skip to content

Commit

Permalink
Update natefoo.postgresql_objects role
Browse files Browse the repository at this point in the history
  • Loading branch information
natefoo committed Apr 1, 2015
1 parent 101a052 commit b8ad8e3
Show file tree
Hide file tree
Showing 5 changed files with 130 additions and 100 deletions.
44 changes: 42 additions & 2 deletions roles/natefoo.postgresql_objects/README.md
Expand Up @@ -2,18 +2,22 @@ PostgreSQL Objects
==================

PostgreSQL Objects is an [Ansible][ansible] role for managing PostgreSQL users,
databases, and privileges. It is a small wrapper around the
groups databases, and privileges. It is a small wrapper around the
[`postgresql_user`][pguser], [`postgresql_db`][pgdb] and
[`postgresql_privs`][pgprivs] standard modules provided with Ansible. Many
PostgreSQL roles exist in [Ansible Galaxy][ansiblegalaxy] but none exist for
only managing database objects without managing the server installation and
configuration.

Ansible >= 1.8 is required due to the use of the `default( omit )` construct in
module parameter templating.

[ansible]: http://www.ansible.com
[pguser]: http://docs.ansible.com/postgresql_user_module.html
[pgdb]: http://docs.ansible.com/postgresql_db_module.html
[pgprivs]: http://docs.ansible.com/postgresql_privs_module.html
[ansiblegalaxy]: https://galaxy.ansible.com
[shell]: http://docs.ansible.com/shell_module.html

Requirements
------------
Expand All @@ -35,6 +39,8 @@ pre-task in the same play as this role:
roles:
- postgresql_objects

[psycopg2]: http://initd.org/psycopg/

Role Variables
--------------

Expand All @@ -43,6 +49,12 @@ Objects are configured via the following variables:
- `postgresql_objects_users`: A list of PostgreSQL users to create or drop.
List items are dictionaries, keys match the [`postgresql_user`][pguser]
module parameters.
- `postgresql_objects_groups`: A list of PostgreSQL groups to create or drop.
List items are dictionaries, keys match the [`postgresql_user`][pguser]
module parameters with the addition of the `users` key, which should itself
be a list of users to add to the group. List items are dictionaries which
should have the `name` key (required) and optionally the `state` key (whose
values are either `present` (default) or `absent`).
- `postgresql_objects_databases`: A list of databases to create or drop. List
items are dictionaries, keys match the [`postgresql_db`][pgdb] module
parameters.
Expand All @@ -62,6 +74,14 @@ that has privileges to perform the requested changes. However, these can be
left unset if you use a system user with administrative privileges in
PostgreSQL, (such as with `sudo: yes` and `sudo_user: postgres` in your play).

**`postgresql_objects_groups` caveats**: Managing group membership **does not
use Ansible modules** because the existing set of provided modules do not
provide the needed functionality for managing groups. Instead, groups are
managed by piping SQL to the `psql(1)` command line utility with Ansible's
[`shell`][shell] module, so extra care should be taken when using the group
functionality. Also, the `postgresql_objects_login_password` option cannot be
used with group membership management.

**`postgresql_objects_ignore_revoke_failure` caveats**: If you typo a user, db,
or table to revoke, this will happily indicate that revoking was successful
(the named user does not have the listed privilege(s) on the provided db, after
Expand Down Expand Up @@ -128,13 +148,33 @@ SELECT privileges to `baz` on sequence `bar_quux_seq` in database `foo`:
sudo: yes
sudo_user: postgres

Revoke specific privileges for user `foo` and delete user `baz`:
Create a group `plugh` and add `foo` and `baz` to this group:

- hosts: dbservers
vars:
postgresql_objects_groups:
- name: plugh
users:
- name: foo
- name: baz
roles:
- role: postgresql_objects
sudo: yes
sudo_user: postgres

Revoke specific privileges for user `foo`, remove user `baz` from group
`plugh`, and delete user `baz`:

- hosts: dbservers
vars:
postgresql_objects_users:
- name: baz
state: absent
postgresql_objects_groups:
- name: plugh
users:
- name: baz
state: absent
postgresql_objects_privileges:
- database: foo
roles: foo
Expand Down
6 changes: 1 addition & 5 deletions roles/natefoo.postgresql_objects/defaults/main.yml
Expand Up @@ -23,11 +23,7 @@
# work.
postgresql_objects_ignore_revoke_failure: true

postgresql_objects_login_host: ""
postgresql_objects_login_user: ""
postgresql_objects_login_password: ""
postgresql_objects_port: 5432

postgresql_objects_users: []
postgresql_objects_groups: []
postgresql_objects_databases: []
postgresql_objects_privileges: []
2 changes: 1 addition & 1 deletion roles/natefoo.postgresql_objects/meta/.galaxy_install_info
@@ -1 +1 @@
{install_date: 'Wed Sep 3 21:18:00 2014', version: master}
{install_date: 'Thu Mar 26 17:31:58 2015', version: '1.0'}
2 changes: 1 addition & 1 deletion roles/natefoo.postgresql_objects/meta/main.yml
Expand Up @@ -4,7 +4,7 @@ galaxy_info:
description: "Configure PostgreSQL objects: users (roles), databases, and privileges"
company: Penn State University
license: AFL v3.0
min_ansible_version: 1.4
min_ansible_version: 1.8
platforms:
- name: EL
versions:
Expand Down
176 changes: 85 additions & 91 deletions roles/natefoo.postgresql_objects/tasks/main.yml
@@ -1,127 +1,121 @@
---
# tasks file for natefoo.postgresql-objects

# Some duplicated tasks here due to the inability to omit missing params,
# should be fixed eventually:
# https://github.com/ansible/ansible/pull/8323

# Revoke privs first so later user drop can succeed
- name: Revoke extra privileges (grant_option set)
postgresql_privs: database={{ item.database }}
roles={{ item.roles }}
type={{ item.type | default( 'table' ) }}
objs={{ item.objs | default( '' ) }}
privs={{ item.privs | default( '' ) }}
schema={{ item.schema | default( '' ) }}
grant_option={{ item.grant_option }}
state={{ item.state | default( 'present' ) }}
login_host={{ postgresql_objects_login_host }}
login_user={{ postgresql_objects_login_user }}
login_password={{ postgresql_objects_login_password }}
port={{ postgresql_objects_port }}
with_items: postgresql_objects_privileges
register: revoke
failed_when: "postgresql_objects_ignore_revoke_failure and revoke.failed is defined and ((revoke.failed and 'does not exist' not in revoke.msg) or (revoke.failed and ',' in item.roles))"
when: item.state is defined and item.state == 'absent' and item.grant_option is defined

- name: Revoke extra privileges
postgresql_privs: database={{ item.database }}
roles={{ item.roles }}
type={{ item.type | default( 'table' ) }}
objs={{ item.objs | default( '' ) }}
privs={{ item.privs | default( '' ) }}
schema={{ item.schema | default( '' ) }}
state={{ item.state | default( 'present' ) }}
login_host={{ postgresql_objects_login_host }}
login_user={{ postgresql_objects_login_user }}
login_password={{ postgresql_objects_login_password }}
port={{ postgresql_objects_port }}
type={{ item.type | default( omit ) }}
objs={{ item.objs | default( omit ) }}
privs={{ item.privs | default( omit ) }}
schema={{ item.schema | default( omit ) }}
grant_option={{ item.grant_option | default(omit) }}
state={{ item.state | default( omit ) }}
login_host={{ postgresql_objects_login_host | default( omit ) }}
login_user={{ postgresql_objects_login_user | default( omit ) }}
login_password={{ postgresql_objects_login_password | default( omit ) }}
port={{ postgresql_objects_port | default( omit ) }}
with_items: postgresql_objects_privileges
register: revoke
failed_when: "postgresql_objects_ignore_revoke_failure and revoke.failed is defined and ((revoke.failed and 'does not exist' not in revoke.msg) or (revoke.failed and ',' in item.roles))"
when: item.state is defined and item.state == 'absent' and item.grant_option is not defined
when: item.state is defined and item.state == 'absent'

# Drop databases first so later user drop can succeed
- name: Drop databases
postgresql_db: name={{ item.name }}
owner={{ item.owner | default( '' ) }}
template={{ item.template | default( '' ) }}
encoding={{ item.encoding | default( '' ) }}
lc_collate={{ item.lc_collate | default( '' ) }}
lc_ctype={{ item.lc_ctype | default( '' ) }}
owner={{ item.owner | default( omit ) }}
template={{ item.template | default( omit ) }}
encoding={{ item.encoding | default( omit ) }}
lc_collate={{ item.lc_collate | default( omit ) }}
lc_ctype={{ item.lc_ctype | default( omit ) }}
state={{ item.state }}
login_host={{ postgresql_objects_login_host }}
login_user={{ postgresql_objects_login_user }}
login_password={{ postgresql_objects_login_password }}
port={{ postgresql_objects_port }}
login_host={{ postgresql_objects_login_host | default( omit ) }}
login_user={{ postgresql_objects_login_user | default( omit ) }}
login_password={{ postgresql_objects_login_password | default( omit ) }}
port={{ postgresql_objects_port | default( omit ) }}
with_items: postgresql_objects_databases
when: item.state is defined and item.state == 'absent'

- name: Create and drop users
postgresql_user: name={{ item.name }}
password={{ item.password | default( 'NULL' ) }}
role_attr_flags={{ item.role_attr_flags | default( '' ) }}
encrypted={{ item.encrypted | default( 'no' ) }}
state={{ item.state | default( 'present' ) }}
login_host={{ postgresql_objects_login_host }}
login_user={{ postgresql_objects_login_user }}
login_password={{ postgresql_objects_login_password }}
port={{ postgresql_objects_port }}
password={{ item.password | default( omit ) }}
role_attr_flags={{ item.role_attr_flags | default( omit ) }}
encrypted={{ item.encrypted | default( omit ) }}
state={{ item.state | default( omit ) }}
login_host={{ postgresql_objects_login_host | default( omit ) }}
login_user={{ postgresql_objects_login_user | default( omit ) }}
login_password={{ postgresql_objects_login_password | default( omit ) }}
port={{ postgresql_objects_port | default( omit ) }}
with_items: postgresql_objects_users

- name: Create groups
postgresql_user: name={{ item.name }}
password={{ item.password | default( omit ) }}
role_attr_flags={{ item.role_attr_flags | default( omit ) }}
encrypted={{ item.encrypted | default( omit ) }}
login_host={{ postgresql_objects_login_host | default( omit ) }}
login_user={{ postgresql_objects_login_user | default( omit ) }}
login_password={{ postgresql_objects_login_password | default( omit ) }}
port={{ postgresql_objects_port | default( omit ) }}
with_items: postgresql_objects_groups
when: item.state is not defined or (item.state is defined and item.state == 'present')

- name: Add or remove users from groups
shell: echo {{ 'REVOKE' if item.1.state is defined and item.1.state == 'absent' else 'GRANT' }} '{{ item.0.name }}' {{ 'FROM' if item.1.state is defined and item.1.state == 'absent' else 'TO' }} '{{ item.1.name }}' | psql -w {{ '-h ' ~ postgresql_objects_login_host if postgresql_objects_login_host is defined else '' }} {{ '-U ' ~ postgresql_objects_login_user if postgresql_objects_login_user is defined else '' }} {{ '-p ' ~ postgresql_objects_port if postgresql_objects_port is defined else '' }} postgres
register: psql
failed_when: psql.stderr.startswith( 'ERROR:' )
changed_when: psql.stderr == ''
with_subelements:
- postgresql_objects_groups
- users

- name: Drop groups
postgresql_user: name={{ item.name }}
state={{ item.state }}
login_host={{ postgresql_objects_login_host | default( omit ) }}
login_user={{ postgresql_objects_login_user | default( omit ) }}
login_password={{ postgresql_objects_login_password | default( omit ) }}
port={{ postgresql_objects_port | default( omit ) }}
with_items: postgresql_objects_groups
when: item.state is defined and item.state == 'absent'

- name: Create databases
postgresql_db: name={{ item.name }}
owner={{ item.owner | default( '' ) }}
template={{ item.template | default( '' ) }}
encoding={{ item.encoding | default( '' ) }}
lc_collate={{ item.lc_collate | default( '' ) }}
lc_ctype={{ item.lc_ctype | default( '' ) }}
state={{ item.state | default( 'present' ) }}
login_host={{ postgresql_objects_login_host }}
login_user={{ postgresql_objects_login_user }}
login_password={{ postgresql_objects_login_password }}
port={{ postgresql_objects_port }}
owner={{ item.owner | default( omit ) }}
template={{ item.template | default( omit ) }}
encoding={{ item.encoding | default( omit ) }}
lc_collate={{ item.lc_collate | default( omit ) }}
lc_ctype={{ item.lc_ctype | default( omit ) }}
state={{ item.state | default( omit ) }}
login_host={{ postgresql_objects_login_host | default( omit ) }}
login_user={{ postgresql_objects_login_user | default( omit ) }}
login_password={{ postgresql_objects_login_password | default( omit ) }}
port={{ postgresql_objects_port | default( omit ) }}
with_items: postgresql_objects_databases
when: item.state is not defined or (item.state is defined and item.state == 'present')

- name: Grant user database privileges
postgresql_user: name={{ item.name }}
db={{ item.db }}
priv={{ item.priv }}
login_host={{ postgresql_objects_login_host }}
login_user={{ postgresql_objects_login_user }}
login_password={{ postgresql_objects_login_password }}
port={{ postgresql_objects_port }}
login_host={{ postgresql_objects_login_host | default( omit ) }}
login_user={{ postgresql_objects_login_user | default( omit ) }}
login_password={{ postgresql_objects_login_password | default( omit ) }}
port={{ postgresql_objects_port | default( omit ) }}
with_items: postgresql_objects_users
when: item.db is defined and item.priv is defined and not (item.state is defined and item.state == 'absent')

- name: Grant extra privileges (grant_option set)
postgresql_privs: database={{ item.database }}
roles={{ item.roles }}
type={{ item.type | default( 'table' ) }}
objs={{ item.objs | default( '' ) }}
privs={{ item.privs | default( '' ) }}
schema={{ item.schema | default( '' ) }}
grant_option={{ item.grant_option }}
state={{ item.state | default( 'present' ) }}
login_host={{ postgresql_objects_login_host }}
login_user={{ postgresql_objects_login_user }}
login_password={{ postgresql_objects_login_password }}
port={{ postgresql_objects_port }}
with_items: postgresql_objects_privileges
when: (item.state is not defined or (item.state is defined and item.state == 'present')) and item.grant_option is defined

- name: Grant extra privileges
postgresql_privs: database={{ item.database }}
postgresql_privs: database={{ item.database | default( omit ) }}
roles={{ item.roles }}
type={{ item.type | default( 'table' ) }}
objs={{ item.objs | default( '' ) }}
privs={{ item.privs | default( '' ) }}
schema={{ item.schema | default( '' ) }}
state={{ item.state | default( 'present' ) }}
login_host={{ postgresql_objects_login_host }}
login_user={{ postgresql_objects_login_user }}
login_password={{ postgresql_objects_login_password }}
port={{ postgresql_objects_port }}
type={{ item.type | default( omit ) }}
objs={{ item.objs | default( omit ) }}
privs={{ item.privs | default( omit ) }}
schema={{ item.schema | default( omit ) }}
grant_option={{ item.grant_option | default( omit ) }}
state={{ item.state | default( omit ) }}
login_host={{ postgresql_objects_login_host | default( omit ) }}
login_user={{ postgresql_objects_login_user | default( omit ) }}
login_password={{ postgresql_objects_login_password | default( omit ) }}
port={{ postgresql_objects_port | default( omit ) }}
with_items: postgresql_objects_privileges
when: (item.state is not defined or (item.state is defined and item.state == 'present')) and item.grant_option is not defined
when: (item.state is not defined or (item.state is defined and item.state == 'present'))

0 comments on commit b8ad8e3

Please sign in to comment.