Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
133 changes: 133 additions & 0 deletions salt/states/postgres_cluster.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
# -*- coding: utf-8 -*-
'''
Management of PostgreSQL clusters
=================================

The postgres_cluster state module is used to manage PostgreSQL clusters.
Clusters can be set as either absent or present

.. code-block:: yaml

create cluster 9.3 main:
postgres_cluster.present:
- name: 'main'
- version: '9.3'
'''
from __future__ import absolute_import


def __virtual__():
'''
Only load if the deb_postgres module is present
'''
return 'postgres.cluster_exists' in __salt__


def present(version,
name,
port=None,
encoding=None,
locale=None,
datadir=None):
'''
Ensure that the named cluster is present with the specified properties.
For more information about all of these options see man pg_createcluster(1)

version
Version of the postgresql cluster

name
The name of the cluster

port
Cluster port

encoding
The character encoding scheme to be used in this database

locale
Locale with which to create cluster

datadir
Where the cluster is stored

.. versionadded:: 2015.XX
'''
msg = 'Cluster {0}/{1} is already present'.format(version, name)
ret = {'name': name,
'changes': {},
'result': True,
'comment': msg}

if __salt__['postgres.cluster_exists'](version, name):
# check cluster config is correct
infos = __salt__['postgres.cluster_list'](verbose=True)
info = infos['{0}/{1}'.format(version, name)]
# TODO: check locale en encoding configs also
if any((port != info['port'] if port else False,
datadir != info['datadir'] if datadir else False,)):
ret['comment'] = 'Cluster {0}/{1} has wrong parameters ' \
'which couldn\'t be changed on fly.' \
.format(version, name)
ret['result'] = False
return ret

# The cluster is not present, add it!
if __opts__.get('test'):
ret['result'] = None
msg = 'Cluster {0}/{1} is set to be created'
ret['comment'] = msg.format(version, name)
return ret
cluster = __salt__['postgres.cluster_create'](
version=version,
name=name,
port=port,
locale=locale,
encoding=encoding,
datadir=datadir)
if cluster:
msg = 'The cluster {0}/{1} has been created'
ret['comment'] = msg.format(version, name)
ret['changes']['{0}/{1}'.format(version, name)] = 'Present'
else:
msg = 'Failed to create cluster {0}/{1}'
ret['comment'] = msg.format(version, name)
ret['result'] = False
return ret


def absent(version,
name):
'''
Ensure that the named cluster is absent

version
Version of the postgresql server of the cluster to remove

name
The name of the cluster to remove

.. versionadded:: 2015.XX
'''
ret = {'name': name,
'changes': {},
'result': True,
'comment': ''}

#check if cluster exists and remove it
if __salt__['postgres.cluster_exists'](version, name):
if __opts__.get('test'):
ret['result'] = None
msg = 'Cluster {0}/{1} is set to be removed'
ret['comment'] = msg.format(version, name)
return ret
if __salt__['postgres.cluster_remove'](version, name):
msg = 'Cluster {0}/{1} has been removed'
ret['comment'] = msg.format(version, name)
ret['changes'][name] = 'Absent'
return ret

# fallback
ret['comment'] = 'Cluster {0}/{1} is not present, so it cannot ' \
'be removed'.format(version, name)
return ret
136 changes: 136 additions & 0 deletions tests/unit/states/postgres_cluster_test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
# -*- coding: utf-8 -*-
'''
:codeauthor: :email:`Logilab <contact@logilab.fr>`
'''
# Import Python libs
from __future__ import absolute_import

# Import Salt Testing Libs
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('../../')

# Import Salt Libs
from salt.states import postgres_cluster

postgres_cluster.__opts__ = {}
postgres_cluster.__salt__ = {}


@skipIf(NO_MOCK, NO_MOCK_REASON)
class PostgresClusterTestCase(TestCase):
'''
Test cases for salt.states.postgres_cluster
'''
# 'present' function tests: 1

