add role_attr_flags parameter to postgresql_user

Pass role_attr_flags a list of comma separated role
attributes when creating or updating a user.
reviewable/pr18780/r1
Jeremiah Heller 12 years ago
parent c482104cda
commit e99c12460b

@ -77,6 +77,13 @@ options:
- "PostgreSQL privileges string in the format: C(table:priv1,priv2)" - "PostgreSQL privileges string in the format: C(table:priv1,priv2)"
required: false required: false
default: null default: null
role_attr_flags:
description:
- "PostgreSQL role attributes string in the format: CREATEDB,CREATEROLE,SUPERUSER"
required: false
default: null
choices: [ "[NO]SUPERUSER","[NO]CREATEROLE", "[NO]CREATEUSER", "[NO]CREATEDB",
"[NO]INHERIT", "[NO]LOGIN", "[NO]REPLICATION" ]
state: state:
description: description:
- The database state - The database state
@ -86,6 +93,8 @@ options:
examples: examples:
- code: postgresql_user db=acme user=django password=ceec4eif7ya priv=CONNECT/products:ALL - code: postgresql_user db=acme user=django password=ceec4eif7ya priv=CONNECT/products:ALL
description: Create django user and grant access to database and products table description: Create django user and grant access to database and products table
- code: postgresql_user user=rails password=secret role_attr_flags=CREATEDB,NOSUPERUSER
- description: Create rails user, grant privilege to create other databases and demote rails from super user status
- code: postgresql_user db=acme user=test priv=ALL/products:ALL state=absent fail_on_user=no - code: postgresql_user db=acme user=test priv=ALL/products:ALL state=absent fail_on_user=no
description: Remove test user privileges from acme description: Remove test user privileges from acme
- code: postgresql_user db=test user=test priv=ALL state=absent - code: postgresql_user db=test user=test priv=ALL state=absent
@ -125,29 +134,45 @@ def user_exists(cursor, user):
return cursor.rowcount > 0 return cursor.rowcount > 0
def user_add(cursor, user, password): def user_add(cursor, user, password, role_attr_flags):
"""Create a new user with write access to the database""" """Create a new user with write access to the database"""
query = "CREATE USER %(user)s with PASSWORD '%(password)s'" query = "CREATE USER %(user)s with PASSWORD '%(password)s' %(role_attr_flags)s"
cursor.execute(query % {"user": user, "password": password}) cursor.execute(query % {"user": user, "password": password, "role_attr_flags": role_attr_flags})
return True return True
def user_chpass(cursor, user, password): def user_alter(cursor, user, password, role_attr_flags):
"""Change user password""" """Change user password"""
changed = False changed = False
# Handle passwords. # Handle passwords.
if password is not None: if password is not None or role_attr_flags is not None:
select = "SELECT rolpassword FROM pg_authid where rolname=%(user)s" # Define columns for select.
cursor.execute(select, {"user": user}) columns = 'rolpassword,rolsuper,rolinherit,rolcreaterole,rolcreatedb,rolcanlogin,rolreplication'
current_pass_hash = cursor.fetchone()[0] # Select password and all flag-like columns in order to verify changes.
# Not sure how to hash the new password, so we just initiate the # rolsuper | rolinherit | rolcreaterole | rolcreatedb | rolcatupdate |
# change and check if the hash changed # rolcanlogin | rolreplication | rolconnlimit | rolpassword | rolvaliduntil
alter = "ALTER USER %(user)s WITH PASSWORD '%(password)s'" # Not sure how to interpolate properly in python yet...
cursor.execute(alter % {"user": user, "password": password}) select = "SELECT " + columns + " FROM pg_authid where rolname=%(user)s"
cursor.execute(select, {"user": user}) cursor.execute(select, {"columns": columns, "user": user})
new_pass_hash = cursor.fetchone()[0] # Grab current role attributes.
if current_pass_hash != new_pass_hash: current_role_attrs = cursor.fetchone()
changed = True
if password is not None:
# Update the role attributes, including password.
alter = "ALTER USER %(user)s WITH PASSWORD '%(password)s' %(role_attr_flags)s"
cursor.execute(alter % {"user": user, "password": password, "role_attr_flags": role_attr_flags})
else:
# Update the role attributes, excluding password.
alter = "ALTER USER %(user)s WITH %(role_attr_flags)s"
cursor.execute(alter % {"user": user, "role_attr_flags": role_attr_flags})
# Grab new role attributes.
cursor.execute(select, {"columns": columns, "user": user})
new_role_attrs = cursor.fetchone()
# Detect any differences between current_ and new_role_attrs.
for i in range(len(current_role_attrs)):
if current_role_attrs[i] != new_role_attrs[i]:
changed = True
return changed return changed
@ -267,6 +292,23 @@ def grant_privileges(cursor, user, privs):
return changed return changed
def parse_role_attrs(role_attr_flags):
"""
Parse role attributes string for user creation.
Format:
attributes[,attributes,...]
Where:
attributes := CREATEDB,CREATEROLE,NOSUPERUSER,...
"""
if ',' not in role_attr_flags:
return role_attr_flags
flag_set = role_attr_flags.split(",")
o_flags = " ".join(flag_set)
return o_flags
def parse_privs(privs, db): def parse_privs(privs, db):
""" """
Parse privilege string to determine permissions for database db. Parse privilege string to determine permissions for database db.
@ -316,7 +358,8 @@ def main():
priv=dict(default=None), priv=dict(default=None),
db=dict(default=''), db=dict(default=''),
port=dict(default='5432'), port=dict(default='5432'),
fail_on_user=dict(default='yes') fail_on_user=dict(default='yes'),
role_attr_flags=dict(default='')
) )
) )
user = module.params["user"] user = module.params["user"]
@ -328,6 +371,7 @@ def main():
module.fail_json(msg="privileges require a database to be specified") module.fail_json(msg="privileges require a database to be specified")
privs = parse_privs(module.params["priv"], db) privs = parse_privs(module.params["priv"], db)
port = module.params["port"] port = module.params["port"]
role_attr_flags = parse_role_attrs(module.params["role_attr_flags"])
if not postgresqldb_found: if not postgresqldb_found:
module.fail_json(msg="the python psycopg2 module is required") module.fail_json(msg="the python psycopg2 module is required")
@ -355,12 +399,12 @@ def main():
user_removed = False user_removed = False
if state == "present": if state == "present":
if user_exists(cursor, user): if user_exists(cursor, user):
changed = user_chpass(cursor, user, password) changed = user_alter(cursor, user, password, role_attr_flags)
else: else:
if password is None: if password is None:
msg = "password parameter required when adding a user" msg = "password parameter required when adding a user"
module.fail_json(msg=msg) module.fail_json(msg=msg)
changed = user_add(cursor, user, password) changed = user_add(cursor, user, password, role_attr_flags)
changed = grant_privileges(cursor, user, privs) or changed changed = grant_privileges(cursor, user, privs) or changed
else: else:
if user_exists(cursor, user): if user_exists(cursor, user):

Loading…
Cancel
Save