2014-09-26 01:01:01 +00:00
#!/usr/bin/python
# -*- coding: utf-8 -*-
# This file is part of Ansible
#
# Ansible is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Ansible is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
2016-12-06 10:35:05 +00:00
ANSIBLE_METADATA = { ' status ' : [ ' stableinterface ' ] ,
' supported_by ' : ' community ' ,
' version ' : ' 1.0 ' }
2014-09-26 01:01:01 +00:00
DOCUMENTATION = """
- - -
module : postgresql_privs
version_added : " 1.2 "
short_description : Grant or revoke privileges on PostgreSQL database objects .
description :
- Grant or revoke privileges on PostgreSQL database objects .
- This module is basically a wrapper around most of the functionality of
PostgreSQL ' s GRANT and REVOKE statements with detection of changes
( GRANT / REVOKE I ( privs ) ON I ( type ) I ( objs ) TO / FROM I ( roles ) )
options :
database :
description :
2014-09-29 23:06:42 +00:00
- Name of database to connect to .
2014-09-26 01:01:01 +00:00
- ' Alias: I(db) '
required : yes
state :
description :
- If C ( present ) , the specified privileges are granted , if C ( absent ) they
are revoked .
required : no
default : present
choices : [ present , absent ]
privs :
description :
- Comma separated list of privileges to grant / revoke .
- ' Alias: I(priv) '
required : no
type :
description :
- Type of database object to set privileges on .
required : no
default : table
choices : [ table , sequence , function , database ,
schema , language , tablespace , group ]
objs :
description :
2014-09-29 23:06:42 +00:00
- Comma separated list of database objects to set privileges on .
2014-09-26 01:01:01 +00:00
- If I ( type ) is C ( table ) or C ( sequence ) , 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 . )
- 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
replaced with commas ( needed to specify function signatures , see
examples ) '
- ' Alias: I(obj) '
required : no
schema :
description :
- Schema that contains the database objects specified via I ( objs ) .
- May only be provided if I ( type ) is C ( table ) , C ( sequence ) or
C ( function ) . Defaults to C ( public ) in these cases .
required : no
roles :
description :
- Comma separated list of role ( user / group ) names to set permissions for .
- The special value C ( PUBLIC ) can be provided instead to set permissions
for the implicitly defined PUBLIC group .
- ' Alias: I(role) '
required : yes
grant_option :
description :
- Whether C ( role ) may grant / revoke the specified privileges / group
memberships to others .
- Set to C ( no ) to revoke GRANT OPTION , leave unspecified to
make no changes .
- I ( grant_option ) only has an effect if I ( state ) is C ( present ) .
- ' Alias: I(admin_option) '
required : no
choices : [ ' yes ' , ' no ' ]
host :
description :
- Database host address . If unspecified , connect via Unix socket .
- ' Alias: I(login_host) '
default : null
required : no
port :
description :
- Database port to connect to .
required : no
default : 5432
2014-09-29 23:06:42 +00:00
unix_socket :
2014-12-03 16:16:59 +00:00
description :
2014-09-29 23:06:42 +00:00
- Path to a Unix domain socket for local connections .
- ' Alias: I(login_unix_socket) '
required : false
default : null
2014-09-26 01:01:01 +00:00
login :
description :
- The username to authenticate with .
- ' Alias: I(login_user) '
default : postgres
password :
description :
- The password to authenticate with .
- ' Alias: I(login_password)) '
default : null
required : no
2016-11-22 15:18:45 +00:00
ssl_mode :
description :
- Determines whether or with what priority a secure SSL TCP / IP connection will be negotiated with the server .
- See https : / / www . postgresql . org / docs / current / static / libpq - ssl . html for more information on the modes .
required : false
default : disable
choices : [ disable , allow , prefer , require , verify - ca , verify - full ]
version_added : ' 2.3 '
ssl_rootcert :
description :
- Specifies the name of a file containing SSL certificate authority ( CA ) certificate ( s ) . If the file exists , the server ' s certificate will be verified to be signed by one of these authorities.
required : false
default : null
version_added : ' 2.3 '
2014-09-26 01:01:01 +00:00
notes :
- Default authentication assumes that postgresql_privs is run by the
C ( postgres ) user on the remote host . ( Ansible ' s C(user) or C(sudo-user)).
- This module requires Python package I ( psycopg2 ) to be installed on the
remote host . In the default case of the remote host also being the
PostgreSQL server , PostgreSQL has to be installed there as well , obviously .
For Debian / Ubuntu - based systems , install packages I ( postgresql ) and
I ( python - psycopg2 ) .
- Parameters that accept comma separated lists ( I ( privs ) , I ( objs ) , I ( roles ) )
have singular alias names ( I ( priv ) , I ( obj ) , I ( role ) ) .
- To revoke only C ( GRANT OPTION ) for a specific object , set I ( state ) to
C ( present ) and I ( grant_option ) to C ( no ) ( see examples ) .
- Note that when revoking privileges from a role R , this role may still have
access via privileges granted to any role R is a member of including
C ( PUBLIC ) .
- Note that when revoking privileges from a role R , you do so as the user
specified via I ( login ) . If R has been granted the same privileges by
another user also , R can still access database objects via these privileges .
- When revoking privileges , C ( RESTRICT ) is assumed ( see PostgreSQL docs ) .
2016-11-22 15:18:45 +00:00
- The ssl_rootcert parameter requires at least Postgres version 8.4 and I ( psycopg2 ) version 2.4 .3 .
2014-09-26 01:01:01 +00:00
requirements : [ psycopg2 ]
2015-06-15 19:53:30 +00:00
author : " Bernhard Weitzhofer (@b6d) "
2014-09-26 01:01:01 +00:00
"""
EXAMPLES = """
# On database "library":
2014-09-29 23:06:42 +00:00
# GRANT SELECT, INSERT, UPDATE ON TABLE public.books, public.authors
2014-09-26 01:01:01 +00:00
# TO librarian, reader WITH GRANT OPTION
2016-10-12 19:34:28 +00:00
- postgresql_privs :
database : library
state : present
privs : SELECT , INSERT , UPDATE
type : table
objs : books , authors
schema : public
roles : librarian , reader
grant_option : yes
2014-09-26 01:01:01 +00:00
# Same as above leveraging default values:
2016-10-12 19:34:28 +00:00
- postgresql_privs :
db : library
privs : SELECT , INSERT , UPDATE
objs : books , authors
roles : librarian , reader
grant_option : yes
2014-09-26 01:01:01 +00:00
2014-09-29 23:06:42 +00:00
# REVOKE GRANT OPTION FOR INSERT ON TABLE books FROM reader
# Note that role "reader" will be *granted* INSERT privilege itself if this
2016-10-12 19:34:28 +00:00
# isn't already the case (since state: present).
- postgresql_privs :
db : library
state : present
priv : INSERT
obj : books
role : reader
grant_option : no
2014-09-26 01:01:01 +00:00
# REVOKE INSERT, UPDATE ON ALL TABLES IN SCHEMA public FROM reader
# "public" is the default schema. This also works for PostgreSQL 8.x.
2016-10-12 19:34:28 +00:00
- postgresql_privs :
db : library
state : absent
privs : INSERT , UPDATE
objs : ALL_IN_SCHEMA
role : reader
2014-09-26 01:01:01 +00:00
# GRANT ALL PRIVILEGES ON SCHEMA public, math TO librarian
2016-10-12 19:34:28 +00:00
- postgresql_privs :
db : library
privs : ALL
type : schema
objs : public , math
role : librarian
2014-09-26 01:01:01 +00:00
# GRANT ALL PRIVILEGES ON FUNCTION math.add(int, int) TO librarian, reader
# Note the separation of arguments with colons.
2016-10-12 19:34:28 +00:00
- postgresql_privs :
db : library
privs : ALL
type : function
obj : add ( int : int )
schema : math
roles : librarian , reader
2014-09-26 01:01:01 +00:00
# GRANT librarian, reader TO alice, bob WITH ADMIN OPTION
# Note that group role memberships apply cluster-wide and therefore are not
# restricted to database "library" here.
2016-10-12 19:34:28 +00:00
- postgresql_privs :
db : library
type : group
objs : librarian , reader
roles : alice , bob
admin_option : yes
2014-09-26 01:01:01 +00:00
# GRANT ALL PRIVILEGES ON DATABASE library TO librarian
2016-10-12 19:34:28 +00:00
# Note that here "db: postgres" specifies the database to connect to, not the
2014-09-26 01:01:01 +00:00
# database to grant privileges on (which is specified via the "objs" param)
2016-10-12 19:34:28 +00:00
- postgresql_privs :
db : postgres
privs : ALL
type : database
obj : library
role : librarian
2014-09-26 01:01:01 +00:00
# GRANT ALL PRIVILEGES ON DATABASE library TO librarian
2014-09-29 23:06:42 +00:00
# If objs is omitted for type "database", it defaults to the database
2014-09-26 01:01:01 +00:00
# to which the connection is established
2016-10-12 19:34:28 +00:00
- postgresql_privs :
db : library
privs : ALL
type : database
role : librarian
2014-09-26 01:01:01 +00:00
"""
try :
import psycopg2
import psycopg2 . extensions
except ImportError :
psycopg2 = None
2014-11-25 06:56:51 +00:00
VALID_PRIVS = frozenset ( ( ' SELECT ' , ' INSERT ' , ' UPDATE ' , ' DELETE ' , ' TRUNCATE ' ,
' REFERENCES ' , ' TRIGGER ' , ' CREATE ' , ' CONNECT ' ,
2014-12-03 22:43:20 +00:00
' TEMPORARY ' , ' TEMP ' , ' EXECUTE ' , ' USAGE ' , ' ALL ' , ' USAGE ' ) )
2014-09-26 01:01:01 +00:00
class Error ( Exception ) :
pass
# We don't have functools.partial in Python < 2.5
def partial ( f , * args , * * kwargs ) :
""" Partial function application """
def g ( * g_args , * * g_kwargs ) :
new_kwargs = kwargs . copy ( )
new_kwargs . update ( g_kwargs )
return f ( * ( args + g_args ) , * * g_kwargs )
g . f = f
g . args = args
g . kwargs = kwargs
return g
class Connection ( object ) :
""" Wrapper around a psycopg2 connection with some convenience methods """
def __init__ ( self , params ) :
self . database = params . database
# To use defaults values, keyword arguments must be absent, so
# check which values are empty and don't include in the **kw
# dictionary
params_map = {
" host " : " host " ,
" login " : " user " ,
" password " : " password " ,
" port " : " port " ,
" database " : " database " ,
2016-11-22 15:18:45 +00:00
" ssl_mode " : " sslmode " ,
" ssl_rootcert " : " sslrootcert "
2014-09-26 01:01:01 +00:00
}
2016-11-22 15:18:45 +00:00
2014-09-26 01:01:01 +00:00
kw = dict ( ( params_map [ k ] , getattr ( params , k ) ) for k in params_map
2016-11-22 15:18:45 +00:00
if getattr ( params , k ) != ' ' and getattr ( params , k ) is not None )
2014-09-29 23:06:42 +00:00
# If a unix_socket is specified, incorporate it here.
is_localhost = " host " not in kw or kw [ " host " ] == " " or kw [ " host " ] == " localhost "
if is_localhost and params . unix_socket != " " :
kw [ " host " ] = params . unix_socket
2016-11-22 15:18:45 +00:00
sslrootcert = params . ssl_rootcert
if psycopg2 . __version__ < ' 2.4.3 ' and sslrootcert is not None :
module . fail_json ( msg = ' psycopg2 must be at least 2.4.3 in order to user the ssl_rootcert parameter ' )
try :
self . connection = psycopg2 . connect ( * * kw )
self . cursor = self . connection . cursor ( )
except TypeError :
e = get_exception ( )
if ' sslrootcert ' in e . args [ 0 ] :
module . fail_json ( msg = ' Postgresql server must be at least version 8.4 to support sslrootcert ' )
module . fail_json ( msg = " unable to connect to database: %s " % e )
2014-09-26 01:01:01 +00:00
def commit ( self ) :
self . connection . commit ( )
def rollback ( self ) :
self . connection . rollback ( )
@property
def encoding ( self ) :
""" Connection encoding in Python-compatible form """
return psycopg2 . extensions . encodings [ self . connection . encoding ]
### Methods for querying database objects
# PostgreSQL < 9.0 doesn't support "ALL TABLES IN SCHEMA schema"-like
# phrases in GRANT or REVOKE statements, therefore alternative methods are
# provided here.
def schema_exists ( self , schema ) :
query = """ SELECT count(*)
FROM pg_catalog . pg_namespace WHERE nspname = % s """
self . cursor . execute ( query , ( schema , ) )
return self . cursor . fetchone ( ) [ 0 ] > 0
def get_all_tables_in_schema ( self , schema ) :
if not self . schema_exists ( schema ) :
raise Error ( ' Schema " %s " does not exist. ' % schema )
query = """ SELECT relname
FROM pg_catalog . pg_class c
JOIN pg_catalog . pg_namespace n ON n . oid = c . relnamespace
2015-06-27 17:41:01 +00:00
WHERE nspname = % s AND relkind in ( ' r ' , ' v ' ) """
2014-09-26 01:01:01 +00:00
self . cursor . execute ( query , ( schema , ) )
return [ t [ 0 ] for t in self . cursor . fetchall ( ) ]
def get_all_sequences_in_schema ( self , schema ) :
if not self . schema_exists ( schema ) :
raise Error ( ' Schema " %s " does not exist. ' % schema )
query = """ SELECT relname
FROM pg_catalog . pg_class c
JOIN pg_catalog . pg_namespace n ON n . oid = c . relnamespace
WHERE nspname = % s AND relkind = ' S ' """
self . cursor . execute ( query , ( schema , ) )
return [ t [ 0 ] for t in self . cursor . fetchall ( ) ]
### Methods for getting access control lists and group membership info
# To determine whether anything has changed after granting/revoking
# privileges, we compare the access control lists of the specified database
# objects before and afterwards. Python's list/string comparison should
# suffice for change detection, we should not actually have to parse ACLs.
# The same should apply to group membership information.
def get_table_acls ( self , schema , tables ) :
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 )
ORDER BY relname """
self . cursor . execute ( query , ( schema , tables ) )
return [ t [ 0 ] for t in self . cursor . fetchall ( ) ]
def get_sequence_acls ( self , schema , sequences ) :
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 = ' S ' AND relname = ANY ( % s )
ORDER BY relname """
self . cursor . execute ( query , ( schema , sequences ) )
return [ t [ 0 ] for t in self . cursor . fetchall ( ) ]
def get_function_acls ( self , schema , function_signatures ) :
funcnames = [ f . split ( ' ( ' , 1 ) [ 0 ] for f in function_signatures ]
query = """ SELECT proacl
FROM pg_catalog . pg_proc p
JOIN pg_catalog . pg_namespace n ON n . oid = p . pronamespace
WHERE nspname = % s AND proname = ANY ( % s )
ORDER BY proname , proargtypes """
self . cursor . execute ( query , ( schema , funcnames ) )
return [ t [ 0 ] for t in self . cursor . fetchall ( ) ]
def get_schema_acls ( self , schemas ) :
query = """ SELECT nspacl FROM pg_catalog.pg_namespace
WHERE nspname = ANY ( % s ) ORDER BY nspname """
self . cursor . execute ( query , ( schemas , ) )
return [ t [ 0 ] for t in self . cursor . fetchall ( ) ]
def get_language_acls ( self , languages ) :
query = """ SELECT lanacl FROM pg_catalog.pg_language
WHERE lanname = ANY ( % s ) ORDER BY lanname """
self . cursor . execute ( query , ( languages , ) )
return [ t [ 0 ] for t in self . cursor . fetchall ( ) ]
def get_tablespace_acls ( self , tablespaces ) :
query = """ SELECT spcacl FROM pg_catalog.pg_tablespace
WHERE spcname = ANY ( % s ) ORDER BY spcname """
self . cursor . execute ( query , ( tablespaces , ) )
return [ t [ 0 ] for t in self . cursor . fetchall ( ) ]
def get_database_acls ( self , databases ) :
query = """ SELECT datacl FROM pg_catalog.pg_database
WHERE datname = ANY ( % s ) ORDER BY datname """
self . cursor . execute ( query , ( databases , ) )
return [ t [ 0 ] for t in self . cursor . fetchall ( ) ]
def get_group_memberships ( self , groups ) :
query = """ SELECT roleid, grantor, member, admin_option
2014-09-29 23:06:42 +00:00
FROM pg_catalog . pg_auth_members am
2014-09-26 01:01:01 +00:00
JOIN pg_catalog . pg_roles r ON r . oid = am . roleid
2014-09-29 23:06:42 +00:00
WHERE r . rolname = ANY ( % s )
2014-09-26 01:01:01 +00:00
ORDER BY roleid , grantor , member """
self . cursor . execute ( query , ( groups , ) )
return self . cursor . fetchall ( )
### Manipulating privileges
def manipulate_privs ( self , obj_type , privs , objs , roles ,
state , grant_option , schema_qualifier = None ) :
""" Manipulate database object privileges.
: param obj_type : Type of database object to grant / revoke
privileges for .
2014-09-29 23:06:42 +00:00
: param privs : Either a list of privileges to grant / revoke
2014-09-26 01:01:01 +00:00
or None if type is " group " .
: param objs : List of database objects to grant / revoke
privileges for .
: param roles : Either a list of role names or " PUBLIC "
for the implicitly defined " PUBLIC " group
: param state : " present " to grant privileges , " absent " to revoke .
2014-09-29 23:06:42 +00:00
: param grant_option : Only for state " present " : If True , set
2014-09-26 01:01:01 +00:00
grant / admin option . If False , revoke it .
If None , don ' t change grant option.
: param schema_qualifier : Some object types ( " TABLE " , " SEQUENCE " ,
" FUNCTION " ) must be qualified by schema .
Ignored for other Types .
"""
# get_status: function to get current status
if obj_type == ' table ' :
get_status = partial ( self . get_table_acls , schema_qualifier )
elif obj_type == ' sequence ' :
get_status = partial ( self . get_sequence_acls , schema_qualifier )
elif obj_type == ' function ' :
get_status = partial ( self . get_function_acls , schema_qualifier )
elif obj_type == ' schema ' :
get_status = self . get_schema_acls
elif obj_type == ' language ' :
get_status = self . get_language_acls
elif obj_type == ' tablespace ' :
get_status = self . get_tablespace_acls
elif obj_type == ' database ' :
get_status = self . get_database_acls
elif obj_type == ' group ' :
get_status = self . get_group_memberships
else :
raise Error ( ' Unsupported database object type " %s " . ' % obj_type )
# Return False (nothing has changed) if there are no objs to work on.
if not objs :
return False
# obj_ids: quoted db object identifiers (sometimes schema-qualified)
if obj_type == ' function ' :
obj_ids = [ ]
for obj in objs :
try :
f , args = obj . split ( ' ( ' , 1 )
except :
raise Error ( ' Illegal function signature: " %s " . ' % obj )
obj_ids . append ( ' " %s " . " %s " ( %s ' % ( schema_qualifier , f , args ) )
elif obj_type in [ ' table ' , ' sequence ' ] :
obj_ids = [ ' " %s " . " %s " ' % ( schema_qualifier , o ) for o in objs ]
else :
obj_ids = [ ' " %s " ' % o for o in objs ]
2014-11-25 06:56:51 +00:00
# set_what: SQL-fragment specifying what to set for the target roles:
# Either group membership or privileges on objects of a certain type
2014-09-26 01:01:01 +00:00
if obj_type == ' group ' :
2014-11-25 09:42:33 +00:00
set_what = ' , ' . join ( pg_quote_identifier ( i , ' role ' ) for i in obj_ids )
2014-09-26 01:01:01 +00:00
else :
2015-01-26 13:04:53 +00:00
# function types are already quoted above
if obj_type != ' function ' :
obj_ids = [ pg_quote_identifier ( i , ' table ' ) for i in obj_ids ]
2014-11-25 06:56:51 +00:00
# Note: obj_type has been checked against a set of string literals
# and privs was escaped when it was parsed
set_what = ' %s ON %s %s ' % ( ' , ' . join ( privs ) , obj_type ,
2015-01-26 13:04:53 +00:00
' , ' . join ( obj_ids ) )
2014-09-26 01:01:01 +00:00
# for_whom: SQL-fragment specifying for whom to set the above
if roles == ' PUBLIC ' :
for_whom = ' PUBLIC '
else :
2014-11-25 09:42:33 +00:00
for_whom = ' , ' . join ( pg_quote_identifier ( r , ' role ' ) for r in roles )
2014-09-26 01:01:01 +00:00
status_before = get_status ( objs )
if state == ' present ' :
if grant_option :
if obj_type == ' group ' :
query = ' GRANT %s TO %s WITH ADMIN OPTION '
else :
query = ' GRANT %s TO %s WITH GRANT OPTION '
else :
2014-09-29 23:06:42 +00:00
query = ' GRANT %s TO %s '
2014-09-26 01:01:01 +00:00
self . cursor . execute ( query % ( set_what , for_whom ) )
# Only revoke GRANT/ADMIN OPTION if grant_option actually is False.
if grant_option == False :
if obj_type == ' group ' :
query = ' REVOKE ADMIN OPTION FOR %s FROM %s '
else :
query = ' REVOKE GRANT OPTION FOR %s FROM %s '
self . cursor . execute ( query % ( set_what , for_whom ) )
else :
2014-09-29 23:06:42 +00:00
query = ' REVOKE %s FROM %s '
2014-09-26 01:01:01 +00:00
self . cursor . execute ( query % ( set_what , for_whom ) )
status_after = get_status ( objs )
return status_before != status_after
def main ( ) :
module = AnsibleModule (
argument_spec = dict (
database = dict ( required = True , aliases = [ ' db ' ] ) ,
state = dict ( default = ' present ' , choices = [ ' present ' , ' absent ' ] ) ,
privs = dict ( required = False , aliases = [ ' priv ' ] ) ,
type = dict ( default = ' table ' ,
choices = [ ' table ' ,
' sequence ' ,
' function ' ,
' database ' ,
' schema ' ,
' language ' ,
' tablespace ' ,
' group ' ] ) ,
objs = dict ( required = False , aliases = [ ' obj ' ] ) ,
schema = dict ( required = False ) ,
roles = dict ( required = True , aliases = [ ' role ' ] ) ,
2014-09-29 23:06:42 +00:00
grant_option = dict ( required = False , type = ' bool ' ,
2014-09-26 01:01:01 +00:00
aliases = [ ' admin_option ' ] ) ,
host = dict ( default = ' ' , aliases = [ ' login_host ' ] ) ,
port = dict ( type = ' int ' , default = 5432 ) ,
2014-09-29 23:06:42 +00:00
unix_socket = dict ( default = ' ' , aliases = [ ' login_unix_socket ' ] ) ,
2014-09-26 01:01:01 +00:00
login = dict ( default = ' postgres ' , aliases = [ ' login_user ' ] ) ,
2016-11-22 15:18:45 +00:00
password = dict ( default = ' ' , aliases = [ ' login_password ' ] , no_log = True ) ,
ssl_mode = dict ( default = " disable " , choices = [ ' disable ' , ' allow ' , ' prefer ' , ' require ' , ' verify-ca ' , ' verify-full ' ] ) ,
ssl_rootcert = dict ( default = None )
2014-09-26 01:01:01 +00:00
) ,
supports_check_mode = True
)
# 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 ' ] :
p . schema = p . schema or ' public '
elif p . schema :
module . fail_json ( msg = ' Argument " schema " is not allowed '
' for type " %s " . ' % p . type )
# param "objs": default, required depends on param "type"
if p . type == ' database ' :
p . objs = p . objs or p . database
elif not p . objs :
module . fail_json ( msg = ' Argument " objs " is required '
' for type " %s " . ' % p . type )
# param "privs": allowed, required depends on param "type"
if p . type == ' group ' :
if p . privs :
module . fail_json ( msg = ' Argument " privs " is not allowed '
' for type " group " . ' )
elif not p . privs :
module . fail_json ( msg = ' Argument " privs " is required '
' for type " %s " . ' % p . type )
# Connect to Database
if not psycopg2 :
module . fail_json ( msg = ' Python module " psycopg2 " must be installed. ' )
try :
conn = Connection ( p )
2016-05-18 14:07:21 +00:00
except psycopg2 . Error :
e = get_exception ( )
2014-09-26 01:01:01 +00:00
module . fail_json ( msg = ' Could not connect to database: %s ' % e )
try :
# privs
if p . privs :
2014-11-25 08:44:18 +00:00
privs = frozenset ( pr . upper ( ) for pr in p . privs . split ( ' , ' ) )
2014-11-25 06:56:51 +00:00
if not privs . issubset ( VALID_PRIVS ) :
module . fail_json ( msg = ' Invalid privileges specified: %s ' % privs . difference ( VALID_PRIVS ) )
2014-09-26 01:01:01 +00:00
else :
privs = None
# objs:
if p . type == ' table ' and p . objs == ' ALL_IN_SCHEMA ' :
objs = conn . get_all_tables_in_schema ( p . schema )
elif p . type == ' sequence ' and p . objs == ' ALL_IN_SCHEMA ' :
objs = conn . get_all_sequences_in_schema ( p . schema )
else :
objs = p . objs . split ( ' , ' )
# function signatures are encoded using ':' to separate args
if p . type == ' function ' :
objs = [ obj . replace ( ' : ' , ' , ' ) for obj in objs ]
# roles
if p . roles == ' PUBLIC ' :
roles = ' PUBLIC '
else :
roles = p . roles . split ( ' , ' )
changed = conn . manipulate_privs (
obj_type = p . type ,
privs = privs ,
objs = objs ,
roles = roles ,
state = p . state ,
grant_option = p . grant_option ,
schema_qualifier = p . schema
)
2016-05-18 14:07:21 +00:00
except Error :
e = get_exception ( )
2014-09-26 01:01:01 +00:00
conn . rollback ( )
module . fail_json ( msg = e . message )
2016-05-18 14:07:21 +00:00
except psycopg2 . Error :
e = get_exception ( )
2014-09-26 01:01:01 +00:00
conn . rollback ( )
# psycopg2 errors come in connection encoding, reencode
msg = e . message . decode ( conn . encoding ) . encode ( sys . getdefaultencoding ( ) ,
' replace ' )
module . fail_json ( msg = msg )
if module . check_mode :
conn . rollback ( )
else :
conn . commit ( )
module . exit_json ( changed = changed )
# import module snippets
from ansible . module_utils . basic import *
2014-11-25 06:56:51 +00:00
from ansible . module_utils . database import *
if __name__ == ' __main__ ' :
main ( )