def test_present(self):
'''
Test to ensure that the named database is present
with the specified properties.
'''
name = 'main'
version = '9.4'

ret = {'name': name,
'changes': {},
'result': False,
'comment': ''}

mock_t = MagicMock(return_value=True)
mock_f = MagicMock(return_value=False)
infos = {'{0}/{1}'.format(version, name): {}}
mock = MagicMock(return_value=infos)
with patch.dict(postgres_cluster.__salt__,
{'postgres.cluster_list': mock,
'postgres.cluster_exists': mock_t,
'postgres.cluster_create': mock_t,
}):
comt = ('Cluster {0}/{1} is already present'.format(version, name))
ret.update({'comment': comt, 'result': True})
self.assertDictEqual(postgres_cluster.present(version, name), ret)
infos['{0}/{1}'.format(version, name)]['port'] = 5433
comt = ('Cluster {0}/{1} has wrong parameters '
'which couldn\'t be changed on fly.'.format(version, name))
ret.update({'comment': comt, 'result': False})
self.assertDictEqual(postgres_cluster.present(version, name, port=5434), ret)
infos['{0}/{1}'.format(version, name)]['datadir'] = '/tmp/'
comt = ('Cluster {0}/{1} has wrong parameters '
'which couldn\'t be changed on fly.'.format(version, name))
ret.update({'comment': comt, 'result': False})
self.assertDictEqual(postgres_cluster.present(version, name, port=5434), ret)

with patch.dict(postgres_cluster.__salt__,
{'postgres.cluster_list': mock,
'postgres.cluster_exists': mock_f,
'postgres.cluster_create': mock_t,
}):
comt = 'The cluster {0}/{1} has been created'.format(version, name)
ret.update({'comment': comt, 'result': True,
'changes': {'{0}/{1}'.format(version, name): 'Present'}
})
self.assertDictEqual(postgres_cluster.present(version, name),
ret)
with patch.dict(postgres_cluster.__opts__, {'test': True}):
comt = 'Cluster {0}/{1} is set to be created'.format(version, name)
ret.update({'comment': comt, 'result': None, 'changes': {}})
self.assertDictEqual(postgres_cluster.present(version, name),
ret)

with patch.dict(postgres_cluster.__salt__,
{'postgres.cluster_list': mock,
'postgres.cluster_exists': mock_f,
'postgres.cluster_create': mock_f,
}):
comt = 'Failed to create cluster {0}/{1}'.format(version, name)
ret.update({'comment': comt, 'result': False})
self.assertDictEqual(postgres_cluster.present(version, name),
ret)

# 'absent' function tests: 1

def test_absent(self):
'''
Test to ensure that the named database is absent.
'''
name = 'main'
version = '9.4'

ret = {'name': name,
'changes': {},
'result': False,
'comment': ''}

mock_t = MagicMock(return_value=True)
mock = MagicMock(side_effect=[True, True, False])
with patch.dict(postgres_cluster.__salt__,
{'postgres.cluster_exists': mock,
'postgres.cluster_remove': mock_t}):
with patch.dict(postgres_cluster.__opts__, {'test': True}):
comt = ('Cluster {0}/{1} is set to be removed'.format(version, name))
ret.update({'comment': comt, 'result': None})
self.assertDictEqual(postgres_cluster.absent(version, name), ret)

with patch.dict(postgres_cluster.__opts__, {'test': False}):
comt = ('Cluster {0}/{1} has been removed'.format(version, name))
ret.update({'comment': comt, 'result': True,
'changes': {name: 'Absent'}})
self.assertDictEqual(postgres_cluster.absent(version, name), ret)

comt = ('Cluster {0}/{1} is not present, so it cannot be removed'
.format(version, name))
ret.update({'comment': comt, 'result': True, 'changes': {}})
self.assertDictEqual(postgres_cluster.absent(version, name), ret)


if __name__ == '__main__':
from integration import run_tests
run_tests(PostgresClusterTestCase, needs_daemon=False)