From 83ee442141f5a90017d63c283260547e14550624 Mon Sep 17 00:00:00 2001
From: Marco Mariani <marco.mariani@nexedi.com>
Date: Mon, 24 Sep 2012 10:34:02 +0200
Subject: [PATCH] create db and user in separate steps

---
 slapos/recipe/postgres/__init__.py | 49 ++++++++++++++++++------------
 1 file changed, 30 insertions(+), 19 deletions(-)

diff --git a/slapos/recipe/postgres/__init__.py b/slapos/recipe/postgres/__init__.py
index 005616717..dce35a223 100644
--- a/slapos/recipe/postgres/__init__.py
+++ b/slapos/recipe/postgres/__init__.py
@@ -35,6 +35,7 @@ from zc.buildout import UserError
 from slapos.recipe.librecipe import GenericBaseRecipe
 from slapos.recipe.librecipe import filehash
 
+
 class Recipe(GenericBaseRecipe):
 
     def _options(self, options):
@@ -49,10 +50,12 @@ class Recipe(GenericBaseRecipe):
             self.createCluster()
             self.createConfig()
             self.createDatabase()
+            self.createSuperuser()
             self.createRunScript()
 
         return [
-                os.path.join(pgdata, 'postgresql.conf')
+                # XXX what to return here?
+                # os.path.join(pgdata, 'postgresql.conf')
                 ]
 
 
@@ -98,19 +101,33 @@ class Recipe(GenericBaseRecipe):
 
                     # "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):
+        self.runPostgresCommand(cmd='CREATE DATABASE "%s"' % self.options['dbname'])
+
+
+    def createSuperuser(self):
+        """
+        Creates a Postgres superuser - other than "slapuser#" for use by the application.
+        """
+        password = 'insecure'
+        enc_password = md5.md5(password).hexdigest()
+        self.runPostgresCommand(cmd="""CREATE USER "%s" PASSWORD '%s' SUPERUSER""" % (self.options['user'], enc_password))
+
+
+    def runPostgresCommand(self, cmd):
+        """
+        Executes a command in single-user mode, with no daemon running.
+
+        Multiple commands can be executed by providing newlines,
+        preceeded by backslash, between them.
+        See http://www.postgresql.org/docs/9.1/static/app-postgres.html
+        """
+
         pgdata = self.options['pgdata-directory']
         postgres_binary = os.path.join(self.options['bin'], 'postgres')
 
@@ -120,23 +137,17 @@ class Recipe(GenericBaseRecipe):
                                   '-D', pgdata,
                                   'postgres',
                                   ], stdin=subprocess.PIPE)
-            password = 'insecure'
-            enc_password = md5.md5(password).hexdigest()
-
-            # to execute multiple commands, all newlines (but the last) must be preceded by backslash.
-            # see http://www.postgresql.org/docs/9.1/static/app-postgres.html
 
-            sql = '\n'.join([
-                    'CREATE DATABASE %s\\\n' % self.options['dbname'],
-                    "CREATE USER '%s' PASSWORD '%s' SUPERUSER'\n" % (self.options['user'], enc_password),
-                ])
-            p.communicate(sql)
+            p.communicate(cmd+'\n')
         except subprocess.CalledProcessError:
             raise UserError('Could not create database %s' % pgdata)
 
 
     def createRunScript(self):
-        # 'exec' the command to control it from supervisor
+        """
+        Creates a script that runs postgres in the foreground.
+        'exec' is used to allow easy control by supervisor.
+        """
         content = textwrap.dedent("""\
                 #!/bin/sh
                 exec %(bin)s/postgres \\
-- 
2.30.9