Merge pull request #43 from drob/postgresql-socket

Adds login_unix_socket options to postgresql modules.
TODO: factor this out into common code as we did for ec2 and others.
This commit is contained in:
Brian Coca 2014-12-01 12:55:22 -05:00
commit adec837306
3 changed files with 54 additions and 17 deletions

View file

@ -44,6 +44,11 @@ options:
- Host running the database - Host running the database
required: false required: false
default: localhost default: localhost
login_unix_socket:
description
- Path to a Unix domain socket for local connections
required: false
default: null
owner: owner:
description: description:
- Name of the role to set as owner of the database - Name of the role to set as owner of the database
@ -178,7 +183,7 @@ def db_create(cursor, db, owner, template, encoding, lc_collate, lc_ctype):
return True return True
else: else:
db_info = get_db_info(cursor, db) db_info = get_db_info(cursor, db)
if (encoding and if (encoding and
get_encoding_id(cursor, encoding) != db_info['encoding_id']): get_encoding_id(cursor, encoding) != db_info['encoding_id']):
raise NotSupportedError( raise NotSupportedError(
'Changing database encoding is not supported. ' 'Changing database encoding is not supported. '
@ -204,7 +209,7 @@ def db_matches(cursor, db, owner, template, encoding, lc_collate, lc_ctype):
return False return False
else: else:
db_info = get_db_info(cursor, db) db_info = get_db_info(cursor, db)
if (encoding and if (encoding and
get_encoding_id(cursor, encoding) != db_info['encoding_id']): get_encoding_id(cursor, encoding) != db_info['encoding_id']):
return False return False
elif lc_collate and lc_collate != db_info['lc_collate']: elif lc_collate and lc_collate != db_info['lc_collate']:
@ -226,6 +231,7 @@ def main():
login_user=dict(default="postgres"), login_user=dict(default="postgres"),
login_password=dict(default=""), login_password=dict(default=""),
login_host=dict(default=""), login_host=dict(default=""),
login_unix_socket=dict(default=""),
port=dict(default="5432"), port=dict(default="5432"),
db=dict(required=True, aliases=['name']), db=dict(required=True, aliases=['name']),
owner=dict(default=""), owner=dict(default=""),
@ -251,7 +257,7 @@ def main():
state = module.params["state"] state = module.params["state"]
changed = False changed = False
# To use defaults values, keyword arguments must be absent, so # To use defaults values, keyword arguments must be absent, so
# check which values are empty and don't include in the **kw # check which values are empty and don't include in the **kw
# dictionary # dictionary
params_map = { params_map = {
@ -260,8 +266,14 @@ def main():
"login_password":"password", "login_password":"password",
"port":"port" "port":"port"
} }
kw = dict( (params_map[k], v) for (k, v) in module.params.iteritems() kw = dict( (params_map[k], v) for (k, v) in module.params.iteritems()
if k in params_map and v != '' ) if k in params_map and v != '' )
# If a login_unix_socket is specified, incorporate it here.
is_localhost = "host" not in kw or kw["host"] == "" or kw["host"] == "localhost"
if is_localhost and module.params["login_unix_socket"] != "":
kw["host"] = module.params["login_unix_socket"]
try: try:
db_connection = psycopg2.connect(database="template1", **kw) db_connection = psycopg2.connect(database="template1", **kw)
# Enable autocommit so we can create databases # Enable autocommit so we can create databases

View file

@ -29,7 +29,7 @@ description:
options: options:
database: database:
description: description:
- Name of database to connect to. - Name of database to connect to.
- 'Alias: I(db)' - 'Alias: I(db)'
required: yes required: yes
state: state:
@ -53,7 +53,7 @@ options:
schema, language, tablespace, group] schema, language, tablespace, group]
objs: objs:
description: description:
- Comma separated list of database objects to set privileges on. - Comma separated list of database objects to set privileges on.
- If I(type) is C(table) or C(sequence), the special value - If I(type) is C(table) or C(sequence), the special value
C(ALL_IN_SCHEMA) can be provided instead to specify all database 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 objects of type I(type) in the schema specified via I(schema). (This
@ -99,6 +99,12 @@ options:
- Database port to connect to. - Database port to connect to.
required: no required: no
default: 5432 default: 5432
unix_socket:
description
- Path to a Unix domain socket for local connections.
- 'Alias: I(login_unix_socket)'
required: false
default: null
login: login:
description: description:
- The username to authenticate with. - The username to authenticate with.
@ -135,7 +141,7 @@ author: Bernhard Weitzhofer
EXAMPLES = """ EXAMPLES = """
# On database "library": # On database "library":
# GRANT SELECT, INSERT, UPDATE ON TABLE public.books, public.authors # GRANT SELECT, INSERT, UPDATE ON TABLE public.books, public.authors
# TO librarian, reader WITH GRANT OPTION # TO librarian, reader WITH GRANT OPTION
- postgresql_privs: > - postgresql_privs: >
database=library database=library
@ -155,8 +161,8 @@ EXAMPLES = """
roles=librarian,reader roles=librarian,reader
grant_option=yes grant_option=yes
# REVOKE GRANT OPTION FOR INSERT ON TABLE books FROM reader # REVOKE GRANT OPTION FOR INSERT ON TABLE books FROM reader
# Note that role "reader" will be *granted* INSERT privilege itself if this # Note that role "reader" will be *granted* INSERT privilege itself if this
# isn't already the case (since state=present). # isn't already the case (since state=present).
- postgresql_privs: > - postgresql_privs: >
db=library db=library
@ -214,7 +220,7 @@ EXAMPLES = """
role=librarian role=librarian
# GRANT ALL PRIVILEGES ON DATABASE library TO librarian # GRANT ALL PRIVILEGES ON DATABASE library TO librarian
# If objs is omitted for type "database", it defaults to the database # If objs is omitted for type "database", it defaults to the database
# to which the connection is established # to which the connection is established
- postgresql_privs: > - postgresql_privs: >
db=library db=library
@ -267,6 +273,12 @@ class Connection(object):
} }
kw = dict( (params_map[k], getattr(params, k)) for k in params_map kw = dict( (params_map[k], getattr(params, k)) for k in params_map
if getattr(params, k) != '' ) if getattr(params, k) != '' )
# 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
self.connection = psycopg2.connect(**kw) self.connection = psycopg2.connect(**kw)
self.cursor = self.connection.cursor() self.cursor = self.connection.cursor()
@ -389,9 +401,9 @@ class Connection(object):
def get_group_memberships(self, groups): def get_group_memberships(self, groups):
query = """SELECT roleid, grantor, member, admin_option query = """SELECT roleid, grantor, member, admin_option
FROM pg_catalog.pg_auth_members am FROM pg_catalog.pg_auth_members am
JOIN pg_catalog.pg_roles r ON r.oid = am.roleid JOIN pg_catalog.pg_roles r ON r.oid = am.roleid
WHERE r.rolname = ANY(%s) WHERE r.rolname = ANY(%s)
ORDER BY roleid, grantor, member""" ORDER BY roleid, grantor, member"""
self.cursor.execute(query, (groups,)) self.cursor.execute(query, (groups,))
return self.cursor.fetchall() return self.cursor.fetchall()
@ -405,14 +417,14 @@ class Connection(object):
:param obj_type: Type of database object to grant/revoke :param obj_type: Type of database object to grant/revoke
privileges for. privileges for.
:param privs: Either a list of privileges to grant/revoke :param privs: Either a list of privileges to grant/revoke
or None if type is "group". or None if type is "group".
:param objs: List of database objects to grant/revoke :param objs: List of database objects to grant/revoke
privileges for. privileges for.
:param roles: Either a list of role names or "PUBLIC" :param roles: Either a list of role names or "PUBLIC"
for the implicitly defined "PUBLIC" group for the implicitly defined "PUBLIC" group
:param state: "present" to grant privileges, "absent" to revoke. :param state: "present" to grant privileges, "absent" to revoke.
:param grant_option: Only for state "present": If True, set :param grant_option: Only for state "present": If True, set
grant/admin option. If False, revoke it. grant/admin option. If False, revoke it.
If None, don't change grant option. If None, don't change grant option.
:param schema_qualifier: Some object types ("TABLE", "SEQUENCE", :param schema_qualifier: Some object types ("TABLE", "SEQUENCE",
@ -481,7 +493,7 @@ class Connection(object):
else: else:
query = 'GRANT %s TO %s WITH GRANT OPTION' query = 'GRANT %s TO %s WITH GRANT OPTION'
else: else:
query = 'GRANT %s TO %s' query = 'GRANT %s TO %s'
self.cursor.execute(query % (set_what, for_whom)) self.cursor.execute(query % (set_what, for_whom))
# Only revoke GRANT/ADMIN OPTION if grant_option actually is False. # Only revoke GRANT/ADMIN OPTION if grant_option actually is False.
@ -492,7 +504,7 @@ class Connection(object):
query = 'REVOKE GRANT OPTION FOR %s FROM %s' query = 'REVOKE GRANT OPTION FOR %s FROM %s'
self.cursor.execute(query % (set_what, for_whom)) self.cursor.execute(query % (set_what, for_whom))
else: else:
query = 'REVOKE %s FROM %s' query = 'REVOKE %s FROM %s'
self.cursor.execute(query % (set_what, for_whom)) self.cursor.execute(query % (set_what, for_whom))
status_after = get_status(objs) status_after = get_status(objs)
return status_before != status_after return status_before != status_after
@ -516,10 +528,11 @@ def main():
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']),
grant_option=dict(required=False, type='bool', grant_option=dict(required=False, type='bool',
aliases=['admin_option']), aliases=['admin_option']),
host=dict(default='', aliases=['login_host']), host=dict(default='', aliases=['login_host']),
port=dict(type='int', default=5432), port=dict(type='int', default=5432),
unix_socket=dict(default='', aliases=['login_unix_socket']),
login=dict(default='postgres', aliases=['login_user']), login=dict(default='postgres', aliases=['login_user']),
password=dict(default='', aliases=['login_password']) password=dict(default='', aliases=['login_password'])
), ),

