[PATCH] Add some properties to install and configure Postgresql

David Bremner david at tethera.net
Sun Dec 19 03:27:52 GMT 2021


In order to do common tasks like adding users in an idempotent way requires
some non-obvious incantations, so it is worth providing properties for these
tasks.

Signed-off-by: David Bremner <david at tethera.net>
---
 consfigurator.asd          |  1 +
 src/package.lisp           | 10 +++++
 src/property/postgres.lisp | 92 ++++++++++++++++++++++++++++++++++++++
 3 files changed, 103 insertions(+)
 create mode 100644 src/property/postgres.lisp

diff --git a/consfigurator.asd b/consfigurator.asd
index 2ae9b40..ab31dcc 100644
--- a/consfigurator.asd
+++ b/consfigurator.asd
@@ -76,6 +76,7 @@
                (:file "src/property/timezone")
                (:file "src/property/swap")
                (:file "src/property/lxc")
+               (:file "src/property/postgres")
                (:file "src/connection/shell-wrap")
 	       (:file "src/connection/fork")
                (:file "src/connection/rehome")
diff --git a/src/package.lisp b/src/package.lisp
index d83a2c5..acc6b85 100644
--- a/src/package.lisp
+++ b/src/package.lisp
@@ -940,6 +940,16 @@
 
                     #:lxc-ls))
 
+  (package :consfigurator.property.postgres
+           (:local-nicknames (#:os          #:consfigurator.property.os)
+                             (#:apt         #:consfigurator.property.apt))
+           (:export #:installed
+                    #:superuser-is
+                    #:has-role
+                    #:has-database
+                    #:has-group
+                    #:can-login))
+
   (package :consfigurator.connection.local
            (:export #:local-connection))
 
diff --git a/src/property/postgres.lisp b/src/property/postgres.lisp
new file mode 100644
index 0000000..ed9fe04
--- /dev/null
+++ b/src/property/postgres.lisp
@@ -0,0 +1,92 @@
+;;; Consfigurator -- Lisp declarative configuration management system
+
+;;; Copyright (C) 2021  David Bremner <david at tethera.net>
+
+;;; This file 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, or (at your option)
+;;; any later version.
+
+;;; This file 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, see <http://www.gnu.org/licenses/>.
+
+(in-package :consfigurator.property.postgres)
+(named-readtables:in-readtable :consfigurator)
+(named-readtables:in-readtable :interpol-syntax)
+
+;; Currently all of properties in this package require Debian because they use
+;; `runuser' and because of the current implementation of the following
+;; function.
+(defproplist installed :posix ()
+  "Ensure that postgresql and associated utilities are installed."
+  (:desc "postgresql and associated utilities installed")
+  (os:etypecase
+    (debianlike (apt:installed "postgresql" "postgresql-client"))))
+
+(defprop superuser-is :posix (name)
+  "Record Postgres superuser"
+  (:desc "postgres superuser is ${name}")
+  (:hostattrs
+   (push-hostattrs 'postgres-superuser name)))
+
+(defun superuser ()
+  "Return Postgres superuser."
+  (or (get-hostattrs-car 'postgres-superuser) "postgres"))
+
+(defprop %run-sql :posix (sql)
+  "Run given sql as the Postgres superuser against the `postgres' database."
+  (:apply
+   (mrun "runuser" "-u" (superuser) "--" "psql" "postgres" :input sql)))
+
+(defproplist has-role :posix (role)
+  "Ensure ROLE exists in the Postgres cluster."
+  (:desc #?"Postgres role ${role} exists")
+  (:hostattrs
+   (os:required 'os:debianlike))
+  (installed)
+  (%run-sql
+   #?"DO $$
+      BEGIN
+      CREATE ROLE ${role};
+      EXCEPTION WHEN duplicate_object THEN RAISE NOTICE '%, skipping',
+        SQLERRM USING ERRCODE = SQLSTATE;
+      END
+      $$;"))
+
+(defproplist has-database :posix (db-name &key (owner nil))
+  "Ensure Postgres DATABASE exists, optionally with owner OWNER"
+  (:desc
+   (strcat #?"Postgres database ${db-name} exists"
+           (if owner #?" with owner ${owner}" "")))
+  (:hostattrs
+   (os:required 'os:debianlike))
+  (installed)
+  ;; this has a potential race condition between test and creation
+  (%run-sql
+   (strcat
+    #?"SELECT 'CREATE DATABASE ${db-name}"
+    (if owner #?" WITH OWNER ${owner}" "")
+    "' WHERE NOT EXISTS "
+    #?"(SELECT FROM pg_database WHERE datname = '${db-name}')\\gexec")))
+
+(defproplist has-group :posix (user group)
+  "Ensure Postgres user USER is a member of GROUP."
+  (:desc #?"Postgres role ${user} is a member of group ${group}")
+  (:hostattrs
+   ;; relies on runuser
+   (os:required 'os:debianlike))
+  (installed)
+  (%run-sql #?"ALTER GROUP ${group} ADD USER ${user}"))
+
+(defprop can-login :posix (user)
+  "Ensure USER can login to Postgres."
+  (:desc #?"Postgres role ${user} can login to database")
+  (:hostattrs
+   (os:required 'os:debianlike))
+  (installed)
+  (%run-sql #?"ALTER USER ${user} WITH LOGIN;"))
-- 
2.34.1




More information about the sgo-software-discuss mailing list