mirror of
https://github.com/valitydev/salt.git
synced 2024-11-07 08:58:59 +00:00
- salt/modules/postgres.py: add functions to manipulate schemas
- salt/states/postgres_schema.py: new states for schemas - tests/unit/modules/postgres_test.py: add tests on new functions - tests/unit/states/postgres_test.py: add tests on new functions
This commit is contained in:
parent
15abeac617
commit
b4dcc992c5
@ -1549,3 +1549,237 @@ def owner_to(dbname,
|
||||
password=password,
|
||||
maintenance_db=dbname)
|
||||
return cmdret
|
||||
|
||||
# Schema related actions
|
||||
|
||||
|
||||
def schema_create(dbname, name, owner=None,
|
||||
user=None,
|
||||
db_user=None, db_password=None,
|
||||
db_host=None, db_port=None):
|
||||
'''
|
||||
Creates a Postgres schema.
|
||||
|
||||
CLI Example:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
salt '*' postgres.schema_create dbname name owner='owner' \\
|
||||
user='user' \\
|
||||
db_user='user' db_password='password'
|
||||
db_host='hostname' db_port='port'
|
||||
'''
|
||||
|
||||
# check if schema exists
|
||||
if schema_exists(dbname, name,
|
||||
db_user=db_user, db_password=db_password,
|
||||
db_host=db_host, db_port=db_port):
|
||||
log.info('{0!r} already exists in {1!r}'.format(name, dbname))
|
||||
return False
|
||||
|
||||
sub_cmd = 'CREATE SCHEMA {0}'.format(name)
|
||||
if owner is not None:
|
||||
sub_cmd = '{0} AUTHORIZATION {1}'.format(sub_cmd, owner)
|
||||
|
||||
ret = _psql_prepare_and_run(['-c', sub_cmd],
|
||||
user=db_user, password=db_password,
|
||||
port=db_port, host=db_host,
|
||||
maintenance_db=dbname, runas=user)
|
||||
|
||||
return ret['retcode'] == 0
|
||||
|
||||
|
||||
def schema_remove(dbname, name,
|
||||
user=None,
|
||||
db_user=None, db_password=None,
|
||||
db_host=None, db_port=None):
|
||||
'''
|
||||
Removes a schema from the Postgres server.
|
||||
|
||||
CLI Example:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
salt '*' postgres.schema_remove dbname schemaname
|
||||
|
||||
dbname
|
||||
Database name we work on
|
||||
|
||||
schemaname
|
||||
The schema's name we'll remove
|
||||
|
||||
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
|
||||
|
||||
'''
|
||||
|
||||
# check if schema exists
|
||||
if not schema_exists(dbname, name,
|
||||
db_user=db_user, db_password=db_password,
|
||||
db_host=db_host, db_port=db_port):
|
||||
log.info('Schema {0!r} does not exist in {0!r}'.format(name, dbname))
|
||||
return False
|
||||
|
||||
# schema exists, proceed
|
||||
sub_cmd = 'DROP SCHEMA {0}'.format(name)
|
||||
_psql_prepare_and_run(
|
||||
['-c', sub_cmd],
|
||||
runas=user,
|
||||
maintenance_db=dbname,
|
||||
host=db_host, user=db_user, port=db_port, password=db_password)
|
||||
|
||||
if not schema_exists(dbname, name,
|
||||
db_user=db_user, db_password=db_password,
|
||||
db_host=db_host, db_port=db_port):
|
||||
return True
|
||||
else:
|
||||
log.info('Failed to delete schema {0!r}.'.format(name))
|
||||
return False
|
||||
|
||||
|
||||
def schema_exists(dbname, name,
|
||||
db_user=None, db_password=None,
|
||||
db_host=None, db_port=None):
|
||||
'''
|
||||
Checks if a schema exists on the Postgres server.
|
||||
|
||||
CLI Example:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
salt '*' postgres.schema_exists dbname schemaname
|
||||
|
||||
dbname
|
||||
Database name we query on
|
||||
|
||||
name
|
||||
Schema name we look for
|
||||
|
||||
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
|
||||
|
||||
'''
|
||||
return bool(
|
||||
schema_get(dbname, name,
|
||||
db_user=db_user,
|
||||
db_host=db_host,
|
||||
db_port=db_port,
|
||||
db_password=db_password))
|
||||
|
||||
|
||||
def schema_get(dbname, name,
|
||||
db_user=None, db_password=None,
|
||||
db_host=None, db_port=None):
|
||||
'''
|
||||
Return a dict with information about schemas in a database.
|
||||
|
||||
CLI Example:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
salt '*' postgres.schema_get dbname name
|
||||
|
||||
dbname
|
||||
Database name we query on
|
||||
|
||||
name
|
||||
Schema name we look for
|
||||
|
||||
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
|
||||
'''
|
||||
all_schemas = schema_list(dbname,
|
||||
db_user=db_user,
|
||||
db_host=db_host,
|
||||
db_port=db_port,
|
||||
db_password=db_password)
|
||||
try:
|
||||
return all_schemas.get(name, None)
|
||||
except AttributeError:
|
||||
log.error('Could not retrieve Postgres schema. Is Postgres running?')
|
||||
return False
|
||||
|
||||
|
||||
def schema_list(dbname,
|
||||
db_user=None, db_password=None,
|
||||
db_host=None, db_port=None):
|
||||
'''
|
||||
Return a dict with information about schemas in a Postgres database.
|
||||
|
||||
CLI Example:
|
||||
|
||||
.. code-block:: bash
|
||||
|
||||
salt '*' postgres.schema_list dbname
|
||||
|
||||
dbname
|
||||
Database name we query on
|
||||
|
||||
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 = {}
|
||||
|
||||
query = (''.join([
|
||||
'SELECT '
|
||||
'pg_namespace.nspname as "name",'
|
||||
'pg_namespace.nspacl as "acl", '
|
||||
'pg_roles.rolname as "owner" '
|
||||
'FROM pg_namespace '
|
||||
'LEFT JOIN pg_roles ON pg_roles.oid = pg_namespace.nspowner '
|
||||
]))
|
||||
|
||||
rows = psql_query(query,
|
||||
host=db_host,
|
||||
user=db_user,
|
||||
port=db_port,
|
||||
maintenance_db=dbname,
|
||||
password=db_password)
|
||||
|
||||
for row in rows:
|
||||
retrow = {}
|
||||
for key in ('owner', 'acl'):
|
||||
retrow[key] = row[key]
|
||||
ret[row['name']] = retrow
|
||||
|
||||
return ret
|
||||
|
155
salt/states/postgres_schema.py
Normal file
155
salt/states/postgres_schema.py
Normal file
@ -0,0 +1,155 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
'''
|
||||
Management of PostgreSQL schemas
|
||||
================================
|
||||
|
||||
The postgres_schemas module is used to create and manage Postgres schemas.
|
||||
|
||||
.. code-block:: yaml
|
||||
|
||||
public:
|
||||
postgres_schema.present 'dbname' 'name'
|
||||
'''
|
||||
|
||||
# Import Python libs
|
||||
|
||||
# Import salt libs
|
||||
import salt.utils
|
||||
import logging
|
||||
|
||||
# Salt imports
|
||||
from salt.modules import postgres
|
||||
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
|
||||
def __virtual__():
|
||||
'''
|
||||
Only load if the postgres module is present
|
||||
'''
|
||||
return 'postgres.schema_exists' in __salt__
|
||||
|
||||
|
||||
def present(dbname, name,
|
||||
owner=None,
|
||||
db_user=None, db_password=None,
|
||||
db_host=None, db_port=None):
|
||||
'''
|
||||
Ensure that the named schema is present in the database.
|
||||
|
||||
dbname
|
||||
The database's name will work on
|
||||
|
||||
name
|
||||
The name of the schema to manage
|
||||
|
||||
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 = {'dbname': dbname,
|
||||
'name': name,
|
||||
'changes': {},
|
||||
'result': True,
|
||||
'comment': 'Schema {0} is already present in '
|
||||
'database {1}'.format(name, dbname)}
|
||||
|
||||
db_args = {
|
||||
'db_user': db_user,
|
||||
'db_password': db_password,
|
||||
'db_host': db_host,
|
||||
'db_port': db_port
|
||||
}
|
||||
|
||||
# check if schema exists
|
||||
schema_attr = __salt__['postgres.schema_get'](dbname, name, **db_args)
|
||||
|
||||
cret = None
|
||||
|
||||
# The schema is not present, make it!
|
||||
if schema_attr is None:
|
||||
cret = __salt__['postgres.schema_create'](dbname,
|
||||
name,
|
||||
owner=owner,
|
||||
**db_args)
|
||||
else:
|
||||
msg = 'Schema {0} already exists in database {1}'
|
||||
cret = None
|
||||
|
||||
if cret:
|
||||
msg = 'Schema {0} has been created in database {1}'
|
||||
ret['result'] = True
|
||||
ret['changes'][name] = 'Present'
|
||||
elif cret is not None:
|
||||
msg = 'Failed to create schema {0} in database {1}'
|
||||
ret['result'] = False
|
||||
else:
|
||||
msg = 'Schema {0} already exists in database {1}'
|
||||
ret['result'] = True
|
||||
|
||||
ret['comment'] = msg.format(name, dbname)
|
||||
return ret
|
||||
|
||||
|
||||
def absent(dbname, name,
|
||||
db_user=None, db_password=None,
|
||||
db_host=None, db_port=None):
|
||||
'''
|
||||
Ensure that the named schema is absent
|
||||
|
||||
dbname
|
||||
The database's name will work on
|
||||
|
||||
name
|
||||
The name of the schema to remove
|
||||
|
||||
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,
|
||||
'dbname': dbname,
|
||||
'changes': {},
|
||||
'result': True,
|
||||
'comment': ''}
|
||||
|
||||
db_args = {
|
||||
'db_user': db_user,
|
||||
'db_password': db_password,
|
||||
'db_host': db_host,
|
||||
'db_port': db_port
|
||||
}
|
||||
|
||||
# check if schema exists and remove it
|
||||
if __salt__['postgres.schema_exists'](dbname, name, **db_args):
|
||||
if __salt__['postgres.schema_remove'](dbname, name, **db_args):
|
||||
ret['comment'] = 'Schema {0} has been removed' \
|
||||
' from database {1}'.format(name, dbname)
|
||||
ret['changes'][name] = 'Absent'
|
||||
return ret
|
||||
else:
|
||||
ret['result'] = False
|
||||
ret['comment'] = 'Schema {0} failed to be removed'.format(name)
|
||||
return ret
|
||||
else:
|
||||
ret['comment'] = 'Schema {0} is not present in database {1},' \
|
||||
' so it cannot be removed'.format(name, dbname)
|
||||
|
||||
return ret
|
@ -27,6 +27,13 @@ test_list_db_csv = (
|
||||
'test_db,postgres,LATIN1,en_US,en_US,,pg_default'
|
||||
)
|
||||
|
||||
test_list_schema_csv = (
|
||||
'name,owner,acl\n'
|
||||
'public,postgres,"{postgres=UC/postgres,=UC/postgres}"\n'
|
||||
'pg_toast,postgres,""'
|
||||
)
|
||||
|
||||
|
||||
if NO_MOCK is False:
|
||||
SALT_STUB = {
|
||||
'config.option': Mock(),
|
||||
@ -666,6 +673,136 @@ class PostgresTestCase(TestCase):
|
||||
'foo', 'bar', True),
|
||||
'md596948aad3fcae80c08a35c9b5958cd89')
|
||||
|
||||
@patch('salt.modules.postgres._run_psql',
|
||||
Mock(return_value={'retcode': None,
|
||||
'stdout': test_list_schema_csv}))
|
||||
def test_schema_list(self):
|
||||
ret = postgres.schema_list(
|
||||
'maint_db',
|
||||
db_user='testuser',
|
||||
db_host='testhost',
|
||||
db_port='testport',
|
||||
db_password='foo'
|
||||
)
|
||||
self.assertDictEqual(ret, {
|
||||
'public': {'acl': '{postgres=UC/postgres,=UC/postgres}',
|
||||
'owner': 'postgres'},
|
||||
'pg_toast': {'acl': '', 'owner': 'postgres'}
|
||||
})
|
||||
|
||||
@patch('salt.modules.postgres._run_psql',
|
||||
Mock(return_value={'retcode': None}))
|
||||
@patch('salt.modules.postgres.psql_query',
|
||||
Mock(return_value=[
|
||||
{
|
||||
'name': 'public',
|
||||
'acl': '{postgres=UC/postgres,=UC/postgres}',
|
||||
'owner': 'postgres'
|
||||
}]))
|
||||
def test_schema_exists(self):
|
||||
ret = postgres.schema_exists(
|
||||
'template1',
|
||||
'public'
|
||||
)
|
||||
self.assertTrue(ret)
|
||||
|
||||
@patch('salt.modules.postgres._run_psql',
|
||||
Mock(return_value={'retcode': None}))
|
||||
@patch('salt.modules.postgres.psql_query',
|
||||
Mock(return_value=[
|
||||
{
|
||||
'name': 'public',
|
||||
'acl': '{postgres=UC/postgres,=UC/postgres}',
|
||||
'owner': 'postgres'
|
||||
}]))
|
||||
def test_schema_get(self):
|
||||
ret = postgres.schema_get(
|
||||
'template1',
|
||||
'public'
|
||||
)
|
||||
self.assertTrue(ret)
|
||||
|
||||
@patch('salt.modules.postgres._run_psql',
|
||||
Mock(return_value={'retcode': None}))
|
||||
@patch('salt.modules.postgres.psql_query',
|
||||
Mock(return_value=[
|
||||
{
|
||||
'name': 'public',
|
||||
'acl': '{postgres=UC/postgres,=UC/postgres}',
|
||||
'owner': 'postgres'
|
||||
}]))
|
||||
def test_schema_get(self):
|
||||
ret = postgres.schema_get(
|
||||
'template1',
|
||||
'pg_toast'
|
||||
)
|
||||
self.assertFalse(ret)
|
||||
|
||||
@patch('salt.modules.postgres._run_psql',
|
||||
Mock(return_value={'retcode': None}))
|
||||
@patch('salt.modules.postgres.schema_exists', Mock(return_value=False))
|
||||
def test_schema_create(self):
|
||||
postgres.schema_create(
|
||||
'test_db',
|
||||
'test_schema',
|
||||
user='user',
|
||||
db_host='test_host',
|
||||
db_port='test_port',
|
||||
db_user='test_user',
|
||||
db_password='test_password'
|
||||
)
|
||||
postgres._run_psql.assert_called_once_with(
|
||||
"/usr/bin/pgsql --no-align --no-readline --no-password "
|
||||
"--username test_user "
|
||||
"--host test_host --port test_port "
|
||||
"--dbname test_db -c 'CREATE SCHEMA test_schema'",
|
||||
host='test_host', port='test_port',
|
||||
password='test_password', user='test_user', runas='user')
|
||||
|
||||
@patch('salt.modules.postgres.schema_exists', Mock(return_value=True))
|
||||
def test_schema_create2(self):
|
||||
ret = postgres.schema_create('test_db',
|
||||
'test_schema',
|
||||
user='user',
|
||||
db_host='test_host',
|
||||
db_port='test_port',
|
||||
db_user='test_user',
|
||||
db_password='test_password'
|
||||
)
|
||||
self.assertFalse(ret)
|
||||
|
||||
@patch('salt.modules.postgres._run_psql',
|
||||
Mock(return_value={'retcode': None}))
|
||||
@patch('salt.modules.postgres.schema_exists', Mock(return_value=True))
|
||||
def test_schema_remove(self):
|
||||
postgres.schema_remove(
|
||||
'test_db',
|
||||
'test_schema',
|
||||
user='user',
|
||||
db_host='test_host',
|
||||
db_port='test_port',
|
||||
db_user='test_user',
|
||||
db_password='test_password'
|
||||
)
|
||||
postgres._run_psql.assert_called_once_with(
|
||||
"/usr/bin/pgsql --no-align --no-readline --no-password "
|
||||
"--username test_user "
|
||||
"--host test_host --port test_port "
|
||||
"--dbname test_db -c 'DROP SCHEMA test_schema'",
|
||||
host='test_host', port='test_port',
|
||||
password='test_password', user='test_user', runas='user')
|
||||
|
||||
@patch('salt.modules.postgres.schema_exists', Mock(return_value=False))
|
||||
def test_schema_remove2(self):
|
||||
ret = postgres.schema_remove('test_db',
|
||||
'test_schema',
|
||||
user='user',
|
||||
db_host='test_host',
|
||||
db_port='test_port',
|
||||
db_user='test_user',
|
||||
db_password='test_password'
|
||||
)
|
||||
self.assertFalse(ret)
|
||||
|
||||
if __name__ == '__main__':
|
||||
from integration import run_tests
|
||||
|
@ -16,12 +16,14 @@ from salt.states import (
|
||||
postgres_user,
|
||||
postgres_group,
|
||||
postgres_extension,
|
||||
postgres_schema,
|
||||
)
|
||||
MODS = (
|
||||
postgres_database,
|
||||
postgres_user,
|
||||
postgres_group,
|
||||
postgres_extension,
|
||||
postgres_schema,
|
||||
)
|
||||
|
||||
|
||||
@ -483,6 +485,82 @@ class PostgresExtensionTestCase(TestCase):
|
||||
)
|
||||
|
||||
|
||||
@skipIf(NO_MOCK, NO_MOCK_REASON)
|
||||
@patch.multiple(postgres_schema,
|
||||
__grains__={'os_family': 'Linux'},
|
||||
__salt__=SALT_STUB)
|
||||
@patch('salt.utils.which', Mock(return_value='/usr/bin/pgsql'))
|
||||
class PostgresSchemaTestCase(TestCase):
|
||||
|
||||
@patch.dict(SALT_STUB, {
|
||||
'postgres.schema_get': Mock(return_value=None),
|
||||
'postgres.schema_create': MagicMock(),
|
||||
})
|
||||
def test_present_creation(self):
|
||||
ret = postgres_schema.present('dbname', 'foo')
|
||||
self.assertEqual(
|
||||
ret,
|
||||
{'comment': 'Schema foo has been created in database dbname',
|
||||
'changes': {'foo': 'Present'},
|
||||
'dbname': 'dbname',
|
||||
'name': 'foo',
|
||||
'result': True}
|
||||
)
|
||||
self.assertEqual(SALT_STUB['postgres.schema_create'].call_count, 1)
|
||||
|
||||
@patch.dict(SALT_STUB, {
|
||||
'postgres.schema_get': Mock(return_value={'foo':
|
||||
{'acl': '',
|
||||
'owner': 'postgres'}
|
||||
}),
|
||||
'postgres.schema_create': MagicMock(),
|
||||
})
|
||||
def test_present_nocreation(self):
|
||||
ret = postgres_schema.present('dbname', 'foo')
|
||||
self.assertEqual(
|
||||
ret,
|
||||
{'comment': 'Schema foo already exists in database dbname',
|
||||
'changes': {},
|
||||
'dbname': 'dbname',
|
||||
'name': 'foo',
|
||||
'result': True}
|
||||
)
|
||||
self.assertEqual(SALT_STUB['postgres.schema_create'].call_count, 0)
|
||||
|
||||
@patch.dict(SALT_STUB, {
|
||||
'postgres.schema_exists': Mock(return_value=True),
|
||||
'postgres.schema_remove': MagicMock(),
|
||||
})
|
||||
def test_absent_remove(self):
|
||||
ret = postgres_schema.absent('dbname', 'foo')
|
||||
self.assertEqual(
|
||||
ret,
|
||||
{'comment': 'Schema foo has been removed from database dbname',
|
||||
'changes': {'foo': 'Absent'},
|
||||
'dbname': 'dbname',
|
||||
'name': 'foo',
|
||||
'result': True}
|
||||
)
|
||||
self.assertEqual(SALT_STUB['postgres.schema_remove'].call_count, 1)
|
||||
|
||||
@patch.dict(SALT_STUB, {
|
||||
'postgres.schema_exists': Mock(return_value=False),
|
||||
'postgres.schema_remove': MagicMock(),
|
||||
})
|
||||
def test_absent_noremove(self):
|
||||
ret = postgres_schema.absent('dbname', 'foo')
|
||||
self.assertEqual(
|
||||
ret,
|
||||
{'comment': 'Schema foo is not present in database dbname,'
|
||||
' so it cannot be removed',
|
||||
'changes': {},
|
||||
'dbname': 'dbname',
|
||||
'name': 'foo',
|
||||
'result': True}
|
||||
)
|
||||
self.assertEqual(SALT_STUB['postgres.schema_remove'].call_count, 0)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
from integration import run_tests
|
||||
run_tests(PostgresExtensionTestCase, needs_daemon=False)
|
||||
|
Loading…
Reference in New Issue
Block a user