View file

@ -78,6 +78,11 @@ options:
- Host running PostgreSQL. - Host running PostgreSQL.
required: false required: false
default: localhost default: localhost
login_unix_socket:
description
- Path to a Unix domain socket for local connections
required: false
default: null
priv: priv:
description: description:
- "PostgreSQL privileges string in the format: C(table:priv1,priv2)" - "PostgreSQL privileges string in the format: C(table:priv1,priv2)"
@ -456,6 +461,7 @@ def main():
login_user=dict(default="postgres"), login_user=dict(default="postgres"),
login_password=dict(default=""), login_password=dict(default=""),
login_host=dict(default=""), login_host=dict(default=""),
login_unix_socket=dict(default=""),
user=dict(required=True, aliases=['name']), user=dict(required=True, aliases=['name']),
password=dict(default=None), password=dict(default=None),
state=dict(default="present", choices=["absent", "present"]), state=dict(default="present", choices=["absent", "present"]),
@ -504,6 +510,12 @@ def main():
} }
kw = dict( (params_map[k], v) for (k, v) in module.params.iteritems() kw = dict( (params_map[k], v) for (k, v) in module.params.iteritems()
if k in params_map and v != "" ) if k in params_map and v != "" )
# If a login_unix_socket is specified, incorporate it here.
is_localhost = "host" not in kw or kw["host"] == "" or kw["host"] == "localhost"
if is_localhost and module.params["login_unix_socket"] != "":
kw["host"] = module.params["login_unix_socket"]
try: try:
db_connection = psycopg2.connect(**kw) db_connection = psycopg2.connect(**kw)
cursor = db_connection.cursor() cursor = db_connection.cursor()