diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..ab1b3b9 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +.kitchen/ +*.swp +*.swo diff --git a/.kitchen.yml b/.kitchen.yml new file mode 100644 index 0000000..d9c06bf --- /dev/null +++ b/.kitchen.yml @@ -0,0 +1,26 @@ +--- +driver: + name: vagrant + network: + - ["private_network", { ip: "192.168.33.33" }] + +provisioner: + name: salt_solo + formula: postgres + pillars-from-files: + postgres.sls: pillar.example + pillars: + top.sls: + base: + "*": + - postgres + state_top: + base: + "*": + - postgres + +platforms: + - name: ubuntu-14.04 + +suites: + - name: default diff --git a/Gemfile b/Gemfile new file mode 100644 index 0000000..4c95fc1 --- /dev/null +++ b/Gemfile @@ -0,0 +1,5 @@ +source "https://rubygems.org" + +gem "test-kitchen", "> 1.2.0" +gem "kitchen-vagrant" +gem "kitchen-salt" diff --git a/Gemfile.lock b/Gemfile.lock new file mode 100644 index 0000000..14f77c6 --- /dev/null +++ b/Gemfile.lock @@ -0,0 +1,26 @@ +GEM + remote: https://rubygems.org/ + specs: + kitchen-salt (0.0.19) + kitchen-vagrant (0.15.0) + test-kitchen (~> 1.0) + mixlib-shellout (2.0.1) + net-scp (1.2.1) + net-ssh (>= 2.6.5) + net-ssh (2.9.2) + safe_yaml (1.0.4) + test-kitchen (1.3.1) + mixlib-shellout (>= 1.2, < 3.0) + net-scp (~> 1.1) + net-ssh (~> 2.7) + safe_yaml (~> 1.0) + thor (~> 0.18) + thor (0.19.1) + +PLATFORMS + ruby + +DEPENDENCIES + kitchen-salt + kitchen-vagrant + test-kitchen (> 1.2.0) diff --git a/LICENSE b/LICENSE index 52ec1c1..4de972d 100644 --- a/LICENSE +++ b/LICENSE @@ -1,4 +1,4 @@ - Copyright (c) 2013 Salt Stack Formulas + Copyright (c) 2013-2015 Salt Stack Formulas Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. diff --git a/README.rst b/README.rst index e4f2c09..71ebb2d 100644 --- a/README.rst +++ b/README.rst @@ -22,3 +22,34 @@ Installs the postgresql package. ------------------- Installs the postgresql python module + +``postgres.client`` +------------------- + +Installs the postgresql client + +Testing +======= + +Testing is done wit kitchen-salt + +``kitchen converge`` +-------------------- + +Runs the postgres main state + +``kitchen verify`` +------------------ + +Runs serverspec tests on the actual instance + +``kitchen test`` +---------------- + +Builds and runs test from scratch + +``kitchen login`` +----------------- + +Gives you ssh to the vagrant machine for manual testing + diff --git a/_modules/postgres_ext.py b/_modules/postgres_ext.py new file mode 100644 index 0000000..89666fa --- /dev/null +++ b/_modules/postgres_ext.py @@ -0,0 +1,261 @@ +from __future__ import absolute_import +import logging +try: + import pipes + import csv + HAS_ALL_IMPORTS = True +except ImportError: + HAS_ALL_IMPORTS = False + +# All this can be removed when we merge this stuff upstream +import salt.utils + +log = logging.getLogger(__name__) + +def __virtual__(): + ''' + Only load this module if the postgres module is already loaded + ''' + if 'postgres.psql_query' in __salt__: + return True + return False + +# Copied directly from salt/modules/postgres.py, remove when upstreaming +def _run_psql(cmd, runas=None, password=None, host=None, port=None, user=None): + ''' + Helper function to call psql, because the password requirement + makes this too much code to be repeated in each function below + ''' + kwargs = { + 'reset_system_locale': False, + 'clean_env': True, + } + if runas is None: + if not host: + host = __salt__['config.option']('postgres.host') + if not host or host.startswith('/'): + if 'FreeBSD' in __grains__['os_family']: + runas = 'pgsql' + if 'OpenBSD' in __grains__['os_family']: + runas = '_postgresql' + else: + runas = 'postgres' + + if user is None: + user = runas + + if runas: + kwargs['runas'] = runas + + if password is None: + password = __salt__['config.option']('postgres.pass') + if password is not None: + pgpassfile = salt.utils.mkstemp(text=True) + with salt.utils.fopen(pgpassfile, 'w') as fp_: + fp_.write('{0}:{1}:*:{2}:{3}'.format( + 'localhost' if not host or host.startswith('/') else host, + port if port else '*', + user if user else '*', + password, + )) + __salt__['file.chown'](pgpassfile, runas, '') + kwargs['env'] = {'PGPASSFILE': pgpassfile} + + ret = __salt__['cmd.run_all'](cmd, python_shell=False, **kwargs) + + if ret.get('retcode', 0) != 0: + log.error('Error connecting to Postgresql server') + if password is not None and not __salt__['file.remove'](pgpassfile): + log.warning('Remove PGPASSFILE failed') + + return ret + + +def _connection_defaults(user=None, host=None, port=None, maintenance_db=None, + password=None): + ''' + Returns a tuple of (user, host, port, db) with config, pillar, or default + values assigned to missing values. + ''' + if not user: + user = __salt__['config.option']('postgres.user') + if not host: + host = __salt__['config.option']('postgres.host') + if not port: + port = __salt__['config.option']('postgres.port') + if not maintenance_db: + maintenance_db = __salt__['config.option']('postgres.maintenance_db') + if password is None: + password = __salt__['config.option']('postgres.pass') + + return (user, host, port, maintenance_db, password) + + +def _psql_cmd(*args, **kwargs): + ''' + Return string with fully composed psql command. + Accept optional keyword arguments: user, host and port as well as any + number or positional arguments to be added to the end of command. + ''' + (user, host, port, maintenance_db, password) = _connection_defaults( + kwargs.get('user'), + kwargs.get('host'), + kwargs.get('port'), + kwargs.get('maintenance_db'), + kwargs.get('password')) + + cmd = [salt.utils.which('psql'), + '--no-align', + '--no-readline', + '--no-password'] # It is never acceptable to issue a password prompt. + if user: + cmd += ['--username', user] + if host: + cmd += ['--host', host] + if port: + cmd += ['--port', str(port)] + if not maintenance_db: + maintenance_db = 'postgres' + cmd += ['--dbname', maintenance_db] + cmd += args + cmdstr = ' '.join([pipes.quote(c) for c in cmd]) + return cmdstr + + +def _psql_prepare_and_run(cmd, + host=None, + port=None, + maintenance_db=None, + password=None, + runas=None, + user=None): + rcmd = _psql_cmd( + host=host, user=user, port=port, + maintenance_db=maintenance_db, password=password, + *cmd) + cmdret = _run_psql( + rcmd, runas=runas, password=password, host=host, port=port, user=user) + return cmdret + +def tablespace_list(user=None, host=None, port=None, maintenance_db=None, + password=None, runas=None): + ''' + Return dictionary with information about tablespaces of a Postgres server. + CLI Example: + .. code-block:: bash + salt '*' postgres_ext.tablespace_list + ''' + + ret = {} + + query = ( + 'SELECT spcname as "Name", pga.rolname as "Owner", spcacl as "ACL", ' + 'spcoptions as "Opts", pg_tablespace_location(pgts.oid) as "Location" ' + 'FROM pg_tablespace pgts, pg_roles pga WHERE pga.oid = pgts.spcowner' + ) + + rows = __salt__['postgres.psql_query'](query, runas=runas, host=host, + user=user, port=port, + maintenance_db=maintenance_db, + password=password) + + for row in rows: + ret[row['Name']] = row + ret[row['Name']].pop('Name') + + return ret + + +def tablespace_exists(name, user=None, host=None, port=None, maintenance_db=None, + password=None, runas=None): + ''' + Checks if a tablespace exists on the Postgres server. + CLI Example: + .. code-block:: bash + salt '*' postgres_ext.tablespace_exists 'dbname' + ''' + + tablespaces = tablespace_list(user=user, host=host, port=port, + maintenance_db=maintenance_db, + password=password, runas=runas) + return name in tablespaces + + +def tablespace_create(name, location, user=None, host=None, port=None, + maintenance_db=None, password=None, runas=None): + ''' + Adds a tablespace to the Postgres server. + + CLI Example: + + .. code-block:: bash + + salt '*' postgres_ext.tablespace_create tablespacename '/path/datadir' + ''' + query = 'CREATE TABLESPACE {0} LOCATION \'{1}\''.format(name, location) + + # Execute the command + 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 tablespace_alter(name, user=None, host=None, port=None, maintenance_db=None, + password=None, new_name=None, new_owner=None, + set_option=None, reset_option=None, runas=None): + ''' + Change tablespace name, owner, or options. + CLI Example: + .. code-block:: bash + salt '*' postgres_ext.tablespace_alter tsname new_owner=otheruser + salt '*' postgres_ext.tablespace_alter index_space new_name=fast_raid + salt '*' postgres_ext.tablespace_alter tsname reset_option=seq_page_cost + ''' + if not any([new_name, new_owner, set_option, reset_option]): + return True # Nothing todo? + + queries = [] + + if new_name: + queries.append('ALTER TABLESPACE {} RENAME TO {}'.format( + name, new_name)) + if new_owner: + queries.append('ALTER TABLESPACE {} OWNER TO {}'.format( + name, new_owner)) + if set_option: + queries.append('ALTER TABLESPACE {} SET ({} = {})'.format( + name, set_option[0], set_option[1])) + if reset_option: + queries.append('ALTER TABLESPACE {} RESET ({})'.format( + name, reset_option)) + + for query in queries: + ret = _psql_prepare_and_run(['-c', query], + user=user, host=host, port=port, + maintenance_db=maintenance_db, + password=password, runas=runas) + if ret['retcode'] != 0: + return False + + return True + + +def tablespace_remove(name, user=None, host=None, port=None, + maintenance_db=None, password=None, runas=None): + ''' + Removes a tablespace from the Postgres server. + CLI Example: + .. code-block:: bash + salt '*' postgres_ext.tablespace_remove tsname + ''' + query = 'DROP TABLESPACE {}'.format(name) + ret = _psql_prepare_and_run(['-c', query], + user=user, + host=host, + port=port, + runas=runas, + maintenance_db=maintenance_db, + password=password) + return ret['retcode'] == 0 diff --git a/_states/postgres_tablespace.py b/_states/postgres_tablespace.py new file mode 100644 index 0000000..bf0953c --- /dev/null +++ b/_states/postgres_tablespace.py @@ -0,0 +1,144 @@ +''' +Management of PostgreSQL tablespace +================================== +The postgres_tablespace module is used to create and manage Postgres +tablespaces. +Tablespaces can be set as either absent or present. +.. code-block:: yaml + ssd-tablespace: + postgres_tablespace.present: + - name: indexes + - path: +''' +from __future__ import absolute_import + + +def __virtual__(): + ''' + Only load if the postgres_ext module is present + ''' + return 'postgres_ext.tablespace_exists' in __salt__ + +def present(name, + directory, + options=None, + owner=None, + user=None, + maintenance_db=None, + db_password=None, + db_host=None, + db_port=None, + db_user=None): + ''' + Ensure that the named tablespace is present with the specified properties. + For more information about all of these options see man create_tablespace(1) + name + The name of the tablespace to manage + directory + The directory where the tablespace will be located + db_user + database username if different from config or defaul + 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 + user + System user all operations should be performed on behalf of + .. versionadded:: Beryllium + ''' + ret = {'name': name, + 'changes': {}, + 'result': True, + 'comment': 'Tablespace {0} is already present'.format(name)} + dbargs = { + 'maintenance_db': maintenance_db, + 'runas': user, + 'host': db_host, + 'user': db_user, + 'port': db_port, + 'password': db_password, + } + tblspaces = __salt__['postgres_ext.tablespace_list'](**dbargs) + if name not in tblspaces: + # not there, create it + if __opts__['test']: + ret['result'] = None + ret['comment'] = 'Tablespace {0} is set to be created'.format(name) + return ret + if __salt__['postgres_ext.tablespace_create'](name, directory, **dbargs): + ret['comment'] = 'The tablespace {0} has been created'.format(name) + ret['changes'][name] = 'Present' + return ret + + # already exists, make sure it's got the right path + if tblspaces[name]['Location'] != directory: + ret['comment'] = 'Tablespace {0} isn\'t at the right path'.format( + name) + ret['result'] = False + return ret # This isn't changeable, they need to remove/remake + + if (owner and not tblspaces[name]['Owner'] == owner): + if __opts__['test']: + ret['result'] = None + ret['comment'] = 'Tablespace {0} owner to be altered'.format(name) + return ret + if __salt__['postgres_ext.tablespace_alter'](name, new_owner=owner): + ret['comment'] = 'Tablespace {0} owner changed'.format(name) + ret['result'] = True + + return ret + + +def absent(name, + user=None, + maintenance_db=None, + db_password=None, + db_host=None, + db_port=None, + db_user=None): + ''' + Ensure that the named database is absent + name + The name of the database to remove + db_user + database username if different from config or defaul + 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 + user + System user all operations should be performed on behalf of + .. versionadded:: Beryllium + ''' + ret = {'name': name, + 'changes': {}, + 'result': True, + 'comment': ''} + + db_args = { + 'maintenance_db': maintenance_db, + 'runas': user, + 'host': db_host, + 'user': db_user, + 'port': db_port, + 'password': db_password, + } + #check if tablespace exists and remove it + if __salt__['postgres_ext.tablespace_exists'](name, **db_args): + if __opts__['test']: + ret['result'] = None + ret['comment'] = 'Tablespace {0} is set to be removed'.format(name) + return ret + if __salt__['postgres_ext.tablespace_remove'](name, **db_args): + ret['comment'] = 'Tablespace {0} has been removed'.format(name) + ret['changes'][name] = 'Absent' + return ret + + # fallback + ret['comment'] = 'Tablespace {0} is not present, so it cannot ' \ + 'be removed'.format(name) + return ret diff --git a/pillar.example b/pillar.example index bec474e..eb34251 100644 --- a/pillar.example +++ b/pillar.example @@ -1,8 +1,11 @@ postgres: pg_hba.conf: salt://postgres/pg_hba.conf + use_upstream_repo: False + lookup: pkg: 'postgresql-9.3' + pkg_client: 'postgresql-client-9.3' pg_hba: '/etc/postgresql/9.3/main/pg_hba.conf' users: diff --git a/postgres/client.sls b/postgres/client.sls new file mode 100644 index 0000000..84b9e07 --- /dev/null +++ b/postgres/client.sls @@ -0,0 +1,17 @@ +{% from "postgres/map.jinja" import postgres with context %} + +{% if postgres.use_upstream_repo %} +include: + - postgres.upstream +{% endif %} + +install-postgresql-client: + pkg.installed: + - name: {{ postgres.pkg_client }} + - refresh: {{ postgres.use_upstream_repo }} + +{% if postgres.pkg_libpq_dev != False %} +install-postgres-libpq-dev: + pkg.installed: + - name: {{ postgres.pkg_libpq_dev }} +{% endif %} diff --git a/postgres/codenamemap.yaml b/postgres/codenamemap.yaml new file mode 100644 index 0000000..8759e4c --- /dev/null +++ b/postgres/codenamemap.yaml @@ -0,0 +1,9 @@ +wheezy: + pkg_repo: deb http://apt.postgresql.org/pub/repos/apt/ wheezy-pgdg main +jessie: + version: 9.4 + pkg_repo: deb http://apt.postgresql.org/pub/repos/apt/ jessie-pgdg main +trusty: + version: 9.3 +utopic: + version: 9.4 diff --git a/postgres/defaults.yaml b/postgres/defaults.yaml new file mode 100644 index 0000000..5c4c27e --- /dev/null +++ b/postgres/defaults.yaml @@ -0,0 +1,19 @@ +postgres: + pkg: postgresql + pkg_dev: postgresql-devel + pkg_libpq_dev: postgresql-libs + pkg_client: postgresql-client + pkg_contrib: postgresql-contrib + python: python-psycopg2 + service: postgresql + conf_dir: /var/lib/pgsql/data + create_cluster: False + init_db: False + version: 9.1 + use_upstream_repo: False + users: {} + acls: [] + databases: {} + tablespaces: {} + postgresconf: "" + pg_hba.conf: salt://postgres/pg_hba.conf diff --git a/postgres/init.sls b/postgres/init.sls index a2eeea4..58b4f95 100644 --- a/postgres/init.sls +++ b/postgres/init.sls @@ -1,8 +1,14 @@ {% from "postgres/map.jinja" import postgres with context %} +{% if postgres.use_upstream_repo %} +include: + - postgres.upstream +{% endif %} + install-postgresql: pkg.installed: - name: {{ postgres.pkg }} + - refresh: {{ postgres.use_upstream_repo }} {% if postgres.create_cluster != False %} create-postgresql-cluster: @@ -39,27 +45,36 @@ install-postgres-dev-package: - name: {{ postgres.pkg_dev }} {% endif %} -{{ postgres.pkg_libpq_dev }}: - pkg.installed +{% if postgres.pkg_libpq_dev != False %} +install-postgres-libpq-dev: + pkg.installed: + - name: {{ postgres.pkg_libpq_dev }} +{% endif %} -{% if 'postgresconf' in pillar.get('postgres', {}) %} +{% if postgres.pkg_contrib != False %} +install-postgres-contrib: + pkg.installed: + - name: {{ postgres.pkg_contrib }} +{% endif %} + +{% if postgres.postgresconf %} postgresql-conf: file.blockreplace: - name: {{ postgres.conf_dir }}/postgresql.conf - marker_start: "# Managed by SaltStack: listen_addresses: please do not edit" - marker_end: "# Managed by SaltStack: end of salt managed zone --" - - content: {{ salt['pillar.get']('postgres:postgresconf') }} + - content: | + {{ postgres.postgresconf|indent(8) }} - show_changes: True - append_if_not_found: True - watch_in: - service: postgresql {% endif %} -{% if 'pg_hba.conf' in pillar.get('postgres', {}) %} pg_hba.conf: file.managed: - name: {{ postgres.conf_dir }}/pg_hba.conf - - source: {{ salt['pillar.get']('postgres:pg_hba.conf', 'salt://postgres/pg_hba.conf') }} + - source: {{ postgres['pg_hba.conf'] }} - template: jinja - user: postgres - group: postgres @@ -68,37 +83,51 @@ pg_hba.conf: - pkg: {{ postgres.pkg }} - watch_in: - service: postgresql -{% endif %} -{% if 'users' in pillar.get('postgres', {}) %} -{% for name, user in salt['pillar.get']('postgres:users').items() %} +{% for name, user in postgres.users.items() %} postgres-user-{{ name }}: postgres_user.present: - name: {{ name }} - - createdb: {{ salt['pillar.get']('postgres:users:' + name + ':createdb', False) }} - - password: {{ salt['pillar.get']('postgres:users:' + name + ':password', 'changethis') }} - - runas: postgres + - createdb: {{ user.get('createdb', False) }} + - password: {{ user.get('password', 'changethis') }} + - user: {{ user.get('runas', 'postgres') }} - require: - service: {{ postgres.service }} {% endfor%} -{% endif %} -{% if 'databases' in pillar.get('postgres', {}) %} -{% for name, db in salt['pillar.get']('postgres:databases').items() %} +{% for name, db in postgres.databases.items() %} postgres-db-{{ name }}: postgres_database.present: - name: {{ name }} - - encoding: {{ salt['pillar.get']('postgres:databases:'+ name +':encoding', 'UTF8') }} - - lc_ctype: {{ salt['pillar.get']('postgres:databases:'+ name +':lc_ctype', 'en_US.UTF8') }} - - lc_collate: {{ salt['pillar.get']('postgres:databases:'+ name +':lc_collate', 'en_US.UTF8') }} - - template: {{ salt['pillar.get']('postgres:databases:'+ name +':template', 'template0') }} - {% if salt['pillar.get']('postgres:databases:'+ name +':owner') %} - - owner: {{ salt['pillar.get']('postgres:databases:'+ name +':owner') }} + - encoding: {{ db.get('encoding', 'UTF8') }} + - lc_ctype: {{ db.get('lc_ctype', 'en_US.UTF8') }} + - lc_collate: {{ db.get('lc_collate', 'en_US.UTF8') }} + - template: {{ db.get('template', 'template0') }} + {% if db.get('owner') %} + - owner: {{ db.get('owner') }} {% endif %} - - runas: {{ salt['pillar.get']('postgres:databases:'+ name +':runas', 'postgres') }} - {% if salt['pillar.get']('postgres:databases:'+ name +':user') %} + - user: {{ db.get('runas', 'postgres') }} + {% if db.get('user') %} - require: - - postgres_user: postgres-user-{{ salt['pillar.get']('postgres:databases:'+ name +':user') }} + - postgres_user: postgres-user-{{ db.get('user') }} {% endif %} {% endfor%} -{% endif %} + +{% for name, directory in postgres.tablespaces.items() %} +postgres-tablespace-dir-perms-{{ directory}}: + file.directory: + - name: {{ directory }} + - user: postgres + - group: postgres + - makedirs: True + - recurse: + - user + - group + +postgres-tablespace-{{ name }}: + postgres_tablespace.present: + - name: {{ name }} + - directory: {{ directory }} + - require: + - service: {{ postgres.service }} +{% endfor%} diff --git a/postgres/map.jinja b/postgres/map.jinja index 4ec03fe..415e344 100644 --- a/postgres/map.jinja +++ b/postgres/map.jinja @@ -1,48 +1,22 @@ -{% set pg_version = salt['grains.filter_by']({ - 'RedHat' : { 'id': '9.1' }, - 'Arch' : { 'id': '9.1' }, - 'Debian' : { 'id': '9.3' }, -}, merge=salt['grains.filter_by']({ - '14.04' : { 'id': '9.3' }, - '14.10' : { 'id': '9.4' }, -}, grain='lsb_distrib_release', merge=salt['grains.filter_by']({ - 'jessie' : { 'id': '9.4' }, - 'wheezy' : { 'id': '9.1' }, -}, grain='lsb_distrib_codename', merge=salt['pillar.get']('postgres:lookup')))) %} +{% import_yaml "postgres/defaults.yaml" as defaults %} +{% import_yaml "postgres/osmap.yaml" as osmap %} +{% import_yaml "postgres/codenamemap.yaml" as codemap %} -{% set postgres = salt['grains.filter_by']({ - 'RedHat': { - 'pkg' : 'postgresql-server', - 'pkg_dev' : 'postgresql-devel', - 'pkg_libpq_dev' : 'postgresql-libs', - 'python' : 'python-psycopg2', - 'service' : 'postgresql', - 'conf_dir' : '/var/lib/pgsql/data', - 'create_cluster' : False, - 'init_db' : True, - 'version' : pg_version.id, - }, - 'Arch': { - 'pkg' : 'postgresql', - 'pkg_dev' : 'postgresql-devel', - 'pkg_libpq_dev' : 'postgresql-libs', - 'python' : 'python-psycopg2', - 'service' : 'postgresql', - 'conf_dir' : '/var/lib/pgsql/data', - 'create_cluster' : False, - 'init_db' : True, - 'version' : pg_version.id, - }, - 'Debian': { - 'pkg' : 'postgresql', - 'pkg_dev' : 'postgresql-server-dev-' + pg_version.id, - 'pkg_libpq_dev' : 'libpq-dev', - 'python' : 'python-pygresql', - 'service' : 'postgresql', - 'pg_hba' : '/etc/postgresql/' + pg_version.id + '/main/pg_hba.conf', - 'conf_dir' : '/etc/postgresql/' + pg_version.id + '/main', - 'create_cluster' : False, - 'init_db' : False, - 'version' : pg_version.id, - }, -}, merge=salt['pillar.get']('postgres:lookup')) %} +{# get the settings for the os_family grain #} +{% set osfam = salt['grains.filter_by'](osmap) or {} %} +{# get the settings for the oscodename grain, os_family data will override + oscodename data #} +{% set oscode = salt['grains.filter_by'](codemap, + grain='oscodename', + merge=osfam) or {} %} + +{# merge the os family/codename specific data over the defaults #} +{% do defaults.postgres.update(oscode) %} + +{# merge the pillar:lookup dict into the defaults/os specific dict #} +{% set lookup = salt['pillar.get']('postgres:lookup', + default=defaults.postgres, + merge=True) %} + +{# merge the actual postgres pillar into the above combined dict #} +{% set postgres = salt['pillar.get']('postgres', default=lookup, merge=True) %} diff --git a/postgres/osmap.yaml b/postgres/osmap.yaml new file mode 100644 index 0000000..dc4224e --- /dev/null +++ b/postgres/osmap.yaml @@ -0,0 +1,6 @@ +RedHat: + pkg_repo: pgdg94 + repo_baseurl: http://yum.postgresql.org/9.4/redhat/rhel-$releasever-$basearch +Arch: {} +Debian: + pkg_repo_file: /etc/apt/sources.list.d/pgdg.list diff --git a/postgres/upstream.sls b/postgres/upstream.sls new file mode 100644 index 0000000..14ec148 --- /dev/null +++ b/postgres/upstream.sls @@ -0,0 +1,14 @@ +{% from "postgres/map.jinja" import postgres with context %} + +{% if grains['os_family'] == 'Debian' %} +install-postgresql-repo: + pkgrepo.managed: + - humanname: PostgreSQL Official Repository + - name: {{ postgres.pkg_repo }} {{ postgres.version }} + - keyid: B97B0AFCAA1A47F044F244A07FCC7D46ACCC4CF8 + - keyserver: keyserver.ubuntu.com + - file: {{ postgres.pkg_repo_file }} + - require_in: + - pkg: {{ postgres.pkg }} +{% endif %} + diff --git a/test/integration/default/serverspec/postgres_spec.rb b/test/integration/default/serverspec/postgres_spec.rb new file mode 100644 index 0000000..8977a5a --- /dev/null +++ b/test/integration/default/serverspec/postgres_spec.rb @@ -0,0 +1,10 @@ +require "serverspec" + +describe service("postgres") do + it { should be_enabled } + it { should be_running } +end + +describe port("5432") do + it { should be_listening } +end