mirror of
https://github.com/valitydev/salt.git
synced 2024-11-07 08:58:59 +00:00
Merge pull request #30053 from akissa/add-postgres-privileges-support
Add postgres privileges support
This commit is contained in:
commit
e915f4b591
6
doc/ref/states/all/salt.states.postgres_privileges.rst
Normal file
6
doc/ref/states/all/salt.states.postgres_privileges.rst
Normal file
@ -0,0 +1,6 @@
|
||||
===============================
|
||||
salt.states.postgres_privileges
|
||||
===============================
|
||||
|
||||
.. automodule:: salt.states.postgres_privileges
|
||||
:members:
|
@ -31,6 +31,7 @@ import distutils.version # pylint: disable=import-error,no-name-in-module
|
||||
import logging
|
||||
import hashlib
|
||||
import os
|
||||
import re
|
||||
import tempfile
|
||||
try:
|
||||
import csv
|
||||
@ -41,6 +42,7 @@ except ImportError:
|
||||
# Import salt libs
|
||||
import salt.utils
|
||||
import salt.utils.itertools
|
||||
from salt.exceptions import SaltInvocationError
|
||||
|
||||
# Import 3rd-party libs
|
||||
import salt.ext.six as six
|
||||
@ -62,6 +64,40 @@ _EXTENSION_FLAGS = (
|
||||
_EXTENSION_TO_UPGRADE,
|
||||
_EXTENSION_TO_MOVE,
|
||||
)
|
||||
_PRIVILEGES_MAP = {
|
||||
'a': 'INSERT',
|
||||
'C': 'CREATE',
|
||||
'D': 'TRUNCATE',
|
||||
'c': 'CONNECT',
|
||||
't': 'TRIGGER',
|
||||
'r': 'SELECT',
|
||||
'U': 'USAGE',
|
||||
'T': 'TEMPORARY',
|
||||
'w': 'UPDATE',
|
||||
'X': 'EXECUTE',
|
||||
'x': 'REFERENCES',
|
||||
'd': 'DELETE',
|
||||
'*': 'GRANT',
|
||||
}
|
||||
_PRIVILEGES_OBJECTS = frozenset(
|
||||
(
|
||||
'schema',
|
||||
'tablespace',
|
||||
'language',
|
||||
'sequence',
|
||||
'table',
|
||||
'group',
|
||||
'database',
|
||||
)
|
||||
)
|
||||
_PRIVILEGE_TYPE_MAP = {
|
||||
'table': 'arwdDxt',
|
||||
'tablespace': 'C',
|
||||
'language': 'U',
|
||||
'sequence': 'rwU',
|
||||
'schema': 'UC',
|
||||
'database': 'CTc',
|
||||
}
|
||||
|
||||
|
||||
def __virtual__():
|
||||
@ -2204,3 +2240,666 @@ def language_remove(name,
|
||||
password=password)
|
||||
|
||||
return ret['retcode'] == 0
|
||||
|
||||
|
||||
def _make_privileges_list_query(name, object_type, prepend):
|
||||
'''
|
||||
Generate the SQL required for specific object type
|
||||
'''
|
||||
if object_type == 'table':
|
||||
query = (' '.join([
|
||||
'SELECT relacl AS name',
|
||||
'FROM pg_catalog.pg_class c',
|
||||
'JOIN pg_catalog.pg_namespace n',
|
||||
'ON n.oid = c.relnamespace',
|
||||
"WHERE nspname = '{0}'",
|
||||
"AND relname = '{1}'",
|
||||
"AND relkind = 'r'",
|
||||
'ORDER BY relname',
|
||||
])).format(prepend, name)
|
||||
elif object_type == 'sequence':
|
||||
query = (' '.join([
|
||||
'SELECT relacl AS name',
|
||||
'FROM pg_catalog.pg_class c',
|
||||
'JOIN pg_catalog.pg_namespace n',
|
||||
'ON n.oid = c.relnamespace',
|
||||
"WHERE nspname = '{0}'",
|
||||
"AND relname = '{1}'",
|
||||
"AND relkind = 'S'",
|
||||
'ORDER BY relname',
|
||||
])).format(prepend, name)
|
||||
elif object_type == 'schema':
|
||||
query = (' '.join([
|
||||
'SELECT nspacl AS name',
|
||||
'FROM pg_catalog.pg_namespace',
|
||||
"WHERE nspname = '{0}'",
|
||||
'ORDER BY nspname',
|
||||
])).format(name)
|
||||
# elif object_type == 'function':
|
||||
# query = (' '.join([
|
||||
# 'SELECT proacl AS name',
|
||||
# 'FROM pg_catalog.pg_proc p',
|
||||
# 'JOIN pg_catalog.pg_namespace n',
|
||||
# 'ON n.oid = p.pronamespace',
|
||||
# "WHERE nspname = '{0}'",
|
||||
# "AND proname = '{1}'",
|
||||
# 'ORDER BY proname, proargtypes',
|
||||
# ])).format(prepend, name)
|
||||
elif object_type == 'tablespace':
|
||||
query = (' '.join([
|
||||
'SELECT spcacl AS name',
|
||||
'FROM pg_catalog.pg_tablespace',
|
||||
"WHERE spcname = '{0}'",
|
||||
'ORDER BY spcname',
|
||||
])).format(name)
|
||||
elif object_type == 'language':
|
||||
query = (' '.join([
|
||||
'SELECT lanacl AS name',
|
||||
'FROM pg_catalog.pg_language',
|
||||
"WHERE lanname = '{0}'",
|
||||
'ORDER BY lanname',
|
||||
])).format(name)
|
||||
elif object_type == 'database':
|
||||
query = (' '.join([
|
||||
'SELECT datacl AS name',
|
||||
'FROM pg_catalog.pg_database',
|
||||
"WHERE datname = '{0}'",
|
||||
'ORDER BY datname',
|
||||
])).format(name)
|
||||
elif object_type == 'group':
|
||||
query = (' '.join([
|
||||
'SELECT rolname, admin_option',
|
||||
'FROM pg_catalog.pg_auth_members m',
|
||||
'JOIN pg_catalog.pg_roles r',
|
||||
'ON m.member=r.oid',
|
||||
'WHERE m.roleid IN',
|
||||
'(SELECT oid',
|
||||
'FROM pg_catalog.pg_roles',
|
||||
"WHERE rolname='{0}')",
|
||||
'ORDER BY rolname',
|
||||
])).format(name)
|
||||
|
||||
return query
|
||||
|
||||
|
||||
def _get_object_owner(name,
|
||||
object_type,
|
||||
prepend='public',
|
||||
maintenance_db=None,
|
||||
user=None,
|
||||
host=None,
|
||||
port=None,
|
||||
password=None,
|
||||
runas=None):
|
||||
'''
|
||||
Return the owner of a postgres object
|
||||
'''
|
||||
if object_type == 'table':
|
||||
query = (' '.join([
|
||||
'SELECT tableowner AS name',
|
||||
'FROM pg_tables',
|
||||
"WHERE schemaname = '{0}'",
|
||||
"AND tablename = '{1}'"
|
||||
])).format(prepend, name)
|
||||
elif object_type == 'sequence':
|
||||
query = (' '.join([
|
||||
'SELECT rolname AS name',
|
||||
'FROM pg_catalog.pg_class c',
|
||||
'JOIN pg_roles r',
|
||||
'ON c.relowner = r.oid',
|
||||
'JOIN pg_catalog.pg_namespace n',
|
||||
'ON n.oid = c.relnamespace',
|
||||
"WHERE relkind='S'",
|
||||
"AND nspname='{0}'",
|
||||
"AND relname = '{1}'",
|
||||
])).format(prepend, name)
|
||||
elif object_type == 'schema':
|
||||
query = (' '.join([
|
||||
'SELECT rolname AS name',
|
||||
'FROM pg_namespace n',
|
||||
'JOIN pg_roles r',
|
||||
'ON n.nspowner = r.oid',
|
||||
"WHERE nspname = '{0}'",
|
||||
])).format(name)
|
||||
elif object_type == 'tablespace':
|
||||
query = (' '.join([
|
||||
'SELECT rolname AS name',
|
||||
'FROM pg_tablespace t',
|
||||
'JOIN pg_roles r',
|
||||
'ON t.spcowner = r.oid',
|
||||
"WHERE spcname = '{0}'",
|
||||
])).format(name)
|
||||
elif object_type == 'language':
|
||||
query = (' '.join([
|
||||
'SELECT rolname AS name',
|
||||
'FROM pg_language l',
|
||||
'JOIN pg_roles r',
|
||||
'ON l.lanowner = r.oid',
|
||||
"WHERE lanname = '{0}'",
|
||||
])).format(name)
|
||||
elif object_type == 'database':
|
||||
query = (' '.join([
|
||||
'SELECT rolname AS name',
|
||||
'FROM pg_database d',
|
||||
'JOIN pg_roles r',
|
||||
'ON d.datdba = r.oid',
|
||||
"WHERE datname = '{0}'",
|
||||
])).format(name)
|
||||
|
||||
rows = psql_query(
|
||||
query,
|
||||
runas=runas,
|
||||
host=host,
|
||||
user=user,
|
||||
port=port,
|
||||
maintenance_db=maintenance_db,
|
||||
password=password)
|
||||
try:
|
||||
ret = rows[0]['name']
|
||||
except IndexError:
|
||||
ret = None
|
||||
|
||||
return ret
|
||||
|
||||
|
||||
def _validate_privileges(object_type, privs, privileges):
|
||||
'''
|
||||
Validate the supplied privileges
|
||||
'''
|
||||
if object_type != 'group':
|
||||
_perms = [_PRIVILEGES_MAP[perm]
|
||||
for perm in _PRIVILEGE_TYPE_MAP[object_type]]
|
||||
_perms.append('ALL')
|
||||
|
||||
if object_type not in _PRIVILEGES_OBJECTS:
|
||||
raise SaltInvocationError(
|
||||
'Invalid object_type: {0} provided'.format(object_type))
|
||||
|
||||
if not set(privs).issubset(set(_perms)):
|
||||
raise SaltInvocationError(
|
||||
'Invalid privilege(s): {0} provided for object {1}'.format(
|
||||
privileges, object_type))
|
||||
else:
|
||||
if privileges:
|
||||
raise SaltInvocationError(
|
||||
'The privileges option should not '
|
||||
'be set for object_type group')
|
||||
|
||||
|
||||
def _mod_priv_opts(object_type, privileges):
|
||||
'''
|
||||
Format options
|
||||
'''
|
||||
object_type = object_type.lower()
|
||||
privileges = '' if privileges is None else privileges
|
||||
_privs = re.split(r'\s?,\s?', privileges.upper())
|
||||
|
||||
return object_type, privileges, _privs
|
||||
|
||||
|
||||
def _process_priv_part(perms):
|
||||
'''
|
||||
Process part
|
||||
'''
|
||||
_tmp = {}
|
||||
previous = None
|
||||
for perm in perms:
|
||||
if previous is None:
|
||||
_tmp[_PRIVILEGES_MAP[perm]] = False
|
||||
previous = _PRIVILEGES_MAP[perm]
|
||||
else:
|
||||
if perm == '*':
|
||||
_tmp[previous] = True
|
||||
else:
|
||||
_tmp[_PRIVILEGES_MAP[perm]] = False
|
||||
previous = _PRIVILEGES_MAP[perm]
|
||||
return _tmp
|
||||
|
||||
|
||||
def privileges_list(
|
||||
name,
|
||||
object_type,
|
||||
prepend='public',
|
||||
maintenance_db=None,
|
||||
user=None,
|
||||
host=None,
|
||||
port=None,
|
||||
password=None,
|
||||
runas=None):
|
||||
'''
|
||||
.. versionadded:: Boron
|
||||
|
||||
Return a list of privileges for the specified object.
|
||||
|
||||
CLI Example:
|
||||
.. code-block:: bash
|
||||
salt '*' postgres.privileges_list table_name table maintenance_db=db_name
|
||||
|
||||
name
|
||||
Name of the object for which the permissions should be returned
|
||||
|
||||
object_type
|
||||
The object type, which can be one of the following:
|
||||
|
||||
- table
|
||||
- sequence
|
||||
- schema
|
||||
- tablespace
|
||||
- language
|
||||
- database
|
||||
- group
|
||||
|
||||
prepend
|
||||
Table and Sequence object types live under a schema so this should be
|
||||
provided if the object is not under the default `public` schema
|
||||
|
||||
maintenance_db
|
||||
The database to connect to
|
||||
|
||||
user
|
||||
database username if different from config or default
|
||||
|
||||
password
|
||||
user password if any password for a specified user
|
||||
|
||||
host
|
||||
Database host if different from config or default
|
||||
|
||||
port
|
||||
Database port if different from config or default
|
||||
|
||||
runas
|
||||
System user all operations should be performed on behalf of
|
||||
'''
|
||||
object_type = object_type.lower()
|
||||
query = _make_privileges_list_query(name, object_type, prepend)
|
||||
|
||||
if object_type not in _PRIVILEGES_OBJECTS:
|
||||
raise SaltInvocationError(
|
||||
'Invalid object_type: {0} provided'.format(object_type))
|
||||
|
||||
rows = psql_query(
|
||||
query,
|
||||
runas=runas,
|
||||
host=host,
|
||||
user=user,
|
||||
port=port,
|
||||
maintenance_db=maintenance_db,
|
||||
password=password)
|
||||
|
||||
ret = {}
|
||||
|
||||
for row in rows:
|
||||
if object_type != 'group':
|
||||
result = row['name']
|
||||
result = result.strip('{}')
|
||||
parts = result.split(',')
|
||||
for part in parts:
|
||||
perms_part, _ = part.split('/')
|
||||
rolename, perms = perms_part.split('=')
|
||||
if rolename == '':
|
||||
rolename = 'public'
|
||||
_tmp = _process_priv_part(perms)
|
||||
ret[rolename] = _tmp
|
||||
else:
|
||||
if row['admin_option'] == 't':
|
||||
admin_option = True
|
||||
else:
|
||||
admin_option = False
|
||||
|
||||
ret[row['rolname']] = admin_option
|
||||
|
||||
return ret
|
||||
|
||||
|
||||
def has_privileges(name,
|
||||
object_name,
|
||||
object_type,
|
||||
privileges=None,
|
||||
grant_option=None,
|
||||
prepend='public',
|
||||
maintenance_db=None,
|
||||
user=None,
|
||||
host=None,
|
||||
port=None,
|
||||
password=None,
|
||||
runas=None):
|
||||
'''
|
||||
.. versionadded:: Boron
|
||||
|
||||
Check if a role has the specified privileges on an object
|
||||
|
||||
CLI Example:
|
||||
.. code-block:: bash
|
||||
salt '*' postgres.has_privileges user_name table_name table \
|
||||
SELECT,INSERT maintenance_db=db_name
|
||||
|
||||
name
|
||||
Name of the role whose privilages should be checked on object_type
|
||||
|
||||
object_name
|
||||
Name of the object on which the check is to be performed
|
||||
|
||||
object_type
|
||||
The object type, which can be one of the following:
|
||||
|
||||
- table
|
||||
- sequence
|
||||
- schema
|
||||
- tablespace
|
||||
- language
|
||||
- database
|
||||
- group
|
||||
|
||||
privileges
|
||||
Comma separated list of privilages to check, from the list below:
|
||||
|
||||
- INSERT
|
||||
- CREATE
|
||||
- TRUNCATE
|
||||
- CONNECT
|
||||
- TRIGGER
|
||||
- SELECT
|
||||
- USAGE
|
||||
- TEMPORARY
|
||||
- UPDATE
|
||||
- EXECUTE
|
||||
- REFERENCES
|
||||
- DELETE
|
||||
- ALL
|
||||
|
||||
grant_option
|
||||
If grant_option is set to True, the grant option check is performed
|
||||
|
||||
prepend
|
||||
Table and Sequence object types live under a schema so this should be
|
||||
provided if the object is not under the default `public` schema
|
||||
|
||||
maintenance_db
|
||||
The database to connect to
|
||||
|
||||
user
|
||||
database username if different from config or default
|
||||
|
||||
password
|
||||
user password if any password for a specified user
|
||||
|
||||
host
|
||||
Database host if different from config or default
|
||||
|
||||
port
|
||||
Database port if different from config or default
|
||||
|
||||
runas
|
||||
System user all operations should be performed on behalf of
|
||||
'''
|
||||
object_type, privileges, _privs = _mod_priv_opts(object_type, privileges)
|
||||
|
||||
_validate_privileges(object_type, _privs, privileges)
|
||||
|
||||
if object_type != 'group':
|
||||
owner = _get_object_owner(object_name, object_type, prepend=prepend,
|
||||
maintenance_db=maintenance_db, user=user, host=host, port=port,
|
||||
password=password, runas=runas)
|
||||
if owner is not None and name == owner:
|
||||
return True
|
||||
|
||||
_privileges = privileges_list(object_name, object_type, prepend=prepend,
|
||||
maintenance_db=maintenance_db, user=user, host=host, port=port,
|
||||
password=password, runas=runas)
|
||||
|
||||
if name in _privileges:
|
||||
if object_type == 'group':
|
||||
if grant_option:
|
||||
retval = _privileges[name]
|
||||
else:
|
||||
retval = True
|
||||
return retval
|
||||
else:
|
||||
_perms = _PRIVILEGE_TYPE_MAP[object_type]
|
||||
if grant_option:
|
||||
perms = dict((_PRIVILEGES_MAP[perm], True) for perm in _perms)
|
||||
retval = perms == _privileges[name]
|
||||
else:
|
||||
perms = [_PRIVILEGES_MAP[perm] for perm in _perms]
|
||||
if 'ALL' in _privs:
|
||||
retval = perms.sort() == _privileges[name].keys().sort()
|
||||
else:
|
||||
retval = set(_privs).issubset(
|
||||
set(_privileges[name].keys()))
|
||||
return retval
|
||||
|
||||
return False
|
||||
|
||||
|
||||
def privileges_grant(name,
|
||||
object_name,
|
||||
object_type,
|
||||
privileges=None,
|
||||
grant_option=None,
|
||||
prepend='public',
|
||||
maintenance_db=None,
|
||||
user=None,
|
||||
host=None,
|
||||
port=None,
|
||||
password=None,
|
||||
runas=None):
|
||||
'''
|
||||
.. versionadded:: Boron
|
||||
|
||||
Grant privileges on a postgres object
|
||||
|
||||
CLI Example:
|
||||
.. code-block:: bash
|
||||
salt '*' postgres.privileges_grant user_name table_name table \
|
||||
SELECT,UPDATE maintenance_db=db_name
|
||||
|
||||
name
|
||||
Name of the role to which privilages should be granted
|
||||
|
||||
object_name
|
||||
Name of the object on which the grant is to be performed
|
||||
|
||||
object_type
|
||||
The object type, which can be one of the following:
|
||||
|
||||
- table
|
||||
- sequence
|
||||
- schema
|
||||
- tablespace
|
||||
- language
|
||||
- database
|
||||
- group
|
||||
|
||||
privileges
|
||||
Comma separated list of privilages to grant, from the list below:
|
||||
|
||||
- INSERT
|
||||
- CREATE
|
||||
- TRUNCATE
|
||||
- CONNECT
|
||||
- TRIGGER
|
||||
- SELECT
|
||||
- USAGE
|
||||
- TEMPORARY
|
||||
- UPDATE
|
||||
- EXECUTE
|
||||
- REFERENCES
|
||||
- DELETE
|
||||
- ALL
|
||||
|
||||
grant_option
|
||||
If grant_option is set to True, the recipient of the privilege can
|
||||
in turn grant it to others
|
||||
|
||||
prepend
|
||||
Table and Sequence object types live under a schema so this should be
|
||||
provided if the object is not under the default `public` schema
|
||||
|
||||
maintenance_db
|
||||
The database to connect to
|
||||
|
||||
user
|
||||
database username if different from config or default
|
||||
|
||||
password
|
||||
user password if any password for a specified user
|
||||
|
||||
host
|
||||
Database host if different from config or default
|
||||
|
||||
port
|
||||
Database port if different from config or default
|
||||
|
||||
runas
|
||||
System user all operations should be performed on behalf of
|
||||
'''
|
||||
object_type, privileges, _privs = _mod_priv_opts(object_type, privileges)
|
||||
|
||||
_validate_privileges(object_type, _privs, privileges)
|
||||
|
||||
if has_privileges(name, object_name, object_type, privileges,
|
||||
prepend=prepend, maintenance_db=maintenance_db, user=user,
|
||||
host=host, port=port, password=password, runas=runas):
|
||||
log.info('The object: %s of type: %s already has privileges: %s set',
|
||||
object_name, object_type, privileges)
|
||||
return False
|
||||
|
||||
_grants = ','.join(_privs)
|
||||
|
||||
if object_type in ['table', 'sequence']:
|
||||
on_part = '{0}.{1}'.format(prepend, object_name)
|
||||
else:
|
||||
on_part = object_name
|
||||
|
||||
if grant_option:
|
||||
if object_type == 'group':
|
||||
query = 'GRANT {0} TO {1} WITH ADMIN OPTION'.format(
|
||||
object_name, name)
|
||||
else:
|
||||
query = 'GRANT {0} ON {1} {2} TO {3} WITH GRANT OPTION'.format(
|
||||
_grants, object_type.upper(), on_part, name)
|
||||
else:
|
||||
if object_type == 'group':
|
||||
query = 'GRANT {0} TO {1}'.format(object_name, name)
|
||||
else:
|
||||
query = 'GRANT {0} ON {1} {2} TO {3}'.format(
|
||||
_grants, object_type.upper(), on_part, name)
|
||||
|
||||
ret = _psql_prepare_and_run(['-c', query],
|
||||
user=user,
|
||||
host=host,
|
||||
port=port,
|
||||
maintenance_db=maintenance_db,
|
||||
password=password,
|
||||
runas=runas)
|
||||
|
||||
return ret['retcode'] == 0
|
||||
|
||||
|
||||
def privileges_revoke(name,
|
||||
object_name,
|
||||
object_type,
|
||||
privileges=None,
|
||||
prepend='public',
|
||||
maintenance_db=None,
|
||||
user=None,
|
||||
host=None,
|
||||
port=None,
|
||||
password=None,
|
||||
runas=None):
|
||||
'''
|
||||
.. versionadded:: Boron
|
||||
|
||||
Revoke privileges on a postgres object
|
||||
|
||||
CLI Example:
|
||||
.. code-block:: bash
|
||||
salt '*' postgres.privileges_revoke user_name table_name table \
|
||||
SELECT,UPDATE maintenance_db=db_name
|
||||
|
||||
name
|
||||
Name of the role whose privilages should be revoked
|
||||
|
||||
object_name
|
||||
Name of the object on which the revoke is to be performed
|
||||
|
||||
object_type
|
||||
The object type, which can be one of the following:
|
||||
|
||||
- table
|
||||
- sequence
|
||||
- schema
|
||||
- tablespace
|
||||
- language
|
||||
- database
|
||||
- group
|
||||
|
||||
privileges
|
||||
Comma separated list of privilages to revoke, from the list below:
|
||||
|
||||
- INSERT
|
||||
- CREATE
|
||||
- TRUNCATE
|
||||
- CONNECT
|
||||
- TRIGGER
|
||||
- SELECT
|
||||
- USAGE
|
||||
- TEMPORARY
|
||||
- UPDATE
|
||||
- EXECUTE
|
||||
- REFERENCES
|
||||
- DELETE
|
||||
- ALL
|
||||
|
||||
maintenance_db
|
||||
The database to connect to
|
||||
|
||||
user
|
||||
database username if different from config or default
|
||||
|
||||
password
|
||||
user password if any password for a specified user
|
||||
|
||||
host
|
||||
Database host if different from config or default
|
||||
|
||||
port
|
||||
Database port if different from config or default
|
||||
|
||||
runas
|
||||
System user all operations should be performed on behalf of
|
||||
'''
|
||||
object_type, privileges, _privs = _mod_priv_opts(object_type, privileges)
|
||||
|
||||
_validate_privileges(object_type, _privs, privileges)
|
||||
|
||||
if not has_privileges(name, object_name, object_type, privileges,
|
||||
prepend=prepend, maintenance_db=maintenance_db, user=user,
|
||||
host=host, port=port, password=password, runas=runas):
|
||||
log.info('The object: %s of type: %s does not'
|
||||
' have privileges: %s set', object_name, object_type, privileges)
|
||||
return False
|
||||
|
||||
_grants = ','.join(_privs)
|
||||
|
||||
if object_type in ['table', 'sequence']:
|
||||
on_part = '{0}.{1}'.format(prepend, object_name)
|
||||
else:
|
||||
on_part = object_name
|
||||
|
||||
if object_type == 'group':
|
||||
query = 'REVOKE {0} FROM {1}'.format(object_name, name)
|
||||
else:
|
||||
query = 'REVOKE {0} ON {1} {2} FROM {3}'.format(
|
||||
_grants, object_type.upper(), on_part, name)
|
||||
|
||||
ret = _psql_prepare_and_run(['-c', query],
|
||||
user=user,
|
||||
host=host,
|
||||
port=port,
|
||||
maintenance_db=maintenance_db,
|
||||
password=password,
|
||||
runas=runas)
|
||||
|
||||
return ret['retcode'] == 0
|
||||
|
307
salt/states/postgres_privileges.py
Normal file
307
salt/states/postgres_privileges.py
Normal file
@ -0,0 +1,307 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
'''
|
||||
Management of PostgreSQL Privileges
|
||||
===================================
|
||||
|
||||
The postgres_privileges module is used to manage Postgres privileges.
|
||||
Privileges can be set as either absent or present.
|
||||
|
||||
Privileges can be set on the following database object types:
|
||||
|
||||
* database
|
||||
* schema
|
||||
* tablespace
|
||||
* table
|
||||
* sequence
|
||||
* language
|
||||
* group
|
||||
|
||||
Setting the grant option is supported as well.
|
||||
|
||||
.. versionadded:: Boron
|
||||
|
||||
.. code-block:: yaml
|
||||
baruwa:
|
||||
postgres_privileges.present:
|
||||
- object_name: awl
|
||||
- object_type: table
|
||||
- privileges:
|
||||
- SELECT
|
||||
- INSERT
|
||||
- DELETE
|
||||
- grant_option: False
|
||||
- prepend: public
|
||||
- maintenance_db: testdb
|
||||
|
||||
.. code-block:: yaml
|
||||
andrew:
|
||||
postgres_privileges.present:
|
||||
- object_name: admins
|
||||
- object_type: group
|
||||
- grant_option: False
|
||||
- maintenance_db: testdb
|
||||
|
||||
.. code-block:: yaml
|
||||
baruwa:
|
||||
postgres_privileges.absent:
|
||||
- object_name: awl
|
||||
- object_type: table
|
||||
- privileges:
|
||||
- SELECT
|
||||
- INSERT
|
||||
- DELETE
|
||||
- prepend: public
|
||||
- maintenance_db: testdb
|
||||
|
||||
.. code-block:: yaml
|
||||
andrew:
|
||||
postgres_privileges.absent:
|
||||
- object_name: admins
|
||||
- object_type: group
|
||||
- maintenance_db: testdb
|
||||
'''
|
||||
from __future__ import absolute_import
|
||||
|
||||
|
||||
def __virtual__():
|
||||
'''
|
||||
Only load if the postgres module is present
|
||||
'''
|
||||
return 'postgres.privileges_grant' in __salt__
|
||||
|
||||
|
||||
def present(name,
|
||||
object_name,
|
||||
object_type,
|
||||
privileges=None,
|
||||
grant_option=None,
|
||||
prepend=None,
|
||||
maintenance_db=None,
|
||||
user=None,
|
||||
db_password=None,
|
||||
db_host=None,
|
||||
db_port=None,
|
||||
db_user=None):
|
||||
'''
|
||||
Grant the requested privilege(s) on the specified object to a role
|
||||
|
||||
name
|
||||
Name of the role to which privilages should be granted
|
||||
|
||||
object_name
|
||||
Name of the object on which the grant is to be performed
|
||||
|
||||
object_type
|
||||
The object type, which can be one of the following:
|
||||
|
||||
- table
|
||||
- sequence
|
||||
- schema
|
||||
- tablespace
|
||||
- language
|
||||
- database
|
||||
- group
|
||||
|
||||
privileges
|
||||
Comma separated list of privilages to grant, from the list below:
|
||||
|
||||
- INSERT
|
||||
- CREATE
|
||||
- TRUNCATE
|
||||
- CONNECT
|
||||
- TRIGGER
|
||||
- SELECT
|
||||
- USAGE
|
||||
- TEMPORARY
|
||||
- UPDATE
|
||||
- EXECUTE
|
||||
- REFERENCES
|
||||
- DELETE
|
||||
- ALL
|
||||
|
||||
:note: privileges should not be set when granting group membership
|
||||
|
||||
grant_option
|
||||
If grant_option is set to True, the recipient of the privilege can
|
||||
in turn grant it to others
|
||||
|
||||
prepend
|
||||
Table and Sequence object types live under a schema so this should be
|
||||
provided if the object is not under the default `public` schema
|
||||
|
||||
maintenance_db
|
||||
The name of the database in which the language is to be installed
|
||||
|
||||
user
|
||||
System user all operations should be performed on behalf of
|
||||
|
||||
db_user
|
||||
database username if different from config or default
|
||||
|
||||
db_password
|
||||
user password if any password for a specified user
|
||||
|
||||
db_host
|
||||
Database host if different from config or default
|
||||
|
||||
db_port
|
||||
Database port if different from config or default
|
||||
'''
|
||||
ret = {
|
||||
'name': name,
|
||||
'changes': {},
|
||||
'result': True,
|
||||
'comment': 'The requested privilege(s) are already set'
|
||||
}
|
||||
|
||||
privileges = ','.join(privileges) if privileges else None
|
||||
|
||||
kwargs = {
|
||||
'privileges': privileges,
|
||||
'grant_option': grant_option,
|
||||
'prepend': prepend,
|
||||
'maintenance_db': maintenance_db,
|
||||
'runas': user,
|
||||
'host': db_host,
|
||||
'user': db_user,
|
||||
'port': db_port,
|
||||
'password': db_password,
|
||||
}
|
||||
|
||||
if not __salt__['postgres.has_privileges'](
|
||||
name, object_name, object_type, **kwargs):
|
||||
_privs = object_name if object_type == 'group' else privileges
|
||||
|
||||
if __opts__['test']:
|
||||
ret['result'] = None
|
||||
ret['comment'] = ('The privilege(s): {0} are'
|
||||
' set to be granted to {1}').format(_privs, name)
|
||||
return ret
|
||||
|
||||
if __salt__['postgres.privileges_grant'](
|
||||
name, object_name, object_type, **kwargs):
|
||||
ret['comment'] = ('The privilege(s): {0} have '
|
||||
'been granted to {1}').format(_privs, name)
|
||||
ret['changes'][name] = 'Present'
|
||||
else:
|
||||
ret['comment'] = ('Failed to grant privilege(s):'
|
||||
' {0} to {1}').format(_privs, name)
|
||||
ret['result'] = False
|
||||
|
||||
return ret
|
||||
|
||||
|
||||
def absent(name,
|
||||
object_name,
|
||||
object_type,
|
||||
privileges=None,
|
||||
prepend=None,
|
||||
maintenance_db=None,
|
||||
user=None,
|
||||
db_password=None,
|
||||
db_host=None,
|
||||
db_port=None,
|
||||
db_user=None):
|
||||
'''
|
||||
Revoke the requested privilege(s) on the specificed object(s)
|
||||
|
||||
name
|
||||
Name of the role whose privilages should be revoked
|
||||
|
||||
object_name
|
||||
Name of the object on which the revoke is to be performed
|
||||
|
||||
object_type
|
||||
The object type, which can be one of the following:
|
||||
|
||||
- table
|
||||
- sequence
|
||||
- schema
|
||||
- tablespace
|
||||
- language
|
||||
- database
|
||||
- group
|
||||
|
||||
privileges
|
||||
Comma separated list of privilages to revoke, from the list below:
|
||||
|
||||
- INSERT
|
||||
- CREATE
|
||||
- TRUNCATE
|
||||
- CONNECT
|
||||
- TRIGGER
|
||||
- SELECT
|
||||
- USAGE
|
||||
- TEMPORARY
|
||||
- UPDATE
|
||||
- EXECUTE
|
||||
- REFERENCES
|
||||
- DELETE
|
||||
- ALL
|
||||
|
||||
NOTE: privileges should not be set when revoking group membership
|
||||
|
||||
prepend
|
||||
Table and Sequence object types live under a schema so this should be
|
||||
provided if the object is not under the default `public` schema
|
||||
|
||||
maintenance_db
|
||||
The name of the database in which the language is to be installed
|
||||
|
||||
user
|
||||
System user all operations should be performed on behalf of
|
||||
|
||||
db_user
|
||||
database username if different from config or default
|
||||
|
||||
db_password
|
||||
user password if any password for a specified user
|
||||
|
||||
db_host
|
||||
Database host if different from config or default
|
||||
|
||||
db_port
|
||||
Database port if different from config or default
|
||||
'''
|
||||
ret = {
|
||||
'name': name,
|
||||
'changes': {},
|
||||
'result': True,
|
||||
'comment': ('The requested privilege(s) are '
|
||||
'not set so cannot be revoked')
|
||||
}
|
||||
|
||||
privileges = ','.join(privileges) if privileges else None
|
||||
|
||||
kwargs = {
|
||||
'privileges': privileges,
|
||||
'prepend': prepend,
|
||||
'maintenance_db': maintenance_db,
|
||||
'runas': user,
|
||||
'host': db_host,
|
||||
'user': db_user,
|
||||
'port': db_port,
|
||||
'password': db_password,
|
||||
}
|
||||
|
||||
if __salt__['postgres.has_privileges'](
|
||||
name, object_name, object_type, **kwargs):
|
||||
_privs = object_name if object_type == 'group' else privileges
|
||||
|
||||
if __opts__['test']:
|
||||
ret['result'] = None
|
||||
ret['comment'] = ('The privilege(s): {0} are'
|
||||
' set to be revoked from {1}').format(_privs, name)
|
||||
return ret
|
||||
|
||||
if __salt__['postgres.privileges_revoke'](
|
||||
name, object_name, object_type, **kwargs):
|
||||
ret['comment'] = ('The privilege(s): {0} have '
|
||||
'been revoked from {1}').format(_privs, name)
|
||||
ret['changes'][name] = 'Absent'
|
||||
else:
|
||||
ret['comment'] = ('Failed to revoke privilege(s):'
|
||||
' {0} from {1}').format(_privs, name)
|
||||
ret['result'] = False
|
||||
|
||||
return ret
|
@ -41,6 +41,18 @@ test_list_language_csv = (
|
||||
'plpgsql\n'
|
||||
)
|
||||
|
||||
test_privileges_list_table_csv = (
|
||||
'name\n'
|
||||
'"{baruwatest=arwdDxt/baruwatest,bayestest=arwd/baruwatest,baruwa=a*r*w*d*D*x*t*/baruwatest}"\n'
|
||||
)
|
||||
|
||||
test_privileges_list_group_csv = (
|
||||
'rolname,admin_option\n'
|
||||
'baruwa,f\n'
|
||||
'baruwatest2,t\n'
|
||||
'baruwatest,f\n'
|
||||
)
|
||||
|
||||
|
||||
if NO_MOCK is False:
|
||||
SALT_STUB = {
|
||||
@ -989,6 +1001,400 @@ class PostgresTestCase(TestCase):
|
||||
)
|
||||
self.assertFalse(ret)
|
||||
|
||||
@patch('salt.modules.postgres._run_psql',
|
||||
Mock(return_value={'retcode': 0,
|
||||
'stdout': test_privileges_list_table_csv}))
|
||||
def test_privileges_list_table(self):
|
||||
'''
|
||||
Test privilege listing on a table
|
||||
'''
|
||||
ret = postgres.privileges_list(
|
||||
'awl',
|
||||
'table',
|
||||
maintenance_db='db_name',
|
||||
runas='user',
|
||||
host='testhost',
|
||||
port='testport',
|
||||
user='testuser',
|
||||
password='testpassword'
|
||||
)
|
||||
expected = {
|
||||
"bayestest": {
|
||||
"INSERT": False,
|
||||
"UPDATE": False,
|
||||
"SELECT": False,
|
||||
"DELETE": False,
|
||||
},
|
||||
"baruwa": {
|
||||
"INSERT": True,
|
||||
"TRUNCATE": True,
|
||||
"UPDATE": True,
|
||||
"TRIGGER": True,
|
||||
"REFERENCES": True,
|
||||
"SELECT": True,
|
||||
"DELETE": True,
|
||||
},
|
||||
"baruwatest": {
|
||||
"INSERT": False,
|
||||
"TRUNCATE": False,
|
||||
"UPDATE": False,
|
||||
"TRIGGER": False,
|
||||
"REFERENCES": False,
|
||||
"SELECT": False,
|
||||
"DELETE": False,
|
||||
},
|
||||
}
|
||||
|
||||
self.assertDictEqual(ret, expected)
|
||||
|
||||
query = ("COPY (SELECT relacl AS name FROM pg_catalog.pg_class c "
|
||||
"JOIN pg_catalog.pg_namespace n ON n.oid = c.relnamespace "
|
||||
"WHERE nspname = 'public' AND relname = 'awl' AND relkind = 'r' "
|
||||
"ORDER BY relname) TO STDOUT WITH CSV HEADER")
|
||||
|
||||
postgres._run_psql.assert_called_once_with(
|
||||
['/usr/bin/pgsql', '--no-align', '--no-readline',
|
||||
'--no-password', '--username', 'testuser', '--host',
|
||||
'testhost', '--port', 'testport', '--dbname', 'db_name',
|
||||
'-v', 'datestyle=ISO,MDY', '-c', query],
|
||||
host='testhost', port='testport',
|
||||
password='testpassword', user='testuser', runas='user')
|
||||
|
||||
@patch('salt.modules.postgres._run_psql',
|
||||
Mock(return_value={'retcode': 0,
|
||||
'stdout': test_privileges_list_group_csv}))
|
||||
def test_privileges_list_group(self):
|
||||
'''
|
||||
Test privilege listing on a group
|
||||
'''
|
||||
ret = postgres.privileges_list(
|
||||
'admin',
|
||||
'group',
|
||||
maintenance_db='db_name',
|
||||
runas='user',
|
||||
host='testhost',
|
||||
port='testport',
|
||||
user='testuser',
|
||||
password='testpassword'
|
||||
)
|
||||
expected = {
|
||||
'baruwa': False,
|
||||
'baruwatest': False,
|
||||
'baruwatest2': True,
|
||||
}
|
||||
|
||||
self.assertDictEqual(ret, expected)
|
||||
|
||||
query = ("COPY (SELECT rolname, admin_option "
|
||||
"FROM pg_catalog.pg_auth_members m JOIN pg_catalog.pg_roles r "
|
||||
"ON m.member=r.oid WHERE m.roleid IN (SELECT oid FROM "
|
||||
"pg_catalog.pg_roles WHERE rolname='admin') ORDER BY rolname) "
|
||||
"TO STDOUT WITH CSV HEADER")
|
||||
|
||||
postgres._run_psql.assert_called_once_with(
|
||||
['/usr/bin/pgsql', '--no-align', '--no-readline',
|
||||
'--no-password', '--username', 'testuser', '--host',
|
||||
'testhost', '--port', 'testport', '--dbname', 'db_name',
|
||||
'-v', 'datestyle=ISO,MDY', '-c', query],
|
||||
host='testhost', port='testport',
|
||||
password='testpassword', user='testuser', runas='user')
|
||||
|
||||
@patch('salt.modules.postgres._run_psql',
|
||||
Mock(return_value={'retcode': 0,
|
||||
'stdout': test_privileges_list_table_csv}))
|
||||
def test_has_privileges_on_table(self):
|
||||
'''
|
||||
Test privilege checks on table
|
||||
'''
|
||||
ret = postgres.has_privileges(
|
||||
'baruwa',
|
||||
'awl',
|
||||
'table',
|
||||
'SELECT,INSERT',
|
||||
grant_option=True,
|
||||
maintenance_db='db_name',
|
||||
runas='user',
|
||||
host='testhost',
|
||||
port='testport',
|
||||
user='testuser',
|
||||
password='testpassword'
|
||||
)
|
||||
|
||||
self.assertTrue(ret)
|
||||
|
||||
ret = postgres.has_privileges(
|
||||
'baruwa',
|
||||
'awl',
|
||||
'table',
|
||||
'ALL',
|
||||
grant_option=True,
|
||||
maintenance_db='db_name',
|
||||
runas='user',
|
||||
host='testhost',
|
||||
port='testport',
|
||||
user='testuser',
|
||||
password='testpassword'
|
||||
)
|
||||
|
||||
self.assertTrue(ret)
|
||||
|
||||
ret = postgres.has_privileges(
|
||||
'bayestest',
|
||||
'awl',
|
||||
'table',
|
||||
'SELECT,INSERT,TRUNCATE',
|
||||
maintenance_db='db_name',
|
||||
runas='user',
|
||||
host='testhost',
|
||||
port='testport',
|
||||
user='testuser',
|
||||
password='testpassword'
|
||||
)
|
||||
|
||||
self.assertFalse(ret)
|
||||
|
||||
ret = postgres.has_privileges(
|
||||
'bayestest',
|
||||
'awl',
|
||||
'table',
|
||||
'SELECT,INSERT',
|
||||
maintenance_db='db_name',
|
||||
runas='user',
|
||||
host='testhost',
|
||||
port='testport',
|
||||
user='testuser',
|
||||
password='testpassword'
|
||||
)
|
||||
|
||||
self.assertTrue(ret)
|
||||
|
||||
@patch('salt.modules.postgres._run_psql',
|
||||
Mock(return_value={'retcode': 0,
|
||||
'stdout': test_privileges_list_group_csv}))
|
||||
def test_has_privileges_on_group(self):
|
||||
'''
|
||||
Test privilege checks on group
|
||||
'''
|
||||
ret = postgres.has_privileges(
|
||||
'baruwa',
|
||||
'admin',
|
||||
'group',
|
||||
maintenance_db='db_name',
|
||||
runas='user',
|
||||
host='testhost',
|
||||
port='testport',
|
||||
user='testuser',
|
||||
password='testpassword'
|
||||
)
|
||||
|
||||
self.assertTrue(ret)
|
||||
|
||||
ret = postgres.has_privileges(
|
||||
'baruwa',
|
||||
'admin',
|
||||
'group',
|
||||
grant_option=True,
|
||||
maintenance_db='db_name',
|
||||
runas='user',
|
||||
host='testhost',
|
||||
port='testport',
|
||||
user='testuser',
|
||||
password='testpassword'
|
||||
)
|
||||
|
||||
self.assertFalse(ret)
|
||||
|
||||
ret = postgres.has_privileges(
|
||||
'tony',
|
||||
'admin',
|
||||
'group',
|
||||
maintenance_db='db_name',
|
||||
runas='user',
|
||||
host='testhost',
|
||||
port='testport',
|
||||
user='testuser',
|
||||
password='testpassword'
|
||||
)
|
||||
|
||||
self.assertFalse(ret)
|
||||
|
||||
def test_privileges_grant_table(self):
|
||||
'''
|
||||
Test granting privileges on table
|
||||
'''
|
||||
with patch('salt.modules.postgres._run_psql',
|
||||
Mock(return_value={'retcode': 0})):
|
||||
with patch('salt.modules.postgres.has_privileges',
|
||||
Mock(return_value=False)):
|
||||
ret = postgres.privileges_grant(
|
||||
'baruwa',
|
||||
'awl',
|
||||
'table',
|
||||
'ALL',
|
||||
grant_option=True,
|
||||
maintenance_db='db_name',
|
||||
runas='user',
|
||||
host='testhost',
|
||||
port='testport',
|
||||
user='testuser',
|
||||
password='testpassword'
|
||||
)
|
||||
|
||||
query = 'GRANT ALL ON TABLE public.awl TO baruwa WITH GRANT OPTION'
|
||||
|
||||
postgres._run_psql.assert_called_once_with(
|
||||
['/usr/bin/pgsql', '--no-align', '--no-readline',
|
||||
'--no-password', '--username', 'testuser', '--host',
|
||||
'testhost', '--port', 'testport', '--dbname', 'db_name',
|
||||
'-c', query],
|
||||
host='testhost', port='testport',
|
||||
password='testpassword', user='testuser', runas='user')
|
||||
|
||||
with patch('salt.modules.postgres._run_psql',
|
||||
Mock(return_value={'retcode': 0})):
|
||||
with patch('salt.modules.postgres.has_privileges',
|
||||
Mock(return_value=False)):
|
||||
ret = postgres.privileges_grant(
|
||||
'baruwa',
|
||||
'awl',
|
||||
'table',
|
||||
'ALL',
|
||||
maintenance_db='db_name',
|
||||
runas='user',
|
||||
host='testhost',
|
||||
port='testport',
|
||||
user='testuser',
|
||||
password='testpassword'
|
||||
)
|
||||
|
||||
query = 'GRANT ALL ON TABLE public.awl TO baruwa'
|
||||
|
||||
postgres._run_psql.assert_called_once_with(
|
||||
['/usr/bin/pgsql', '--no-align', '--no-readline',
|
||||
'--no-password', '--username', 'testuser', '--host',
|
||||
'testhost', '--port', 'testport', '--dbname', 'db_name',
|
||||
'-c', query],
|
||||
host='testhost', port='testport',
|
||||
password='testpassword', user='testuser', runas='user')
|
||||
|
||||
def test_privileges_grant_group(self):
|
||||
'''
|
||||
Test granting privileges on group
|
||||
'''
|
||||
with patch('salt.modules.postgres._run_psql',
|
||||
Mock(return_value={'retcode': 0})):
|
||||
with patch('salt.modules.postgres.has_privileges',
|
||||
Mock(return_value=False)):
|
||||
ret = postgres.privileges_grant(
|
||||
'baruwa',
|
||||
'admins',
|
||||
'group',
|
||||
grant_option=True,
|
||||
maintenance_db='db_name',
|
||||
runas='user',
|
||||
host='testhost',
|
||||
port='testport',
|
||||
user='testuser',
|
||||
password='testpassword'
|
||||
)
|
||||
|
||||
query = 'GRANT admins TO baruwa WITH ADMIN OPTION'
|
||||
|
||||
postgres._run_psql.assert_called_once_with(
|
||||
['/usr/bin/pgsql', '--no-align', '--no-readline',
|
||||
'--no-password', '--username', 'testuser', '--host',
|
||||
'testhost', '--port', 'testport', '--dbname', 'db_name',
|
||||
'-c', query],
|
||||
host='testhost', port='testport',
|
||||
password='testpassword', user='testuser', runas='user')
|
||||
|
||||
with patch('salt.modules.postgres._run_psql',
|
||||
Mock(return_value={'retcode': 0})):
|
||||
with patch('salt.modules.postgres.has_privileges',
|
||||
Mock(return_value=False)):
|
||||
ret = postgres.privileges_grant(
|
||||
'baruwa',
|
||||
'admins',
|
||||
'group',
|
||||
maintenance_db='db_name',
|
||||
runas='user',
|
||||
host='testhost',
|
||||
port='testport',
|
||||
user='testuser',
|
||||
password='testpassword'
|
||||
)
|
||||
|
||||
query = 'GRANT admins TO baruwa'
|
||||
|
||||
postgres._run_psql.assert_called_once_with(
|
||||
['/usr/bin/pgsql', '--no-align', '--no-readline',
|
||||
'--no-password', '--username', 'testuser', '--host',
|
||||
'testhost', '--port', 'testport', '--dbname', 'db_name',
|
||||
'-c', query],
|
||||
host='testhost', port='testport',
|
||||
password='testpassword', user='testuser', runas='user')
|
||||
|
||||
def test_privileges_revoke_table(self):
|
||||
'''
|
||||
Test revoking privileges on table
|
||||
'''
|
||||
with patch('salt.modules.postgres._run_psql',
|
||||
Mock(return_value={'retcode': 0})):
|
||||
with patch('salt.modules.postgres.has_privileges',
|
||||
Mock(return_value=True)):
|
||||
ret = postgres.privileges_revoke(
|
||||
'baruwa',
|
||||
'awl',
|
||||
'table',
|
||||
'ALL',
|
||||
maintenance_db='db_name',
|
||||
runas='user',
|
||||
host='testhost',
|
||||
port='testport',
|
||||
user='testuser',
|
||||
password='testpassword'
|
||||
)
|
||||
|
||||
query = 'REVOKE ALL ON TABLE public.awl FROM baruwa'
|
||||
|
||||
postgres._run_psql.assert_called_once_with(
|
||||
['/usr/bin/pgsql', '--no-align', '--no-readline',
|
||||
'--no-password', '--username', 'testuser', '--host',
|
||||
'testhost', '--port', 'testport', '--dbname', 'db_name',
|
||||
'-c', query],
|
||||
host='testhost', port='testport',
|
||||
password='testpassword', user='testuser', runas='user')
|
||||
|
||||
def test_privileges_revoke_group(self):
|
||||
'''
|
||||
Test revoking privileges on group
|
||||
'''
|
||||
with patch('salt.modules.postgres._run_psql',
|
||||
Mock(return_value={'retcode': 0})):
|
||||
with patch('salt.modules.postgres.has_privileges',
|
||||
Mock(return_value=True)):
|
||||
ret = postgres.privileges_revoke(
|
||||
'baruwa',
|
||||
'admins',
|
||||
'group',
|
||||
maintenance_db='db_name',
|
||||
runas='user',
|
||||
host='testhost',
|
||||
port='testport',
|
||||
user='testuser',
|
||||
password='testpassword'
|
||||
)
|
||||
|
||||
query = 'REVOKE admins FROM baruwa'
|
||||
|
||||
postgres._run_psql.assert_called_once_with(
|
||||
['/usr/bin/pgsql', '--no-align', '--no-readline',
|
||||
'--no-password', '--username', 'testuser', '--host',
|
||||
'testhost', '--port', 'testport', '--dbname', 'db_name',
|
||||
'-c', query],
|
||||
host='testhost', port='testport',
|
||||
password='testpassword', user='testuser', runas='user')
|
||||
|
||||
if __name__ == '__main__':
|
||||
from integration import run_tests
|
||||
run_tests(PostgresTestCase, needs_daemon=False)
|
||||
|
170
tests/unit/states/postgres_privileges_test.py
Normal file
170
tests/unit/states/postgres_privileges_test.py
Normal file
@ -0,0 +1,170 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
'''
|
||||
:codeauthor: :email:`Andrew Colin Kissa <andrew@topdog.za.net>`
|
||||
'''
|
||||
from __future__ import absolute_import
|
||||
|
||||
from salttesting import skipIf, TestCase
|
||||
from salttesting.mock import (
|
||||
NO_MOCK,
|
||||
NO_MOCK_REASON,
|
||||
MagicMock,
|
||||
patch
|
||||
)
|
||||
|
||||
from salttesting.helpers import ensure_in_syspath
|
||||
|
||||
ensure_in_syspath('../../')
|
||||
|
||||
from salt.states import postgres_privileges
|
||||
|
||||
|
||||
@skipIf(NO_MOCK, NO_MOCK_REASON)
|
||||
class PostgresPrivilegesTestCase(TestCase):
|
||||
'''
|
||||
Test cases for salt.states.postgres_privileges
|
||||
'''
|
||||
|
||||
def setUp(self):
|
||||
'''
|
||||
Setup data for the tests
|
||||
'''
|
||||
postgres_privileges.__opts__ = {}
|
||||
postgres_privileges.__salt__ = {}
|
||||
self.table_name = 'awl'
|
||||
self.group_name = 'admins'
|
||||
self.name = 'baruwa'
|
||||
self.ret = {'name': self.name,
|
||||
'changes': {},
|
||||
'result': False,
|
||||
'comment': ''}
|
||||
self.mock_true = MagicMock(return_value=True)
|
||||
self.mock_false = MagicMock(return_value=False)
|
||||
|
||||
def test_present_table(self):
|
||||
'''
|
||||
Test present
|
||||
'''
|
||||
with patch.dict(postgres_privileges.__salt__,
|
||||
{'postgres.has_privileges': self.mock_true}):
|
||||
comt = 'The requested privilege(s) are already set'
|
||||
self.ret.update({'comment': comt, 'result': True})
|
||||
self.assertDictEqual(
|
||||
postgres_privileges.present(
|
||||
self.name,
|
||||
self.table_name,
|
||||
'table'),
|
||||
self.ret)
|
||||
|
||||
with patch.dict(postgres_privileges.__salt__,
|
||||
{'postgres.has_privileges': self.mock_false,
|
||||
'postgres.privileges_grant': self.mock_true}):
|
||||
with patch.dict(postgres_privileges.__opts__, {'test': True}):
|
||||
comt = ('The privilege(s): {0} are'
|
||||
' set to be granted to {1}').format('ALL', self.name)
|
||||
self.ret.update({'comment': comt, 'result': None})
|
||||
self.assertDictEqual(
|
||||
postgres_privileges.present(self.name,
|
||||
self.table_name, 'table', privileges=['ALL']), self.ret)
|
||||
|
||||
with patch.dict(postgres_privileges.__opts__, {'test': False}):
|
||||
comt = ('The privilege(s): {0} have '
|
||||
'been granted to {1}').format('ALL', self.name)
|
||||
self.ret.update({'comment': comt,
|
||||
'result': True,
|
||||
'changes': {'baruwa': 'Present'}})
|
||||
self.assertDictEqual(
|
||||
postgres_privileges.present(self.name,
|
||||
self.table_name, 'table', privileges=['ALL']), self.ret)
|
||||
|
||||
def test_present_group(self):
|
||||
'''
|
||||
Test present group
|
||||
'''
|
||||
with patch.dict(postgres_privileges.__salt__,
|
||||
{'postgres.has_privileges': self.mock_false,
|
||||
'postgres.privileges_grant': self.mock_true}):
|
||||
with patch.dict(postgres_privileges.__opts__, {'test': True}):
|
||||
comt = ('The privilege(s): {0} are'
|
||||
' set to be granted to {1}').format(self.group_name,
|
||||
self.name)
|
||||
self.ret.update({'comment': comt, 'result': None})
|
||||
self.assertDictEqual(
|
||||
postgres_privileges.present(self.name,
|
||||
self.group_name, 'group'), self.ret)
|
||||
|
||||
with patch.dict(postgres_privileges.__opts__, {'test': False}):
|
||||
comt = ('The privilege(s): {0} have '
|
||||
'been granted to {1}').format(self.group_name,
|
||||
self.name)
|
||||
self.ret.update({'comment': comt,
|
||||
'result': True,
|
||||
'changes': {'baruwa': 'Present'}})
|
||||
self.assertDictEqual(
|
||||
postgres_privileges.present(self.name,
|
||||
self.group_name, 'group'), self.ret)
|
||||
|
||||
def test_absent_table(self):
|
||||
'''
|
||||
Test absent
|
||||
'''
|
||||
with patch.dict(postgres_privileges.__salt__,
|
||||
{'postgres.has_privileges': self.mock_false}):
|
||||
with patch.dict(postgres_privileges.__opts__, {'test': True}):
|
||||
comt = ('The requested privilege(s)'
|
||||
' are not set so cannot be revoked')
|
||||
self.ret.update({'comment': comt, 'result': True})
|
||||
self.assertDictEqual(
|
||||
postgres_privileges.absent(
|
||||
self.name,
|
||||
self.table_name,
|
||||
'table'),
|
||||
self.ret)
|
||||
|
||||
with patch.dict(postgres_privileges.__salt__,
|
||||
{'postgres.has_privileges': self.mock_true,
|
||||
'postgres.privileges_revoke': self.mock_true}):
|
||||
with patch.dict(postgres_privileges.__opts__, {'test': True}):
|
||||
comt = ('The privilege(s): {0} are'
|
||||
' set to be revoked from {1}').format('ALL', self.name)
|
||||
self.ret.update({'comment': comt, 'result': None})
|
||||
self.assertDictEqual(
|
||||
postgres_privileges.absent(self.name,
|
||||
self.table_name, 'table', privileges=['ALL']), self.ret)
|
||||
|
||||
with patch.dict(postgres_privileges.__opts__, {'test': False}):
|
||||
comt = ('The privilege(s): {0} have '
|
||||
'been revoked from {1}').format('ALL', self.name)
|
||||
self.ret.update({'comment': comt,
|
||||
'result': True,
|
||||
'changes': {'baruwa': 'Absent'}})
|
||||
self.assertDictEqual(
|
||||
postgres_privileges.absent(self.name,
|
||||
self.table_name, 'table', privileges=['ALL']), self.ret)
|
||||
|
||||
def test_absent_group(self):
|
||||
'''
|
||||
Test absent group
|
||||
'''
|
||||
with patch.dict(postgres_privileges.__salt__,
|
||||
{'postgres.has_privileges': self.mock_true,
|
||||
'postgres.privileges_revoke': self.mock_true}):
|
||||
with patch.dict(postgres_privileges.__opts__, {'test': True}):
|
||||
comt = ('The privilege(s): {0} are'
|
||||
' set to be revoked from {1}').format(self.group_name,
|
||||
self.name)
|
||||
self.ret.update({'comment': comt, 'result': None})
|
||||
self.assertDictEqual(
|
||||
postgres_privileges.absent(self.name,
|
||||
self.group_name, 'group'), self.ret)
|
||||
|
||||
with patch.dict(postgres_privileges.__opts__, {'test': False}):
|
||||
comt = ('The privilege(s): {0} have '
|
||||
'been revoked from {1}').format(self.group_name,
|
||||
self.name)
|
||||
self.ret.update({'comment': comt,
|
||||
'result': True,
|
||||
'changes': {'baruwa': 'Absent'}})
|
||||
self.assertDictEqual(
|
||||
postgres_privileges.absent(self.name,
|
||||
self.group_name, 'group'), self.ret)
|
Loading…
Reference in New Issue
Block a user