mirror of
https://github.com/ansible-collections/community.general.git
synced 2024-09-14 20:13:21 +02:00
postgresql_user: fix bugs related to 'expires' option (#23862)
* Factorize tests related to no_password_change using an include task * Refactor: deduplicate tasks * postgresql_user: test 'expires' parameter * Change 'valid until' even it's the only updated field * value is changed when another value is provided * value isn't returned when unset * Remove unused variable * psycopg2.extras.DictRow is able to handle comparison * postgresql_user: simplify helper method * postgresql_user: define variable just before using it * Fix comparison between user input and applied configuration * new test: adding an invalid attribute * Refactor, add cleaning task * Check that using same attribute a 2nd time does nothing * Always try to remove created user * postgresql_user: fix pep8
This commit is contained in:
parent
301cbc1f5b
commit
460d932aa8
7 changed files with 304 additions and 368 deletions
|
@ -207,11 +207,10 @@ EXAMPLES = '''
|
||||||
password: NULL
|
password: NULL
|
||||||
'''
|
'''
|
||||||
|
|
||||||
from hashlib import md5
|
|
||||||
import itertools
|
import itertools
|
||||||
import re
|
import re
|
||||||
|
|
||||||
from distutils.version import StrictVersion
|
from distutils.version import StrictVersion
|
||||||
|
from hashlib import md5
|
||||||
|
|
||||||
try:
|
try:
|
||||||
import psycopg2
|
import psycopg2
|
||||||
|
@ -220,15 +219,15 @@ except ImportError:
|
||||||
postgresqldb_found = False
|
postgresqldb_found = False
|
||||||
else:
|
else:
|
||||||
postgresqldb_found = True
|
postgresqldb_found = True
|
||||||
|
|
||||||
from ansible.module_utils._text import to_bytes
|
from ansible.module_utils._text import to_bytes
|
||||||
from ansible.module_utils.six import iteritems
|
from ansible.module_utils.six import iteritems
|
||||||
|
|
||||||
_flags = ('SUPERUSER', 'CREATEROLE', 'CREATEUSER', 'CREATEDB', 'INHERIT', 'LOGIN', 'REPLICATION')
|
FLAGS = ('SUPERUSER', 'CREATEROLE', 'CREATEUSER', 'CREATEDB', 'INHERIT', 'LOGIN', 'REPLICATION')
|
||||||
_flags_by_version = {'BYPASSRLS': '9.5.0'}
|
FLAGS_BY_VERSION = {'BYPASSRLS': '9.5.0'}
|
||||||
|
|
||||||
VALID_PRIVS = dict(table=frozenset(('SELECT', 'INSERT', 'UPDATE', 'DELETE', 'TRUNCATE', 'REFERENCES', 'TRIGGER', 'ALL')),
|
VALID_PRIVS = dict(table=frozenset(('SELECT', 'INSERT', 'UPDATE', 'DELETE', 'TRUNCATE', 'REFERENCES', 'TRIGGER', 'ALL')),
|
||||||
database=frozenset(('CREATE', 'CONNECT', 'TEMPORARY', 'TEMP', 'ALL')),
|
database=frozenset(('CREATE', 'CONNECT', 'TEMPORARY', 'TEMP', 'ALL')),)
|
||||||
)
|
|
||||||
|
|
||||||
# map to cope with idiosyncracies of SUPERUSER and LOGIN
|
# map to cope with idiosyncracies of SUPERUSER and LOGIN
|
||||||
PRIV_TO_AUTHID_COLUMN = dict(SUPERUSER='rolsuper', CREATEROLE='rolcreaterole',
|
PRIV_TO_AUTHID_COLUMN = dict(SUPERUSER='rolsuper', CREATEROLE='rolcreaterole',
|
||||||
|
@ -236,9 +235,11 @@ PRIV_TO_AUTHID_COLUMN = dict(SUPERUSER='rolsuper', CREATEROLE='rolcreaterole',
|
||||||
INHERIT='rolinherit', LOGIN='rolcanlogin',
|
INHERIT='rolinherit', LOGIN='rolcanlogin',
|
||||||
REPLICATION='rolreplication', BYPASSRLS='rolbypassrls')
|
REPLICATION='rolreplication', BYPASSRLS='rolbypassrls')
|
||||||
|
|
||||||
|
|
||||||
class InvalidFlagsError(Exception):
|
class InvalidFlagsError(Exception):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
|
||||||
class InvalidPrivsError(Exception):
|
class InvalidPrivsError(Exception):
|
||||||
pass
|
pass
|
||||||
|
|
||||||
|
@ -260,9 +261,9 @@ def user_add(cursor, user, password, role_attr_flags, encrypted, expires):
|
||||||
"""Create a new database user (role)."""
|
"""Create a new database user (role)."""
|
||||||
# Note: role_attr_flags escaped by parse_role_attrs and encrypted is a literal
|
# Note: role_attr_flags escaped by parse_role_attrs and encrypted is a literal
|
||||||
query_password_data = dict(password=password, expires=expires)
|
query_password_data = dict(password=password, expires=expires)
|
||||||
query = ['CREATE USER %(user)s' % { "user": pg_quote_identifier(user, 'role')}]
|
query = ['CREATE USER %(user)s' % {"user": pg_quote_identifier(user, 'role')}]
|
||||||
if password is not None:
|
if password is not None:
|
||||||
query.append("WITH %(crypt)s" % { "crypt": encrypted })
|
query.append("WITH %(crypt)s" % {"crypt": encrypted})
|
||||||
query.append("PASSWORD %(password)s")
|
query.append("PASSWORD %(password)s")
|
||||||
if expires is not None:
|
if expires is not None:
|
||||||
query.append("VALID UNTIL %(expires)s")
|
query.append("VALID UNTIL %(expires)s")
|
||||||
|
@ -271,6 +272,7 @@ def user_add(cursor, user, password, role_attr_flags, encrypted, expires):
|
||||||
cursor.execute(query, query_password_data)
|
cursor.execute(query, query_password_data)
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
def user_alter(cursor, module, user, password, role_attr_flags, encrypted, expires, no_password_changes):
|
def user_alter(cursor, module, user, password, role_attr_flags, encrypted, expires, no_password_changes):
|
||||||
"""Change user password and/or attributes. Return True if changed, False otherwise."""
|
"""Change user password and/or attributes. Return True if changed, False otherwise."""
|
||||||
changed = False
|
changed = False
|
||||||
|
@ -285,9 +287,8 @@ def user_alter(cursor, module, user, password, role_attr_flags, encrypted, expir
|
||||||
return False
|
return False
|
||||||
|
|
||||||
# Handle passwords.
|
# Handle passwords.
|
||||||
if not no_password_changes and (password is not None or role_attr_flags != ''):
|
if not no_password_changes and (password is not None or role_attr_flags != '' or expires is not None):
|
||||||
# Select password and all flag-like columns in order to verify changes.
|
# Select password and all flag-like columns in order to verify changes.
|
||||||
query_password_data = dict(password=password, expires=expires)
|
|
||||||
select = "SELECT * FROM pg_authid where rolname=%(user)s"
|
select = "SELECT * FROM pg_authid where rolname=%(user)s"
|
||||||
cursor.execute(select, {"user": user})
|
cursor.execute(select, {"user": user})
|
||||||
# Grab current role attributes.
|
# Grab current role attributes.
|
||||||
|
@ -300,7 +301,7 @@ def user_alter(cursor, module, user, password, role_attr_flags, encrypted, expir
|
||||||
# 3: The size of the 'md5' prefix
|
# 3: The size of the 'md5' prefix
|
||||||
# When the provided password looks like a MD5-hash, value of
|
# When the provided password looks like a MD5-hash, value of
|
||||||
# 'encrypted' is ignored.
|
# 'encrypted' is ignored.
|
||||||
if ((password.startswith('md5') and len(password) == 32+3) or encrypted == 'UNENCRYPTED'):
|
if ((password.startswith('md5') and len(password) == 32 + 3) or encrypted == 'UNENCRYPTED'):
|
||||||
if password != current_role_attrs['rolpassword']:
|
if password != current_role_attrs['rolpassword']:
|
||||||
pwchanging = True
|
pwchanging = True
|
||||||
elif encrypted == 'ENCRYPTED':
|
elif encrypted == 'ENCRYPTED':
|
||||||
|
@ -321,7 +322,12 @@ def user_alter(cursor, module, user, password, role_attr_flags, encrypted, expir
|
||||||
if current_role_attrs[PRIV_TO_AUTHID_COLUMN[role_attr_name]] != role_attr_value:
|
if current_role_attrs[PRIV_TO_AUTHID_COLUMN[role_attr_name]] != role_attr_value:
|
||||||
role_attr_flags_changing = True
|
role_attr_flags_changing = True
|
||||||
|
|
||||||
expires_changing = (expires is not None and expires == current_role_attrs['rolvaliduntil'])
|
if expires is not None:
|
||||||
|
cursor.execute("SELECT %s::timestamptz;", (expires,))
|
||||||
|
expires_with_tz = cursor.fetchone()[0]
|
||||||
|
expires_changing = expires_with_tz != current_role_attrs.get('rolvaliduntil')
|
||||||
|
else:
|
||||||
|
expires_changing = False
|
||||||
|
|
||||||
if not pwchanging and not role_attr_flags_changing and not expires_changing:
|
if not pwchanging and not role_attr_flags_changing and not expires_changing:
|
||||||
return False
|
return False
|
||||||
|
@ -336,6 +342,7 @@ def user_alter(cursor, module, user, password, role_attr_flags, encrypted, expir
|
||||||
if expires is not None:
|
if expires is not None:
|
||||||
alter.append("VALID UNTIL %(expires)s")
|
alter.append("VALID UNTIL %(expires)s")
|
||||||
|
|
||||||
|
query_password_data = dict(password=password, expires=expires)
|
||||||
try:
|
try:
|
||||||
cursor.execute(' '.join(alter), query_password_data)
|
cursor.execute(' '.join(alter), query_password_data)
|
||||||
changed = True
|
changed = True
|
||||||
|
@ -396,12 +403,11 @@ def user_alter(cursor, module, user, password, role_attr_flags, encrypted, expir
|
||||||
new_role_attrs = cursor.fetchone()
|
new_role_attrs = cursor.fetchone()
|
||||||
|
|
||||||
# Detect any differences between current_ and new_role_attrs.
|
# Detect any differences between current_ and new_role_attrs.
|
||||||
for i in range(len(current_role_attrs)):
|
changed = current_role_attrs != new_role_attrs
|
||||||
if current_role_attrs[i] != new_role_attrs[i]:
|
|
||||||
changed = True
|
|
||||||
|
|
||||||
return changed
|
return changed
|
||||||
|
|
||||||
|
|
||||||
def user_delete(cursor, user):
|
def user_delete(cursor, user):
|
||||||
"""Try to remove a user. Returns True if successful otherwise False"""
|
"""Try to remove a user. Returns True if successful otherwise False"""
|
||||||
cursor.execute("SAVEPOINT ansible_pgsql_user_delete")
|
cursor.execute("SAVEPOINT ansible_pgsql_user_delete")
|
||||||
|
@ -415,6 +421,7 @@ def user_delete(cursor, user):
|
||||||
cursor.execute("RELEASE SAVEPOINT ansible_pgsql_user_delete")
|
cursor.execute("RELEASE SAVEPOINT ansible_pgsql_user_delete")
|
||||||
return True
|
return True
|
||||||
|
|
||||||
|
|
||||||
def has_table_privileges(cursor, user, table, privs):
|
def has_table_privileges(cursor, user, table, privs):
|
||||||
"""
|
"""
|
||||||
Return the difference between the privileges that a user already has and
|
Return the difference between the privileges that a user already has and
|
||||||
|
@ -431,6 +438,7 @@ def has_table_privileges(cursor, user, table, privs):
|
||||||
desired = privs.difference(cur_privs)
|
desired = privs.difference(cur_privs)
|
||||||
return (have_currently, other_current, desired)
|
return (have_currently, other_current, desired)
|
||||||
|
|
||||||
|
|
||||||
def get_table_privileges(cursor, user, table):
|
def get_table_privileges(cursor, user, table):
|
||||||
if '.' in table:
|
if '.' in table:
|
||||||
schema, table = table.split('.', 1)
|
schema, table = table.split('.', 1)
|
||||||
|
@ -441,25 +449,28 @@ def get_table_privileges(cursor, user, table):
|
||||||
cursor.execute(query, (user, table, schema))
|
cursor.execute(query, (user, table, schema))
|
||||||
return frozenset([x[0] for x in cursor.fetchall()])
|
return frozenset([x[0] for x in cursor.fetchall()])
|
||||||
|
|
||||||
|
|
||||||
def grant_table_privileges(cursor, user, table, privs):
|
def grant_table_privileges(cursor, user, table, privs):
|
||||||
# Note: priv escaped by parse_privs
|
# Note: priv escaped by parse_privs
|
||||||
privs = ', '.join(privs)
|
privs = ', '.join(privs)
|
||||||
query = 'GRANT %s ON TABLE %s TO %s' % (
|
query = 'GRANT %s ON TABLE %s TO %s' % (
|
||||||
privs, pg_quote_identifier(table, 'table'), pg_quote_identifier(user, 'role') )
|
privs, pg_quote_identifier(table, 'table'), pg_quote_identifier(user, 'role'))
|
||||||
cursor.execute(query)
|
cursor.execute(query)
|
||||||
|
|
||||||
|
|
||||||
def revoke_table_privileges(cursor, user, table, privs):
|
def revoke_table_privileges(cursor, user, table, privs):
|
||||||
# Note: priv escaped by parse_privs
|
# Note: priv escaped by parse_privs
|
||||||
privs = ', '.join(privs)
|
privs = ', '.join(privs)
|
||||||
query = 'REVOKE %s ON TABLE %s FROM %s' % (
|
query = 'REVOKE %s ON TABLE %s FROM %s' % (
|
||||||
privs, pg_quote_identifier(table, 'table'), pg_quote_identifier(user, 'role') )
|
privs, pg_quote_identifier(table, 'table'), pg_quote_identifier(user, 'role'))
|
||||||
cursor.execute(query)
|
cursor.execute(query)
|
||||||
|
|
||||||
|
|
||||||
def get_database_privileges(cursor, user, db):
|
def get_database_privileges(cursor, user, db):
|
||||||
priv_map = {
|
priv_map = {
|
||||||
'C':'CREATE',
|
'C': 'CREATE',
|
||||||
'T':'TEMPORARY',
|
'T': 'TEMPORARY',
|
||||||
'c':'CONNECT',
|
'c': 'CONNECT',
|
||||||
}
|
}
|
||||||
query = 'SELECT datacl FROM pg_database WHERE datname = %s'
|
query = 'SELECT datacl FROM pg_database WHERE datname = %s'
|
||||||
cursor.execute(query, (db,))
|
cursor.execute(query, (db,))
|
||||||
|
@ -474,6 +485,7 @@ def get_database_privileges(cursor, user, db):
|
||||||
o.add(priv_map[v])
|
o.add(priv_map[v])
|
||||||
return normalize_privileges(o, 'database')
|
return normalize_privileges(o, 'database')
|
||||||
|
|
||||||
|
|
||||||
def has_database_privileges(cursor, user, db, privs):
|
def has_database_privileges(cursor, user, db, privs):
|
||||||
"""
|
"""
|
||||||
Return the difference between the privileges that a user already has and
|
Return the difference between the privileges that a user already has and
|
||||||
|
@ -490,9 +502,10 @@ def has_database_privileges(cursor, user, db, privs):
|
||||||
desired = privs.difference(cur_privs)
|
desired = privs.difference(cur_privs)
|
||||||
return (have_currently, other_current, desired)
|
return (have_currently, other_current, desired)
|
||||||
|
|
||||||
|
|
||||||
def grant_database_privileges(cursor, user, db, privs):
|
def grant_database_privileges(cursor, user, db, privs):
|
||||||
# Note: priv escaped by parse_privs
|
# Note: priv escaped by parse_privs
|
||||||
privs =', '.join(privs)
|
privs = ', '.join(privs)
|
||||||
if user == "PUBLIC":
|
if user == "PUBLIC":
|
||||||
query = 'GRANT %s ON DATABASE %s TO PUBLIC' % (
|
query = 'GRANT %s ON DATABASE %s TO PUBLIC' % (
|
||||||
privs, pg_quote_identifier(db, 'database'))
|
privs, pg_quote_identifier(db, 'database'))
|
||||||
|
@ -502,6 +515,7 @@ def grant_database_privileges(cursor, user, db, privs):
|
||||||
pg_quote_identifier(user, 'role'))
|
pg_quote_identifier(user, 'role'))
|
||||||
cursor.execute(query)
|
cursor.execute(query)
|
||||||
|
|
||||||
|
|
||||||
def revoke_database_privileges(cursor, user, db, privs):
|
def revoke_database_privileges(cursor, user, db, privs):
|
||||||
# Note: priv escaped by parse_privs
|
# Note: priv escaped by parse_privs
|
||||||
privs = ', '.join(privs)
|
privs = ', '.join(privs)
|
||||||
|
@ -514,6 +528,7 @@ def revoke_database_privileges(cursor, user, db, privs):
|
||||||
pg_quote_identifier(user, 'role'))
|
pg_quote_identifier(user, 'role'))
|
||||||
cursor.execute(query)
|
cursor.execute(query)
|
||||||
|
|
||||||
|
|
||||||
def revoke_privileges(cursor, user, privs):
|
def revoke_privileges(cursor, user, privs):
|
||||||
if privs is None:
|
if privs is None:
|
||||||
return False
|
return False
|
||||||
|
@ -532,6 +547,7 @@ def revoke_privileges(cursor, user, privs):
|
||||||
changed = True
|
changed = True
|
||||||
return changed
|
return changed
|
||||||
|
|
||||||
|
|
||||||
def grant_privileges(cursor, user, privs):
|
def grant_privileges(cursor, user, privs):
|
||||||
if privs is None:
|
if privs is None:
|
||||||
return False
|
return False
|
||||||
|
@ -550,6 +566,7 @@ def grant_privileges(cursor, user, privs):
|
||||||
changed = True
|
changed = True
|
||||||
return changed
|
return changed
|
||||||
|
|
||||||
|
|
||||||
def parse_role_attrs(cursor, role_attr_flags):
|
def parse_role_attrs(cursor, role_attr_flags):
|
||||||
"""
|
"""
|
||||||
Parse role attributes string for user creation.
|
Parse role attributes string for user creation.
|
||||||
|
@ -567,20 +584,17 @@ def parse_role_attrs(cursor, role_attr_flags):
|
||||||
Note: "[NO]BYPASSRLS" role attribute introduced in 9.5
|
Note: "[NO]BYPASSRLS" role attribute introduced in 9.5
|
||||||
|
|
||||||
"""
|
"""
|
||||||
flags = frozenset(itertools.chain(_flags, get_valid_flags_by_version(cursor)))
|
flags = frozenset(role.upper() for role in role_attr_flags.split(',') if role)
|
||||||
valid_flags = frozenset(itertools.chain(flags, ('NO%s' % f for f in flags)))
|
|
||||||
|
|
||||||
if ',' in role_attr_flags:
|
valid_flags = frozenset(itertools.chain(FLAGS, get_valid_flags_by_version(cursor)))
|
||||||
flag_set = frozenset(r.upper() for r in role_attr_flags.split(","))
|
valid_flags = frozenset(itertools.chain(valid_flags, ('NO%s' % flag for flag in valid_flags)))
|
||||||
elif role_attr_flags:
|
|
||||||
flag_set = frozenset((role_attr_flags.upper(),))
|
if not flags.issubset(valid_flags):
|
||||||
else:
|
|
||||||
flag_set = frozenset()
|
|
||||||
if not flag_set.issubset(valid_flags):
|
|
||||||
raise InvalidFlagsError('Invalid role_attr_flags specified: %s' %
|
raise InvalidFlagsError('Invalid role_attr_flags specified: %s' %
|
||||||
' '.join(flag_set.difference(valid_flags)))
|
' '.join(flags.difference(valid_flags)))
|
||||||
o_flags = ' '.join(flag_set)
|
|
||||||
return o_flags
|
return ' '.join(flags)
|
||||||
|
|
||||||
|
|
||||||
def normalize_privileges(privs, type_):
|
def normalize_privileges(privs, type_):
|
||||||
new_privs = set(privs)
|
new_privs = set(privs)
|
||||||
|
@ -593,6 +607,7 @@ def normalize_privileges(privs, type_):
|
||||||
|
|
||||||
return new_privs
|
return new_privs
|
||||||
|
|
||||||
|
|
||||||
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.
|
||||||
|
@ -609,8 +624,8 @@ def parse_privs(privs, db):
|
||||||
return privs
|
return privs
|
||||||
|
|
||||||
o_privs = {
|
o_privs = {
|
||||||
'database':{},
|
'database': {},
|
||||||
'table':{}
|
'table': {}
|
||||||
}
|
}
|
||||||
for token in privs.split('/'):
|
for token in privs.split('/'):
|
||||||
if ':' not in token:
|
if ':' not in token:
|
||||||
|
@ -624,13 +639,14 @@ def parse_privs(privs, db):
|
||||||
|
|
||||||
if not priv_set.issubset(VALID_PRIVS[type_]):
|
if not priv_set.issubset(VALID_PRIVS[type_]):
|
||||||
raise InvalidPrivsError('Invalid privs specified for %s: %s' %
|
raise InvalidPrivsError('Invalid privs specified for %s: %s' %
|
||||||
(type_, ' '.join(priv_set.difference(VALID_PRIVS[type_]))))
|
(type_, ' '.join(priv_set.difference(VALID_PRIVS[type_]))))
|
||||||
|
|
||||||
priv_set = normalize_privileges(priv_set, type_)
|
priv_set = normalize_privileges(priv_set, type_)
|
||||||
o_privs[type_][name] = priv_set
|
o_privs[type_][name] = priv_set
|
||||||
|
|
||||||
return o_privs
|
return o_privs
|
||||||
|
|
||||||
|
|
||||||
def get_pg_server_version(cursor):
|
def get_pg_server_version(cursor):
|
||||||
"""
|
"""
|
||||||
Queries Postgres for its server version.
|
Queries Postgres for its server version.
|
||||||
|
@ -646,6 +662,7 @@ def get_pg_server_version(cursor):
|
||||||
cursor.execute("SHOW SERVER_VERSION")
|
cursor.execute("SHOW SERVER_VERSION")
|
||||||
return cursor.fetchone()['server_version']
|
return cursor.fetchone()['server_version']
|
||||||
|
|
||||||
|
|
||||||
def get_valid_flags_by_version(cursor):
|
def get_valid_flags_by_version(cursor):
|
||||||
"""
|
"""
|
||||||
Some role attributes were introduced after certain versions. We want to
|
Some role attributes were introduced after certain versions. We want to
|
||||||
|
@ -655,7 +672,7 @@ def get_valid_flags_by_version(cursor):
|
||||||
|
|
||||||
return [
|
return [
|
||||||
flag
|
flag
|
||||||
for flag, version_introduced in _flags_by_version.items()
|
for flag, version_introduced in FLAGS_BY_VERSION.items()
|
||||||
if current_version >= StrictVersion(version_introduced)
|
if current_version >= StrictVersion(version_introduced)
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -685,7 +702,7 @@ def main():
|
||||||
ssl_mode=dict(default='prefer', choices=['disable', 'allow', 'prefer', 'require', 'verify-ca', 'verify-full']),
|
ssl_mode=dict(default='prefer', choices=['disable', 'allow', 'prefer', 'require', 'verify-ca', 'verify-full']),
|
||||||
ssl_rootcert=dict(default=None)
|
ssl_rootcert=dict(default=None)
|
||||||
),
|
),
|
||||||
supports_check_mode = True
|
supports_check_mode=True
|
||||||
)
|
)
|
||||||
|
|
||||||
user = module.params["user"]
|
user = module.params["user"]
|
||||||
|
@ -696,7 +713,6 @@ def main():
|
||||||
if db == '' and module.params["priv"] is not None:
|
if db == '' and module.params["priv"] is not None:
|
||||||
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"]
|
|
||||||
no_password_changes = module.params["no_password_changes"]
|
no_password_changes = module.params["no_password_changes"]
|
||||||
if module.params["encrypted"]:
|
if module.params["encrypted"]:
|
||||||
encrypted = "ENCRYPTED"
|
encrypted = "ENCRYPTED"
|
||||||
|
@ -712,15 +728,15 @@ def main():
|
||||||
# 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 = {
|
||||||
"login_host":"host",
|
"login_host": "host",
|
||||||
"login_user":"user",
|
"login_user": "user",
|
||||||
"login_password":"password",
|
"login_password": "password",
|
||||||
"port":"port",
|
"port": "port",
|
||||||
"db":"database",
|
"db": "database",
|
||||||
"ssl_mode":"sslmode",
|
"ssl_mode": "sslmode",
|
||||||
"ssl_rootcert":"sslrootcert"
|
"ssl_rootcert": "sslrootcert"
|
||||||
}
|
}
|
||||||
kw = dict( (params_map[k], v) for (k, v) in iteritems(module.params)
|
kw = dict((params_map[k], v) for (k, v) in iteritems(module.params)
|
||||||
if k in params_map and v != "" and v is not None)
|
if k in params_map and v != "" and v is not None)
|
||||||
|
|
||||||
# If a login_unix_socket is specified, incorporate it here.
|
# If a login_unix_socket is specified, incorporate it here.
|
||||||
|
@ -800,6 +816,7 @@ def main():
|
||||||
kw['changed'] = changed
|
kw['changed'] = changed
|
||||||
module.exit_json(**kw)
|
module.exit_json(**kw)
|
||||||
|
|
||||||
|
|
||||||
# import module snippets
|
# import module snippets
|
||||||
from ansible.module_utils.basic import *
|
from ansible.module_utils.basic import *
|
||||||
from ansible.module_utils.database import *
|
from ansible.module_utils.database import *
|
||||||
|
|
|
@ -184,9 +184,9 @@
|
||||||
- "result.stdout_lines[-1] == '(0 rows)'"
|
- "result.stdout_lines[-1] == '(0 rows)'"
|
||||||
|
|
||||||
#
|
#
|
||||||
# Create and destroy user
|
# Create and destroy user, test 'password' and 'encrypted' parameters
|
||||||
#
|
#
|
||||||
- include: test_user.yml
|
- include: test_password.yml
|
||||||
vars:
|
vars:
|
||||||
encrypted: '{{ item.user_creation_encrypted_value }}'
|
encrypted: '{{ item.user_creation_encrypted_value }}'
|
||||||
db_password1: 'secretù' # use UTF-8
|
db_password1: 'secretù' # use UTF-8
|
||||||
|
@ -194,154 +194,31 @@
|
||||||
- user_creation_encrypted_value: 'yes'
|
- user_creation_encrypted_value: 'yes'
|
||||||
- user_creation_encrypted_value: 'no'
|
- user_creation_encrypted_value: 'no'
|
||||||
|
|
||||||
# BYPASSRLS role attribute was introduced in Postgres 9.5, so
|
# BYPASSRLS role attribute was introduced in PostgreSQL 9.5, so
|
||||||
# we want to test atrribute management differently depending
|
# we want to test atrribute management differently depending
|
||||||
# on the version. See https://github.com/ansible/ansible/pull/24625
|
# on the version.
|
||||||
# for more details.
|
- name: Get PostgreSQL version
|
||||||
- name: Get Postgres version
|
|
||||||
become_user: "{{ pg_user }}"
|
become_user: "{{ pg_user }}"
|
||||||
become: True
|
become: True
|
||||||
shell: echo 'SHOW SERVER_VERSION' | psql -d postgres
|
shell: "echo 'SHOW SERVER_VERSION' | psql --tuples-only --no-align --dbname postgres"
|
||||||
register: postgres_version_resp
|
register: postgres_version_resp
|
||||||
|
|
||||||
- name: Print Postgres server version
|
- name: Print PostgreSQL server version
|
||||||
debug:
|
debug:
|
||||||
msg: "{{ postgres_version_resp.stdout_lines[-2] | trim }}"
|
msg: "{{ postgres_version_resp.stdout }}"
|
||||||
|
|
||||||
- name: Role attribute testing for Postgres 9.5+
|
- set_fact:
|
||||||
include: postgresql_user_9.5_or_greater.yml
|
bypassrls_supported: "{{ postgres_version_resp.stdout | version_compare('9.5.0', '>=') }}"
|
||||||
when: (postgres_version_resp.stdout_lines[-2] | trim) | version_compare('9.5.0', '>=')
|
|
||||||
|
|
||||||
- name: Role attribute testing for Postgres versions below 9.5
|
# test 'no_password_change' and 'role_attr_flags' parameters
|
||||||
include: postgresql_user_less_than_9.5.yml
|
- include: test_no_password_change.yml
|
||||||
when: (postgres_version_resp.stdout_lines[-2] | trim) | version_compare('9.5.0', '<')
|
vars:
|
||||||
|
no_password_changes: '{{ item }}'
|
||||||
|
with_items:
|
||||||
|
- 'yes'
|
||||||
|
- 'no'
|
||||||
|
|
||||||
- name: Cleanup the user
|
### TODO: fail_on_user
|
||||||
become_user: "{{ pg_user }}"
|
|
||||||
become: True
|
|
||||||
postgresql_user:
|
|
||||||
name: "{{ db_user1 }}"
|
|
||||||
state: 'absent'
|
|
||||||
login_user: "{{ pg_user }}"
|
|
||||||
db: postgres
|
|
||||||
|
|
||||||
- name: Check that they were removed
|
|
||||||
become_user: "{{ pg_user }}"
|
|
||||||
become: True
|
|
||||||
shell: echo "select * from pg_user where usename='{{ db_user1 }}';" | psql -d postgres
|
|
||||||
register: result
|
|
||||||
|
|
||||||
- assert:
|
|
||||||
that:
|
|
||||||
- "result.stdout_lines[-1] == '(0 rows)'"
|
|
||||||
|
|
||||||
# Test cases to replicate issue 19835
|
|
||||||
- name: Create a user "{{ db_user3 }}" to test issue 19835
|
|
||||||
become_user: "{{ pg_user }}"
|
|
||||||
become: True
|
|
||||||
postgresql_user:
|
|
||||||
name: "{{ db_user3 }}"
|
|
||||||
encrypted: 'yes'
|
|
||||||
password: "md55c8ccfd9d6711fc69a7eae647fc54f51"
|
|
||||||
login_user: "{{ pg_user }}"
|
|
||||||
#role_attr_flags: "NOSUPERUSER,NOCREATEROLE,NOCREATEDB,noinherit,NOLOGIN"
|
|
||||||
db: postgres
|
|
||||||
register: result
|
|
||||||
|
|
||||||
- name: Check that ansible reports that "{{ db_user3 }}" was created for testing issue 19835
|
|
||||||
assert:
|
|
||||||
that:
|
|
||||||
- "result.changed == True"
|
|
||||||
|
|
||||||
- name: debug result
|
|
||||||
debug:
|
|
||||||
var: result
|
|
||||||
|
|
||||||
- name: Check that "{{ db_user3 }}" was created for testing issue 19835
|
|
||||||
become_user: "{{ pg_user }}"
|
|
||||||
become: True
|
|
||||||
shell: echo "select * from pg_user where usename='{{ db_user3 }}';" | psql -d postgres
|
|
||||||
register: result
|
|
||||||
|
|
||||||
- assert:
|
|
||||||
that:
|
|
||||||
- "result.stdout_lines[-1] == '(1 row)'"
|
|
||||||
|
|
||||||
- name: Modify user "{{ db_user3 }}" to have only login role attributes for testing issue 19835
|
|
||||||
become_user: "{{ pg_user }}"
|
|
||||||
become: True
|
|
||||||
postgresql_user:
|
|
||||||
name: "{{ db_user3 }}"
|
|
||||||
state: "present"
|
|
||||||
role_attr_flags: "NOSUPERUSER,NOCREATEROLE,NOCREATEDB,noinherit"
|
|
||||||
login_user: "{{ pg_user }}"
|
|
||||||
db: postgres
|
|
||||||
register: result
|
|
||||||
|
|
||||||
- name: Check that ansible reports it modified the roles for testing issue 19835
|
|
||||||
assert:
|
|
||||||
that:
|
|
||||||
- "result.changed == True"
|
|
||||||
|
|
||||||
- name: Check that the user "{{ db_user3 }}" has the requested role attributes for testing issue 19835
|
|
||||||
become_user: "{{ pg_user }}"
|
|
||||||
become: True
|
|
||||||
shell: echo "select 'super:'||rolsuper, 'createrole:'||rolcreaterole, 'create:'||rolcreatedb, 'inherit:'||rolinherit, 'login:'||rolcanlogin from pg_roles where rolname='{{ db_user3 }}';" | psql -d postgres
|
|
||||||
register: result
|
|
||||||
|
|
||||||
- name: Modify a single role attribute on the user "{{ db_user3 }}" with no_password_changes set to yes. issue 19835
|
|
||||||
become_user: "{{ pg_user }}"
|
|
||||||
become: True
|
|
||||||
postgresql_user:
|
|
||||||
name: "{{ db_user3 }}"
|
|
||||||
state: "present"
|
|
||||||
role_attr_flags: "CREATEDB"
|
|
||||||
no_password_changes: yes
|
|
||||||
login_user: "{{ pg_user }}"
|
|
||||||
db: postgres
|
|
||||||
register: result
|
|
||||||
|
|
||||||
- name: Check that ansible reports it modified the role with no_password_changes set to yes. issue 19835
|
|
||||||
assert:
|
|
||||||
that:
|
|
||||||
- "result.changed == True"
|
|
||||||
|
|
||||||
- name: Check that the user "{{ db_user3 }}" has the requested role attributes with no_password_changes set to yes. issue 19835
|
|
||||||
become_user: "{{ pg_user }}"
|
|
||||||
become: True
|
|
||||||
shell: echo "select 'super:'||rolsuper, 'createrole:'||rolcreaterole, 'create:'||rolcreatedb, 'inherit:'||rolinherit, 'login:'||rolcanlogin from pg_roles where rolname='{{ db_user3 }}';" | psql -d postgres
|
|
||||||
register: result
|
|
||||||
|
|
||||||
- name: Assert that the request role attributes check for user "{{ db_user3 }}" was correct with no_password_changes set to yes. issue 19835
|
|
||||||
assert:
|
|
||||||
that:
|
|
||||||
- "result.stdout_lines[-1] == '(1 row)'"
|
|
||||||
- "'super:f' in result.stdout_lines[-2]"
|
|
||||||
- "'createrole:f' in result.stdout_lines[-2]"
|
|
||||||
- "'create:t' in result.stdout_lines[-2]"
|
|
||||||
- "'inherit:f' in result.stdout_lines[-2]"
|
|
||||||
- "'login:t' in result.stdout_lines[-2]"
|
|
||||||
|
|
||||||
- name: Cleanup the "{{ db_user3 }}" user
|
|
||||||
become_user: "{{ pg_user }}"
|
|
||||||
become: True
|
|
||||||
postgresql_user:
|
|
||||||
name: "{{ db_user3 }}"
|
|
||||||
state: 'absent'
|
|
||||||
login_user: "{{ pg_user }}"
|
|
||||||
db: postgres
|
|
||||||
|
|
||||||
- name: Check that "{{ db_user3 }}" was removed
|
|
||||||
become_user: "{{ pg_user }}"
|
|
||||||
become: True
|
|
||||||
shell: echo "select * from pg_user where usename='{{ db_user3 }}';" | psql -d postgres
|
|
||||||
register: result
|
|
||||||
|
|
||||||
- assert:
|
|
||||||
that:
|
|
||||||
- "result.stdout_lines[-1] == '(0 rows)'"
|
|
||||||
|
|
||||||
### TODO: test expires, fail_on_user
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# Test db ownership
|
# Test db ownership
|
||||||
|
|
|
@ -1,90 +0,0 @@
|
||||||
---
|
|
||||||
- name: Create a user with all role attributes
|
|
||||||
become_user: "{{ pg_user }}"
|
|
||||||
become: True
|
|
||||||
postgresql_user:
|
|
||||||
name: "{{ db_user1 }}"
|
|
||||||
state: "present"
|
|
||||||
role_attr_flags: "SUPERUSER,CREATEROLE,CREATEDB,INHERIT,login,BYPASSRLS"
|
|
||||||
login_user: "{{ pg_user }}"
|
|
||||||
db: postgres
|
|
||||||
|
|
||||||
- name: Check that the user has the requested role attributes
|
|
||||||
become_user: "{{ pg_user }}"
|
|
||||||
become: True
|
|
||||||
shell: echo "select 'super:'||rolsuper, 'createrole:'||rolcreaterole, 'create:'||rolcreatedb, 'inherit:'||rolinherit, 'login:'||rolcanlogin, 'bypassrls:'||rolbypassrls from pg_roles where rolname='{{ db_user1 }}';" | psql -d postgres
|
|
||||||
register: result
|
|
||||||
|
|
||||||
- assert:
|
|
||||||
that:
|
|
||||||
- "result.stdout_lines[-1] == '(1 row)'"
|
|
||||||
- "'super:t' in result.stdout_lines[-2]"
|
|
||||||
- "'createrole:t' in result.stdout_lines[-2]"
|
|
||||||
- "'create:t' in result.stdout_lines[-2]"
|
|
||||||
- "'inherit:t' in result.stdout_lines[-2]"
|
|
||||||
- "'login:t' in result.stdout_lines[-2]"
|
|
||||||
- "'bypassrls:t' in result.stdout_lines[-2]"
|
|
||||||
|
|
||||||
- name: Modify a user to have no role attributes
|
|
||||||
become_user: "{{ pg_user }}"
|
|
||||||
become: True
|
|
||||||
postgresql_user:
|
|
||||||
name: "{{ db_user1 }}"
|
|
||||||
state: "present"
|
|
||||||
role_attr_flags: "NOSUPERUSER,NOCREATEROLE,NOCREATEDB,noinherit,NOLOGIN,NOBYPASSRLS"
|
|
||||||
login_user: "{{ pg_user }}"
|
|
||||||
db: postgres
|
|
||||||
register: result
|
|
||||||
|
|
||||||
- name: Check that ansible reports it modified the role
|
|
||||||
assert:
|
|
||||||
that:
|
|
||||||
- "result.changed == True"
|
|
||||||
|
|
||||||
- name: Check that the user has the requested role attributes
|
|
||||||
become_user: "{{ pg_user }}"
|
|
||||||
become: True
|
|
||||||
shell: echo "select 'super:'||rolsuper, 'createrole:'||rolcreaterole, 'create:'||rolcreatedb, 'inherit:'||rolinherit, 'login:'||rolcanlogin, 'bypassrls:'||rolbypassrls from pg_roles where rolname='{{ db_user1 }}';" | psql -d postgres
|
|
||||||
register: result
|
|
||||||
|
|
||||||
- assert:
|
|
||||||
that:
|
|
||||||
- "result.stdout_lines[-1] == '(1 row)'"
|
|
||||||
- "'super:f' in result.stdout_lines[-2]"
|
|
||||||
- "'createrole:f' in result.stdout_lines[-2]"
|
|
||||||
- "'create:f' in result.stdout_lines[-2]"
|
|
||||||
- "'inherit:f' in result.stdout_lines[-2]"
|
|
||||||
- "'login:f' in result.stdout_lines[-2]"
|
|
||||||
- "'bypassrls:f' in result.stdout_lines[-2]"
|
|
||||||
|
|
||||||
- name: Modify a single role attribute on a user
|
|
||||||
become_user: "{{ pg_user }}"
|
|
||||||
become: True
|
|
||||||
postgresql_user:
|
|
||||||
name: "{{ db_user1 }}"
|
|
||||||
state: "present"
|
|
||||||
role_attr_flags: "LOGIN"
|
|
||||||
login_user: "{{ pg_user }}"
|
|
||||||
db: postgres
|
|
||||||
register: result
|
|
||||||
|
|
||||||
- name: Check that ansible reports it modified the role
|
|
||||||
assert:
|
|
||||||
that:
|
|
||||||
- "result.changed == True"
|
|
||||||
|
|
||||||
- name: Check that the user has the requested role attributes
|
|
||||||
become_user: "{{ pg_user }}"
|
|
||||||
become: True
|
|
||||||
shell: echo "select 'super:'||rolsuper, 'createrole:'||rolcreaterole, 'create:'||rolcreatedb, 'inherit:'||rolinherit, 'login:'||rolcanlogin, 'bypassrls:'||rolbypassrls from pg_roles where rolname='{{ db_user1 }}';" | psql -d postgres
|
|
||||||
register: result
|
|
||||||
|
|
||||||
- assert:
|
|
||||||
that:
|
|
||||||
- "result.stdout_lines[-1] == '(1 row)'"
|
|
||||||
- "'super:f' in result.stdout_lines[-2]"
|
|
||||||
- "'createrole:f' in result.stdout_lines[-2]"
|
|
||||||
- "'create:f' in result.stdout_lines[-2]"
|
|
||||||
- "'inherit:f' in result.stdout_lines[-2]"
|
|
||||||
- "'login:t' in result.stdout_lines[-2]"
|
|
||||||
- "'bypassrls:f' in result.stdout_lines[-2]"
|
|
|
@ -1,87 +0,0 @@
|
||||||
---
|
|
||||||
- name: Create a user with all role attributes
|
|
||||||
become_user: "{{ pg_user }}"
|
|
||||||
become: True
|
|
||||||
postgresql_user:
|
|
||||||
name: "{{ db_user1 }}"
|
|
||||||
state: "present"
|
|
||||||
role_attr_flags: "SUPERUSER,CREATEROLE,CREATEDB,INHERIT,login"
|
|
||||||
login_user: "{{ pg_user }}"
|
|
||||||
db: postgres
|
|
||||||
|
|
||||||
- name: Check that the user has the requested role attributes
|
|
||||||
become_user: "{{ pg_user }}"
|
|
||||||
become: True
|
|
||||||
shell: echo "select 'super:'||rolsuper, 'createrole:'||rolcreaterole, 'create:'||rolcreatedb, 'inherit:'||rolinherit, 'login:'||rolcanlogin from pg_roles where rolname='{{ db_user1 }}';" | psql -d postgres
|
|
||||||
register: result
|
|
||||||
|
|
||||||
- assert:
|
|
||||||
that:
|
|
||||||
- "result.stdout_lines[-1] == '(1 row)'"
|
|
||||||
- "'super:t' in result.stdout_lines[-2]"
|
|
||||||
- "'createrole:t' in result.stdout_lines[-2]"
|
|
||||||
- "'create:t' in result.stdout_lines[-2]"
|
|
||||||
- "'inherit:t' in result.stdout_lines[-2]"
|
|
||||||
- "'login:t' in result.stdout_lines[-2]"
|
|
||||||
|
|
||||||
- name: Modify a user to have no role attributes
|
|
||||||
become_user: "{{ pg_user }}"
|
|
||||||
become: True
|
|
||||||
postgresql_user:
|
|
||||||
name: "{{ db_user1 }}"
|
|
||||||
state: "present"
|
|
||||||
role_attr_flags: "NOSUPERUSER,NOCREATEROLE,NOCREATEDB,noinherit,NOLOGIN"
|
|
||||||
login_user: "{{ pg_user }}"
|
|
||||||
db: postgres
|
|
||||||
register: result
|
|
||||||
|
|
||||||
- name: Check that ansible reports it modified the role
|
|
||||||
assert:
|
|
||||||
that:
|
|
||||||
- "result.changed == True"
|
|
||||||
|
|
||||||
- name: Check that the user has the requested role attributes
|
|
||||||
become_user: "{{ pg_user }}"
|
|
||||||
become: True
|
|
||||||
shell: echo "select 'super:'||rolsuper, 'createrole:'||rolcreaterole, 'create:'||rolcreatedb, 'inherit:'||rolinherit, 'login:'||rolcanlogin from pg_roles where rolname='{{ db_user1 }}';" | psql -d postgres
|
|
||||||
register: result
|
|
||||||
|
|
||||||
- assert:
|
|
||||||
that:
|
|
||||||
- "result.stdout_lines[-1] == '(1 row)'"
|
|
||||||
- "'super:f' in result.stdout_lines[-2]"
|
|
||||||
- "'createrole:f' in result.stdout_lines[-2]"
|
|
||||||
- "'create:f' in result.stdout_lines[-2]"
|
|
||||||
- "'inherit:f' in result.stdout_lines[-2]"
|
|
||||||
- "'login:f' in result.stdout_lines[-2]"
|
|
||||||
|
|
||||||
- name: Modify a single role attribute on a user
|
|
||||||
become_user: "{{ pg_user }}"
|
|
||||||
become: True
|
|
||||||
postgresql_user:
|
|
||||||
name: "{{ db_user1 }}"
|
|
||||||
state: "present"
|
|
||||||
role_attr_flags: "LOGIN"
|
|
||||||
login_user: "{{ pg_user }}"
|
|
||||||
db: postgres
|
|
||||||
register: result
|
|
||||||
|
|
||||||
- name: Check that ansible reports it modified the role
|
|
||||||
assert:
|
|
||||||
that:
|
|
||||||
- "result.changed == True"
|
|
||||||
|
|
||||||
- name: Check that the user has the requested role attributes
|
|
||||||
become_user: "{{ pg_user }}"
|
|
||||||
become: True
|
|
||||||
shell: echo "select 'super:'||rolsuper, 'createrole:'||rolcreaterole, 'create:'||rolcreatedb, 'inherit:'||rolinherit, 'login:'||rolcanlogin from pg_roles where rolname='{{ db_user1 }}';" | psql -d postgres
|
|
||||||
register: result
|
|
||||||
|
|
||||||
- assert:
|
|
||||||
that:
|
|
||||||
- "result.stdout_lines[-1] == '(1 row)'"
|
|
||||||
- "'super:f' in result.stdout_lines[-2]"
|
|
||||||
- "'createrole:f' in result.stdout_lines[-2]"
|
|
||||||
- "'create:f' in result.stdout_lines[-2]"
|
|
||||||
- "'inherit:f' in result.stdout_lines[-2]"
|
|
||||||
- "'login:t' in result.stdout_lines[-2]"
|
|
|
@ -0,0 +1,167 @@
|
||||||
|
- vars:
|
||||||
|
task_parameters: &task_parameters
|
||||||
|
become_user: "{{ pg_user }}"
|
||||||
|
become: True
|
||||||
|
register: result
|
||||||
|
postgresql_parameters: ¶meters
|
||||||
|
db: postgres
|
||||||
|
name: "{{ db_user1 }}"
|
||||||
|
login_user: "{{ pg_user }}"
|
||||||
|
|
||||||
|
block:
|
||||||
|
|
||||||
|
- name: Create a user with all role attributes
|
||||||
|
<<: *task_parameters
|
||||||
|
postgresql_user:
|
||||||
|
<<: *parameters
|
||||||
|
state: "present"
|
||||||
|
role_attr_flags: "SUPERUSER,CREATEROLE,CREATEDB,INHERIT,login{{ bypassrls_supported | ternary(',BYPASSRLS', '') }}"
|
||||||
|
no_password_changes: '{{ no_password_changes }}' # no_password_changes is ignored when user doesn't already exist
|
||||||
|
|
||||||
|
- name: Check that the user has the requested role attributes
|
||||||
|
<<: *task_parameters
|
||||||
|
shell: "echo \"select 'super:'||rolsuper, 'createrole:'||rolcreaterole, 'create:'||rolcreatedb, 'inherit:'||rolinherit, 'login:'||rolcanlogin {{ bypassrls_supported | ternary(\", 'bypassrls:'||rolbypassrls\", '') }} from pg_roles where rolname='{{ db_user1 }}';\" | psql -d postgres"
|
||||||
|
|
||||||
|
- assert:
|
||||||
|
that:
|
||||||
|
- "result.stdout_lines[-1] == '(1 row)'"
|
||||||
|
- "'super:t' in result.stdout_lines[-2]"
|
||||||
|
- "'createrole:t' in result.stdout_lines[-2]"
|
||||||
|
- "'create:t' in result.stdout_lines[-2]"
|
||||||
|
- "'inherit:t' in result.stdout_lines[-2]"
|
||||||
|
- "'login:t' in result.stdout_lines[-2]"
|
||||||
|
|
||||||
|
- block:
|
||||||
|
- name: Check that the user has the requested role attribute BYPASSRLS
|
||||||
|
<<: *task_parameters
|
||||||
|
shell: "echo \"select 'bypassrls:'||rolbypassrls from pg_roles where rolname='{{ db_user1 }}';\" | psql -d postgres"
|
||||||
|
|
||||||
|
- assert:
|
||||||
|
that:
|
||||||
|
- "not bypassrls_supported or 'bypassrls:t' in result.stdout_lines[-2]"
|
||||||
|
when: bypassrls_supported
|
||||||
|
|
||||||
|
- name: Modify a user to have no role attributes
|
||||||
|
<<: *task_parameters
|
||||||
|
postgresql_user:
|
||||||
|
<<: *parameters
|
||||||
|
state: "present"
|
||||||
|
role_attr_flags: "NOSUPERUSER,NOCREATEROLE,NOCREATEDB,noinherit,NOLOGIN{{ bypassrls_supported | ternary(',NOBYPASSRLS', '') }}"
|
||||||
|
no_password_changes: '{{ no_password_changes }}'
|
||||||
|
|
||||||
|
- name: Check that ansible reports it modified the role
|
||||||
|
assert:
|
||||||
|
that:
|
||||||
|
- "result.changed"
|
||||||
|
|
||||||
|
- name: "Check that the user doesn't have any attribute"
|
||||||
|
<<: *task_parameters
|
||||||
|
shell: "echo \"select 'super:'||rolsuper, 'createrole:'||rolcreaterole, 'create:'||rolcreatedb, 'inherit:'||rolinherit, 'login:'||rolcanlogin from pg_roles where rolname='{{ db_user1 }}';\" | psql -d postgres"
|
||||||
|
|
||||||
|
- assert:
|
||||||
|
that:
|
||||||
|
- "result.stdout_lines[-1] == '(1 row)'"
|
||||||
|
- "'super:f' in result.stdout_lines[-2]"
|
||||||
|
- "'createrole:f' in result.stdout_lines[-2]"
|
||||||
|
- "'create:f' in result.stdout_lines[-2]"
|
||||||
|
- "'inherit:f' in result.stdout_lines[-2]"
|
||||||
|
- "'login:f' in result.stdout_lines[-2]"
|
||||||
|
|
||||||
|
- block:
|
||||||
|
- name: Check that the user has the requested role attribute BYPASSRLS
|
||||||
|
<<: *task_parameters
|
||||||
|
shell: "echo \"select 'bypassrls:'||rolbypassrls from pg_roles where rolname='{{ db_user1 }}';\" | psql -d postgres"
|
||||||
|
|
||||||
|
- assert:
|
||||||
|
that:
|
||||||
|
- "not bypassrls_supported or 'bypassrls:f' in result.stdout_lines[-2]"
|
||||||
|
when: bypassrls_supported
|
||||||
|
|
||||||
|
- name: Try to add an invalid attribute
|
||||||
|
<<: *task_parameters
|
||||||
|
postgresql_user:
|
||||||
|
<<: *parameters
|
||||||
|
state: "present"
|
||||||
|
role_attr_flags: "NOSUPERUSER,NOCREATEROLE,NOCREATEDB,noinherit,NOLOGIN{{ bypassrls_supported | ternary(',NOBYPASSRLS', '') }},INVALID"
|
||||||
|
no_password_changes: '{{ no_password_changes }}'
|
||||||
|
ignore_errors: True
|
||||||
|
|
||||||
|
- name: Check that ansible reports failure
|
||||||
|
assert:
|
||||||
|
that:
|
||||||
|
- "not result.changed"
|
||||||
|
- "result.failed"
|
||||||
|
- "result.msg == 'Invalid role_attr_flags specified: INVALID'"
|
||||||
|
|
||||||
|
- name: Modify a single role attribute on a user
|
||||||
|
<<: *task_parameters
|
||||||
|
postgresql_user:
|
||||||
|
<<: *parameters
|
||||||
|
state: "present"
|
||||||
|
role_attr_flags: "LOGIN"
|
||||||
|
no_password_changes: '{{ no_password_changes }}'
|
||||||
|
|
||||||
|
- name: Check that ansible reports it modified the role
|
||||||
|
assert:
|
||||||
|
that:
|
||||||
|
- "result.changed"
|
||||||
|
|
||||||
|
- name: Check the role attributes
|
||||||
|
<<: *task_parameters
|
||||||
|
shell: echo "select 'super:'||rolsuper, 'createrole:'||rolcreaterole, 'create:'||rolcreatedb, 'inherit:'||rolinherit, 'login:'||rolcanlogin from pg_roles where rolname='{{ db_user1 }}';" | psql -d postgres
|
||||||
|
|
||||||
|
- assert:
|
||||||
|
that:
|
||||||
|
- "result.stdout_lines[-1] == '(1 row)'"
|
||||||
|
- "'super:f' in result.stdout_lines[-2]"
|
||||||
|
- "'createrole:f' in result.stdout_lines[-2]"
|
||||||
|
- "'create:f' in result.stdout_lines[-2]"
|
||||||
|
- "'inherit:f' in result.stdout_lines[-2]"
|
||||||
|
- "'login:t' in result.stdout_lines[-2]"
|
||||||
|
|
||||||
|
- block:
|
||||||
|
- name: Check the role attribute BYPASSRLS
|
||||||
|
<<: *task_parameters
|
||||||
|
shell: echo "select 'bypassrls:'||rolbypassrls from pg_roles where rolname='{{ db_user1 }}';" | psql -d postgres
|
||||||
|
|
||||||
|
- assert:
|
||||||
|
that:
|
||||||
|
- "(postgres_version_resp.stdout | version_compare('9.5.0', '<')) or 'bypassrls:f' in result.stdout_lines[-2]"
|
||||||
|
when: bypassrls_supported
|
||||||
|
|
||||||
|
- name: Check that using same attribute a second time does nothing
|
||||||
|
<<: *task_parameters
|
||||||
|
postgresql_user:
|
||||||
|
<<: *parameters
|
||||||
|
state: "present"
|
||||||
|
role_attr_flags: "LOGIN"
|
||||||
|
no_password_changes: '{{ no_password_changes }}'
|
||||||
|
environment:
|
||||||
|
PGOPTIONS: '-c default_transaction_read_only=on' # ensure 'alter user' query isn't executed
|
||||||
|
|
||||||
|
- name: Check there isn't any update reported
|
||||||
|
assert:
|
||||||
|
that:
|
||||||
|
- "not result.changed"
|
||||||
|
|
||||||
|
- name: Cleanup the user
|
||||||
|
<<: *task_parameters
|
||||||
|
postgresql_user:
|
||||||
|
<<: *parameters
|
||||||
|
state: 'absent'
|
||||||
|
no_password_changes: '{{ no_password_changes }}' # user deletion: no_password_changes is ignored
|
||||||
|
|
||||||
|
- name: Check that user was removed
|
||||||
|
<<: *task_parameters
|
||||||
|
shell: echo "select * from pg_user where usename='{{ db_user1 }}';" | psql -d postgres
|
||||||
|
|
||||||
|
- assert:
|
||||||
|
that:
|
||||||
|
- "result.stdout_lines[-1] == '(0 rows)'"
|
||||||
|
|
||||||
|
always:
|
||||||
|
- name: Cleanup the user
|
||||||
|
<<: *task_parameters
|
||||||
|
postgresql_user:
|
||||||
|
<<: *parameters
|
||||||
|
state: 'absent'
|
|
@ -8,7 +8,7 @@
|
||||||
name: "{{ db_user1 }}"
|
name: "{{ db_user1 }}"
|
||||||
login_user: "{{ pg_user }}"
|
login_user: "{{ pg_user }}"
|
||||||
|
|
||||||
block: # block is only used here in order to be able to define YAML anchors at the beginning in 'vars' section
|
block:
|
||||||
- name: 'Check that PGOPTIONS environment variable is effective (1/2)'
|
- name: 'Check that PGOPTIONS environment variable is effective (1/2)'
|
||||||
<<: *task_parameters
|
<<: *task_parameters
|
||||||
postgresql_user:
|
postgresql_user:
|
||||||
|
@ -63,6 +63,27 @@
|
||||||
that:
|
that:
|
||||||
- "{{ not result|changed }}"
|
- "{{ not result|changed }}"
|
||||||
|
|
||||||
|
- name: 'Define an expiration time'
|
||||||
|
<<: *task_parameters
|
||||||
|
postgresql_user:
|
||||||
|
<<: *parameters
|
||||||
|
expires: '2025-01-01'
|
||||||
|
environment:
|
||||||
|
PGCLIENTENCODING: 'UTF8'
|
||||||
|
|
||||||
|
- <<: *changed
|
||||||
|
|
||||||
|
- name: 'Redefine the same expiration time'
|
||||||
|
<<: *task_parameters
|
||||||
|
postgresql_user:
|
||||||
|
expires: '2025-01-01'
|
||||||
|
<<: *parameters
|
||||||
|
environment:
|
||||||
|
PGCLIENTENCODING: 'UTF8'
|
||||||
|
PGOPTIONS: '-c default_transaction_read_only=on' # ensure 'alter user' query isn't executed
|
||||||
|
|
||||||
|
- <<: *not_changed
|
||||||
|
|
||||||
- block:
|
- block:
|
||||||
|
|
||||||
- name: 'Using MD5-hashed password: check that password not changed when using cleartext password'
|
- name: 'Using MD5-hashed password: check that password not changed when using cleartext password'
|
||||||
|
@ -72,7 +93,7 @@
|
||||||
password: '{{ db_password1 }}'
|
password: '{{ db_password1 }}'
|
||||||
encrypted: 'yes'
|
encrypted: 'yes'
|
||||||
environment:
|
environment:
|
||||||
# PGCLIENTENCODING: 'UTF8'
|
PGCLIENTENCODING: 'UTF8'
|
||||||
PGOPTIONS: '-c default_transaction_read_only=on' # ensure 'alter user' query isn't executed
|
PGOPTIONS: '-c default_transaction_read_only=on' # ensure 'alter user' query isn't executed
|
||||||
|
|
||||||
- <<: *not_changed
|
- <<: *not_changed
|
||||||
|
@ -99,6 +120,18 @@
|
||||||
|
|
||||||
- <<: *not_changed
|
- <<: *not_changed
|
||||||
|
|
||||||
|
- name: 'Redefine the same expiration time and password (encrypted)'
|
||||||
|
<<: *task_parameters
|
||||||
|
postgresql_user:
|
||||||
|
<<: *parameters
|
||||||
|
encrypted: 'yes'
|
||||||
|
password: "md5{{ (db_password1 ~ db_user1) | hash('md5')}}"
|
||||||
|
expires: '2025-01-01'
|
||||||
|
environment:
|
||||||
|
PGOPTIONS: '-c default_transaction_read_only=on' # ensure 'alter user' query isn't executed
|
||||||
|
|
||||||
|
- <<: *not_changed
|
||||||
|
|
||||||
- name: 'Using MD5-hashed password: check that password changed when using another cleartext password'
|
- name: 'Using MD5-hashed password: check that password changed when using another cleartext password'
|
||||||
<<: *task_parameters
|
<<: *task_parameters
|
||||||
postgresql_user:
|
postgresql_user:
|
||||||
|
@ -144,6 +177,19 @@
|
||||||
|
|
||||||
- <<: *not_changed
|
- <<: *not_changed
|
||||||
|
|
||||||
|
- name: 'Redefine the same expiration time and password (not encrypted)'
|
||||||
|
<<: *task_parameters
|
||||||
|
postgresql_user:
|
||||||
|
<<: *parameters
|
||||||
|
password: "{{ db_password1 }}"
|
||||||
|
encrypted: 'no'
|
||||||
|
expires: '2025-01-01'
|
||||||
|
environment:
|
||||||
|
PGCLIENTENCODING: 'UTF8'
|
||||||
|
PGOPTIONS: '-c default_transaction_read_only=on' # ensure 'alter user' query isn't executed
|
||||||
|
|
||||||
|
- <<: *not_changed
|
||||||
|
|
||||||
- name: 'Using cleartext password: check that password changed when using another cleartext password'
|
- name: 'Using cleartext password: check that password changed when using another cleartext password'
|
||||||
<<: *task_parameters
|
<<: *task_parameters
|
||||||
postgresql_user:
|
postgresql_user:
|
||||||
|
@ -184,3 +230,10 @@
|
||||||
PGOPTIONS: '-c default_transaction_read_only=on' # ensure 'alter user' query isn't executed
|
PGOPTIONS: '-c default_transaction_read_only=on' # ensure 'alter user' query isn't executed
|
||||||
|
|
||||||
- <<: *not_changed
|
- <<: *not_changed
|
||||||
|
|
||||||
|
always:
|
||||||
|
- name: Remove user
|
||||||
|
<<: *task_parameters
|
||||||
|
postgresql_user:
|
||||||
|
state: 'absent'
|
||||||
|
<<: *parameters
|
|
@ -233,7 +233,6 @@ lib/ansible/modules/database/postgresql/postgresql_ext.py
|
||||||
lib/ansible/modules/database/postgresql/postgresql_lang.py
|
lib/ansible/modules/database/postgresql/postgresql_lang.py
|
||||||
lib/ansible/modules/database/postgresql/postgresql_privs.py
|
lib/ansible/modules/database/postgresql/postgresql_privs.py
|
||||||
lib/ansible/modules/database/postgresql/postgresql_schema.py
|
lib/ansible/modules/database/postgresql/postgresql_schema.py
|
||||||
lib/ansible/modules/database/postgresql/postgresql_user.py
|
|
||||||
lib/ansible/modules/database/vertica/vertica_configuration.py
|
lib/ansible/modules/database/vertica/vertica_configuration.py
|
||||||
lib/ansible/modules/database/vertica/vertica_facts.py
|
lib/ansible/modules/database/vertica/vertica_facts.py
|
||||||
lib/ansible/modules/database/vertica/vertica_role.py
|
lib/ansible/modules/database/vertica/vertica_role.py
|
||||||
|
|
Loading…
Reference in a new issue