diff --git a/setup.py b/setup.py index 19deaea4e05c54b4d2534277f4e8d37022c6861a..816e56ba3b7f59653be2afc386e1625fdddac653 100755 --- a/setup.py +++ b/setup.py @@ -110,6 +110,7 @@ setup(name=name, 'novnc = slapos.recipe.novnc:Recipe', 'onetimeupload = slapos.recipe.onetimeupload:Recipe', 'pbs = slapos.recipe.pbs:Recipe', + 'postgres = slapos.recipe.postgres:Recipe', 'proactive = slapos.recipe.proactive:Recipe', 'publish = slapos.recipe.publish:Recipe', 'publishurl = slapos.recipe.publishurl:Recipe', diff --git a/slapos/recipe/postgres/__init__.py b/slapos/recipe/postgres/__init__.py new file mode 100644 index 0000000000000000000000000000000000000000..004981600915e7763fcee4c6c9de7ede26f0a7a5 --- /dev/null +++ b/slapos/recipe/postgres/__init__.py @@ -0,0 +1,136 @@ +############################################################################## +# +# Copyright (c) 2010 Vifib SARL and Contributors. All Rights Reserved. +# +# WARNING: This program as such is intended to be used by professional +# programmers who take the whole responsibility of assessing all potential +# consequences resulting from its eventual inadequacies and bugs +# End users who are looking for a ready-to-use solution with commercial +# guarantees and support are strongly adviced to contract a Free Software +# Service Company +# +# This program is Free Software; you can redistribute it and/or +# modify it under the terms of the GNU General Public License +# as published by the Free Software Foundation; either version 3 +# of the License, or (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program; if not, write to the Free Software +# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. +# +############################################################################## + +import os +import sys +import subprocess +import textwrap +from zc.buildout import UserError + +from slapos.recipe.librecipe import GenericBaseRecipe +from slapos.recipe.librecipe import filehash + +class Recipe(GenericBaseRecipe): + + def _options(self, options): + options['password'] = self.generatePassword() + options['url'] = 'postgresql://%(user)s:%(password)s/%(host)s:%(port)s/%(dbname)s' % dict(options, host=options['ipv6_host'].pop()) + + + def install(self): + self.createCluster() + self.createConfig() + self.createDatabase() + self.createRunScript() + + pgdata = self.options['pgdata-directory'] + + return [ + os.path.join(pgdata, 'postgresql.conf') + ] + + + def createCluster(self): + initdb_binary = os.path.join(self.options['bin'], 'initdb') + + + pgdata = self.options['pgdata-directory'] + + if not os.path.exists(pgdata): + try: + subprocess.check_call([initdb_binary, + '-D', pgdata, + '-A', 'ident', + '-E', 'UTF8', + ]) + except subprocess.CalledProcessError: + raise UserError('Could not create cluster directory in %s' % pgdata) + + + def createConfig(self): + pgdata = self.options['pgdata-directory'] + + with open(os.path.join(pgdata, 'postgresql.conf'), 'wb') as cfg: + cfg.write(textwrap.dedent("""\ + logging_collector = on + log_rotation_size = 50MB + max_connections = 100 + datestyle = 'iso, mdy' + + lc_messages = 'en_US.UTF-8' + lc_monetary = 'en_US.UTF-8' + lc_numeric = 'en_US.UTF-8' + lc_time = 'en_US.UTF-8' + default_text_search_config = 'pg_catalog.english' + """)) + + + with open(os.path.join(pgdata, 'pg_hba.conf'), 'wb') as cfg: + # see http://www.postgresql.org/docs/9.1/static/auth-pg-hba-conf.html + + cfg.write(textwrap.dedent("""\ + # TYPE DATABASE USER ADDRESS METHOD + + # "local" is for Unix domain socket connections only + local all all ident + # IPv4 local connections: + host all all 127.0.0.1/32 md5 + # IPv6 local connections: + host all all ::1/128 md5 + # Allow replication connections from localhost, by a user with the + # replication privilege. + #local replication slapuser4 ident + #host replication slapuser4 127.0.0.1/32 md5 + #host replication slapuser4 ::1/128 md5 + """)) + + + def createDatabase(self): + pgdata = self.options['pgdata-directory'] + postgres_binary = os.path.join(self.options['bin'], 'postgres') + + try: + p = subprocess.Popen([postgres_binary, + '--single', + '-D', pgdata, + 'postgres', + ], stdin=subprocess.PIPE) + p.communicate('CREATE DATABASE %s\n' % self.options['dbname']) + except subprocess.CalledProcessError: + raise UserError('Could not create database %s' % pgdata) + + + def createRunScript(self): + content = textwrap.dedent("""\ + #!/bin/sh + %(bin)s/postgres \\ + -D %(pgdata-directory)s + """ % self.options) + name = os.path.join(self.options['services'], 'postgres-start') + self.createExecutable(name, content=content) + + diff --git a/software/postgres/instance.cfg.in b/software/postgres/instance.cfg.in new file mode 100644 index 0000000000000000000000000000000000000000..d389f446c5f036bd161e40754608e1d8a283f0cd --- /dev/null +++ b/software/postgres/instance.cfg.in @@ -0,0 +1,68 @@ +[buildout] +parts = + symlinks + publish + postgres-instance + + +# Define egg directories to be the one from Software Release +# (/opt/slapgrid/...) +eggs-directory = ${buildout:eggs-directory} +develop-eggs-directory = ${buildout:develop-eggs-directory} +offline = true + + +[instance-parameters] +# Fetches parameters defined in SlapOS Master for this instance +recipe = slapos.cookbook:slapconfiguration +computer = $${slap-connection:computer-id} +partition = $${slap-connection:partition-id} +url = $${slap-connection:server-url} +key = $${slap-connection:key-file} +cert = $${slap-connection:cert-file} + + +[directories] +recipe = slapos.cookbook:mkdirectory +bin = $${buildout:directory}/bin +etc = $${buildout:directory}/etc +services = $${directories:etc}/run/ +promises = $${directories:etc}/promise/ +var = $${buildout:directory}/var + + +[symlinks] +recipe = cns.recipe.symlink +symlink_target = $${directories:bin} +symlink_base = ${postgresql:location}/bin + + +[postgres-instance] +# create cluster, configuration files and a database +recipe = slapos.cookbook:postgres + +# Options +ipv6_host = $${instance-parameters:ipv6} +user = user +port = 5432 +dbname = db +# pgdata_directory is created by initdb, and should not exist beforehand. +pgdata-directory = $${directories:var}/data +services = $${directories:services} +bin = $${directories:bin} + + +[publish] +recipe = slapos.cookbook:publishurl +url = $${postgres-instance:url} + + +[slap-connection] +# part to migrate to new - separated words +computer-id = $${slap_connection:computer_id} +partition-id = $${slap_connection:partition_id} +server-url = $${slap_connection:server_url} +software-release-url = $${slap_connection:software_release_url} +key-file = $${slap_connection:key_file} +cert-file = $${slap_connection:cert_file} + diff --git a/software/postgres/software.cfg b/software/postgres/software.cfg new file mode 100644 index 0000000000000000000000000000000000000000..46d21841829f08b1472a6ca8dcd370f71a9ee02a --- /dev/null +++ b/software/postgres/software.cfg @@ -0,0 +1,25 @@ +[buildout] + +extends = + ../../stack/slapos.cfg + ../../component/postgresql/buildout.cfg + +parts = + eggs + slapos-cookbook + instance-template + postgresql + +[instance-template] +recipe = slapos.recipe.template +url = ${:_profile_base_location_}/instance.cfg.in +output = ${buildout:directory}/template.cfg +#md5sum = +mode = 0644 + + +[eggs] +recipe = zc.recipe.egg +eggs = + cns.recipe.symlink +