diff --git a/.gitignore b/.gitignore
index 52d4c3e..eea0e79 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,4 +1,16 @@
-target
-doc
-checkout
-logs
+/target
+/lib
+/classes
+/checkouts
+/logs
+/doc
+doc-src/VERSIONS.md
+doc-src/INTRO.md
+pom.xml
+pom.xml.asc
+*.jar
+*.class
+.lein-deps-sum
+.lein-failures
+.lein-plugins
+.lein-repl-history
diff --git a/README.md b/README.md
index c05e65a..2815d32 100644
--- a/README.md
+++ b/README.md
@@ -1,26 +1,85 @@
-# Pallet crate for postgres
+[Repository](https://github.com/pallet/postgres-crate) ·
+[Issues](https://github.com/pallet/postgres-crate/issues) ·
+[API docs](http://palletops.com/postgres-crate/0.8/api) ·
+[Annotated source](http://palletops.com/postgres-crate/0.8/annotated/uberdoc.html) ·
+[Release Notes](https://github.com/pallet/postgres-crate/blob/develop/ReleaseNotes.md)
+
+A Pallet crate to install and configure postgres.
+
+### Dependency Information
+
+```clj
+:dependencies [[com.palletops/postgres-crate "0.8.0-alpha.1"]]
+```
+
+### Releases
+
+
+
+ | Pallet | Crate Version | Repo | GroupId |
+
+
+
+ | 0.8.0-beta.6 |
+ 0.8.0-alpha.1 |
+ clojars |
+ com.palletops |
+ Release Notes |
+ Source |
+
+
+ | 0.7.2 |
+ 0.7.0-beta.2 |
+ clojars |
+ com.palletops |
+ Release Notes |
+ Source |
+
+
+
+
+## Usage
+
+The `server-spec` function provides a convenient pallet server spec for
+postgres. It takes a single map as an argument, specifying configuration
+choices, as described below for the `settings` function. You can use this
+in your own group or server specs in the :extends clause.
+
+```clj
+(require '[pallet/crate/postgres :as postgres])
+(group-spec my-postgres-group
+ :extends [(postgres/server-spec {})])
+```
+
+While `server-spec` provides an all-in-one function, you can use the individual
+plan functions as you see fit.
+
+The `settings` function provides a plan function that should be called in the
+`:settings` phase. The function puts the configuration options into the pallet
+session, where they can be found by the other crate functions, or by other
+crates wanting to interact with postgres.
+
+The `install` function is responsible for actually installing postgres.
+
+The `configure` function writes the postgres configuration file, using the form
+passed to the :config key in the `settings` function.
-This a crate to install and run postgres via [Pallet](http://pallet.github.com/pallet).
-
-[Release Notes](ReleaseNotes.md)
-
-## Server Spec
-
-The postgres crate defines the `postgres` function, that takes a settings map
-and returns a server-spec for installing postgres.
## Settings
The postgres crate uses the following settings:
-* `:version`
- a string to specify the point version of PostgreSQL (e.g., `"9.1"`). The default is the version provided by the system's packaging system
+* `:version`
+ a string to specify the point version of PostgreSQL (e.g., `"9.1"`). The
+ default is the version provided by the system's packaging system
* `:components`
- a set of one or more recognized keywords. The set of every component is `#{:server :libs :client}`.
+ a set of one or more recognized keywords. The set of every component is
+ `#{:server :libs :client}`.
* `:strategy`
- allows override of the install strategy (`:packages`, `:package-source`, or `:rpm`)
+ allows override of the install strategy (`:packages`, `:package-source`, or
+ `:rpm`)
* `:packages`
the packages that are used to install
@@ -29,7 +88,9 @@ The postgres crate uses the following settings:
a non-default package source for the packages
* `:rpm`
- takes a map of [`remote-file` options](http://palletops.com/pallet/api/0.7/pallet.action.remote-file.html) specifying an RPM file to install
+ takes a map of
+ [`remote-file` options](http://palletops.com/pallet/api/0.7/pallet.action.remote-file.html)
+ specifying an RPM file to install
* `:default-cluster-name`
name of the default cluster created by the installer
@@ -44,7 +105,8 @@ The postgres crate uses the following settings:
path to `postgresql.conf`
* `:has-pg-wrapper`
- boolean flag for availability of a wrapper allowing command execution against a specified cluster.
+ boolean flag for availability of a wrapper allowing command execution against
+ a specified cluster.
* `:has-multicluster-service`
boolean flag specifying whether the init service is multi-cluster capable.
@@ -74,4 +136,4 @@ The postgres crate uses the following settings:
Licensed under [EPL](http://www.eclipse.org/legal/epl-v10.html)
-Copyright 2010, 2011, 2012 Hugo Duncan.
+Copyright 2013 Hugo Duncan.
diff --git a/dev-resources/logback-test.xml b/dev-resources/logback-test.xml
new file mode 100644
index 0000000..584feb5
--- /dev/null
+++ b/dev-resources/logback-test.xml
@@ -0,0 +1,116 @@
+
+
+
+
+
+ INFO
+
+
+ %d{HH:mm:ss.SSS} [%thread] %-5level %logger{20} - %msg%n
+
+
+
+
+ logs/jclouds-compute.log
+
+ logs/old/jclouds-compute.%d{yyyy-MM-dd}.log
+ 3
+
+
+ %date %level [%thread] %logger{10} [%file:%line] %msg%n
+
+
+
+
+ logs/jclouds-wire.log
+
+ logs/old/jclouds-wire.%d{yyyy-MM-dd}.log
+ 3
+
+
+ %date %level [%thread] %logger{10} [%file:%line] %msg%n
+
+
+
+
+ logs/pallet.log
+
+ logs/old/pallet.%d{yyyy-MM-dd}.log
+ 3
+
+
+ %date %level [%thread] %logger{10} %msg%n
+
+
+
+
+ logs/vmfest.log
+
+ logs/old/vmfest.%d{yyyy-MM-dd}.log
+ 3
+
+
+ %date %level [%thread] %logger{10} %msg%n
+
+
+
+
+
+ target
+ unspecified
+
+
+
+ logs/target-${target}.log
+ false
+
+ %msg%n
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/doc-src/FOOTER.md b/doc-src/FOOTER.md
new file mode 100644
index 0000000..fb3ffd9
--- /dev/null
+++ b/doc-src/FOOTER.md
@@ -0,0 +1,10 @@
+## Support
+
+[On the group](http://groups.google.com/group/pallet-clj), or
+[#pallet](http://webchat.freenode.net/?channels=#pallet) on freenode irc.
+
+## License
+
+Licensed under [EPL](http://www.eclipse.org/legal/epl-v10.html)
+
+Copyright 2013 Hugo Duncan.
diff --git a/doc-src/USAGE.md b/doc-src/USAGE.md
new file mode 100644
index 0000000..1b8ddca
--- /dev/null
+++ b/doc-src/USAGE.md
@@ -0,0 +1,88 @@
+## Usage
+
+The `server-spec` function provides a convenient pallet server spec for
+postgres. It takes a single map as an argument, specifying configuration
+choices, as described below for the `settings` function. You can use this
+in your own group or server specs in the :extends clause.
+
+```clj
+(require '[pallet/crate/postgres :as postgres])
+(group-spec my-postgres-group
+ :extends [(postgres/server-spec {})])
+```
+
+While `server-spec` provides an all-in-one function, you can use the individual
+plan functions as you see fit.
+
+The `settings` function provides a plan function that should be called in the
+`:settings` phase. The function puts the configuration options into the pallet
+session, where they can be found by the other crate functions, or by other
+crates wanting to interact with postgres.
+
+The `install` function is responsible for actually installing postgres.
+
+The `configure` function writes the postgres configuration file, using the form
+passed to the :config key in the `settings` function.
+
+
+## Settings
+
+The postgres crate uses the following settings:
+
+* `:version`
+ a string to specify the point version of PostgreSQL (e.g., `"9.1"`). The
+ default is the version provided by the system's packaging system
+
+* `:components`
+ a set of one or more recognized keywords. The set of every component is
+ `#{:server :libs :client}`.
+
+* `:strategy`
+ allows override of the install strategy (`:packages`, `:package-source`, or
+ `:rpm`)
+
+* `:packages`
+ the packages that are used to install
+
+* `:package-source`
+ a non-default package source for the packages
+
+* `:rpm`
+ takes a map of
+ [`remote-file` options](http://palletops.com/pallet/api/0.7/pallet.action.remote-file.html)
+ specifying an RPM file to install
+
+* `:default-cluster-name`
+ name of the default cluster created by the installer
+
+* `:bin`
+ path to binaries
+
+* `:owner`
+ unix owner for Postgres files
+
+* `:postgresql_file`
+ path to `postgresql.conf`
+
+* `:has-pg-wrapper`
+ boolean flag for availability of a wrapper allowing command execution against
+ a specified cluster.
+
+* `:has-multicluster-service`
+ boolean flag specifying whether the init service is multi-cluster capable.
+
+* `:initdb-via`
+ whether to use the initdb (`:initdb`), or service (`:service`) to run initdb
+
+* `:options`
+ A map of options:
+ - `:data_directory`
+ path to storage location
+ - `:hba_file`
+ path to `pg_hba.conf` location
+ - `:ident_file`
+ path to `pg_ident.conf` location
+ - `:external_pid_file`
+ path to pid file
+ - `:unix_socket_directory`
+ path to directory for unix sockets
diff --git a/pallet.clj b/pallet.clj
new file mode 100644
index 0000000..f94ef48
--- /dev/null
+++ b/pallet.clj
@@ -0,0 +1,13 @@
+;;; Pallet project configuration file
+
+(require
+ '[pallet.crate.postgres-test
+ :refer [test-server-spec]]
+ '[pallet.crates.test-nodes :refer [node-specs]])
+
+(defproject postgres-crate
+ :provider node-specs ; supported pallet nodes
+ :groups [(group-spec "pgtest"
+ :extends [with-automated-admin-user
+ test-server-spec]
+ :roles #{:live-test :default :postgres})])
diff --git a/pom.xml b/pom.xml
deleted file mode 100644
index b90cd32..0000000
--- a/pom.xml
+++ /dev/null
@@ -1,17 +0,0 @@
-
-
- 4.0.0
-
- org.cloudhoist
- pallet-crate-pom
- 0.7.1
-
- postgres
- 0.7.0-SNAPSHOT
-
-
- scm:git:git://github.com/pallet/postgres-crate.git
- scm:git:ssh://git@github.com/pallet/postgres-crate.git
- https://github.com/pallet/postgres-crate
-
-
diff --git a/profiles.clj b/profiles.clj
new file mode 100644
index 0000000..692eee0
--- /dev/null
+++ b/profiles.clj
@@ -0,0 +1,25 @@
+{:dev
+ {:dependencies [[com.palletops/pallet "0.8.0-SNAPSHOT" :classifier "tests"]
+ [com.palletops/crates "0.1.2-SNAPSHOT"]
+ [com.palletops/pallet-test-env "RELEASE"]
+ [ch.qos.logback/logback-classic "1.0.9"]]
+ :plugins [[com.palletops/lein-pallet-crate "RELEASE"]
+ [lein-pallet-release "RELEASE"]
+ [com.palletops/lein-test-env "RELEASE"]]}
+ :provided
+ {:dependencies [[org.clojure/clojure "1.6.0"]
+ [com.palletops/pallet "0.8.0-SNAPSHOT"]]}
+ :aws {:pallet/test-env
+ {:test-specs
+ [;; {:selector :ubuntu-13-10}
+ ;; {:selector :ubuntu-13-04
+ ;; :expected [{:feature ["oracle-java-8"]
+ ;; :expected? :not-supported}]}
+ ;; {:selector :ubuntu-12-04}
+ ;; {:selector :amzn-linux-2013-092}
+ {:selector :centos-6-5}
+ ;; {:selector :debian-7-5}
+ ;; {:selector :debian-6-0}
+ ]}}
+ :vmfest {:pallet/test-env {:test-specs
+ [{:selector :ubuntu-13-04}]}}}
diff --git a/project.clj b/project.clj
new file mode 100644
index 0000000..5fe0f27
--- /dev/null
+++ b/project.clj
@@ -0,0 +1,7 @@
+(defproject com.palletops/postgres-crate "0.8.0-SNAPSHOT"
+ :description "Pallet crate to install, configure and use postgres"
+ :url "http://palletops.com"
+ :license {:name "Eclipse Public License"
+ :url "http://www.eclipse.org/legal/epl-v10.html"}
+ :scm {:url "git@github.com:pallet/runit-crate.git"}
+ :dependencies [[prismatic/schema "0.2.1"]])
diff --git a/resources/pallet_crate/postgres_crate/meta.edn b/resources/pallet_crate/postgres_crate/meta.edn
new file mode 100644
index 0000000..567ce35
--- /dev/null
+++ b/resources/pallet_crate/postgres_crate/meta.edn
@@ -0,0 +1,8 @@
+{:header "postgres"
+ :title "A Pallet crate to install and configure postgres."
+ :git-repo "https://github.com/pallet/postgres-crate"
+ :api-docs "http://palletops.com/postgres-crate/0.8/api"
+ :annotated-docs "http://palletops.com/postgres-crate/0.8/annotated/uberdoc.html"
+ :tag-prefix ""
+ :versions [{:pallet "0.8.0-beta.6" :version "0.8.0-alpha.1"}
+ {:pallet "0.7.2" :version "0.7.0-beta.2"}]}
diff --git a/src/pallet/crate/postgres.clj b/src/pallet/crate/postgres.clj
index 8574486..c7a4144 100644
--- a/src/pallet/crate/postgres.clj
+++ b/src/pallet/crate/postgres.clj
@@ -39,195 +39,92 @@ Links:
"
(:require
[pallet.action :as action]
- [pallet.action.directory :as directory]
- [pallet.action.exec-script :as exec-script]
- [pallet.action.file :as file]
- [pallet.action.package :as package]
- [pallet.action.package.debian-backports :as debian-backports]
- [pallet.action.remote-file :as remote-file]
- [pallet.action.service :as service]
+ [pallet.actions :refer [add-rpm content-options directory exec-checked-script
+ exec-script file package package-manager
+ package-source remote-file]
+ :as actions]
+ [pallet.api :refer [plan-fn] :as api]
+ [pallet.compute :as compute]
+ [pallet.core.session :refer [session]]
+ [pallet.crate :refer [assoc-settings defplan get-settings os-family
+ target-node update-settings]]
+ [pallet.crate-install :as crate-install]
[pallet.crate.etc-default :as etc-default]
- [pallet.parameter :as parameter]
+ [pallet.crate.postgres.config :as config]
+ [pallet.crate.postgres.kb :as kb]
+ [pallet.crate.service
+ :refer [supervisor-config supervisor-config-map] :as service]
[pallet.script.lib :as lib]
- [pallet.session :as session]
[pallet.stevedore :as stevedore]
- [pallet.thread-expr :as thread-expr]
+ [pallet.node :refer [is-64bit?]]
+ [pallet.utils :refer [apply-map]]
[clojure.tools.logging :as logging]
[clojure.string :as string])
(:use
- pallet.thread-expr
- [pallet.action.package :only [package package-manager package-source]]
- [pallet.action.package.debian-backports :only [debian-backports-repository]]
- [pallet.core :only [server-spec]]
- [pallet.phase :only [phase-fn]]
+ [pallet.crate.package.debian-backports :only [add-debian-backports]]
[pallet.script :only [defscript]]
[pallet.version-dispatch
- :only [defmulti-version-crate defmulti-version defmulti-os-crate
- multi-version-session-method multi-version-method
- multi-os-session-method]]
- [pallet.versions :only [as-version-vector version-string]]
- [slingshot.slingshot :only [throw+]]))
+ :only [defmethod-version defmulti-version defmulti-version-plan
+ defmethod-version-plan defmulti-version-plan os-map os-map-lookup]
+ :as version-dispatch]
+ [pallet.versions :only [as-version-vector version-string]]))
+
+
+(def facility
+ "The settings facility for postgres."
+ ::postgresql)
(def ^{:private true} pallet-cfg-preamble
"# This file was auto-generated by Pallet. Do not edit it manually unless you
# know what you are doing. If you are still using Pallet, you probably want to
# edit your Pallet scripts and rerun them.\n\n")
-
(def ^{:doc "Flag for recognising changes to configuration"}
postgresql-config-changed-flag "postgresql-config")
-;;; Default Postgres package version
-(defmulti-os-crate postgres-package-version [session])
-
-(multi-os-session-method
- postgres-package-version {:os :linux}
- [os os-version session]
- [8])
-
-(multi-os-session-method
- postgres-package-version {:os :ubuntu :os-version [12]}
- [os os-version session]
- [9 1])
-
;;; Install strategy
-(defmulti-version-crate install-strategy [version session settings])
-
-(def ^{:dynamic true} *pgdg-repo-versions*
- {"9.0" "9.0-5"
- "9.1" "9.1-5"
- "9.2" "9.2-5"})
-
-(defn pgdg-url
- [version os-family]
- (format
- "http://yum.pgrpms.org/reporpms/%s/pgdg-%s%s-%s.noarch.rpm"
- version
- (name os-family)
- (string/replace version "." "")
- (*pgdg-repo-versions* version)))
-
-(multi-version-session-method
- install-strategy {:os :rh-base}
- [os os-version version session settings]
- (->
- (cond
- (:strategy settings) settings
- (:package-source settings) (assoc settings :strategy :package-source)
- :else (let [default-version (postgres-package-version session)
- target-version (:version settings)]
- (if (= (version-string default-version) target-version)
- (assoc settings
- :strategy :packages
- :packages (map
- #(str "postgresql-" (name %))
- (:components settings #{:server :libs}))
- :layout :rh-base)
- (assoc settings
- :strategy :rpm-repo
- :rpm {:name "pgdg.rpm"
- :url (pgdg-url (version-string version)
- (if (= os :rhel) "redhat" os))}
- :packages (map
- #(str "postgresql"
- (string/replace target-version "." "")
- "-" (name %))
- (:components settings #{:server :libs}))
- :layout :pgdg))))))
-
-(multi-version-session-method
- install-strategy {:os :debian}
- [os os-version version session settings]
- (->
- (cond
- (:strategy settings) settings
- (:package-source settings) (assoc settings :strategy :package-source)
- :else (let [default-version (postgres-package-version session)
- target-version (:version settings)]
- (if (= (version-string default-version) target-version)
- (assoc settings
- :strategy :packages
- :packages ["postgresql"]
- :layout :debian-base)
- (assoc settings
- :strategy :package-source
- :package-source (debian-backports-repository)
- :packages ["libpq5" (str "postgresql-" target-version)]
- :layout :debian-base))))))
-
-(multi-version-session-method
- install-strategy {:os :ubuntu}
- [os os-version version session settings]
- (->
- (cond
- (:strategy settings) settings
- (:package-source settings) (assoc settings :strategy :package-source)
- :else (let [default-version (postgres-package-version session)
- target-version (:version settings)]
- (if (= (version-string default-version) target-version)
- (assoc settings
- :strategy :packages
- :packages ["postgresql"]
- :layout :debian-base)
- (assoc settings
- :strategy :package-source
- :package-source {:name "Martin Pitt backports"
- :aptitude {:url "ppa:pitti/postgresql"}
- :apt {:url "ppa:pitti/postgresql"}}
- :packages [(str "postgresql-" target-version)]
- :layout :debian-base))))))
-
-(multi-version-session-method
- install-strategy {:os :arch}
- [os os-version version session settings]
- (->
- (cond
- (:strategy settings) settings
- (:package-source settings) (assoc settings :strategy :package-source)
- :else (let [default-version (postgres-package-version session)
- target-version (:version settings)]
- (if (= (version-string default-version) target-version)
- (assoc settings
- :strategy :packages
- :packages ["postgresql"]
- :layout :arch)
- (throw+
- {:reason :no-install-strategy}
- "No install strategy for postgres %s on %s %s"
- version os os-version))))))
-
-;;; Dispatch to install strategy
-(defmulti install-method (fn [session settings] (:strategy settings)))
-
-(defmethod install-method :packages [session settings]
- (reduce package session (:packages settings)))
-
-(defmethod install-method :package-source
- [session {:keys [package-source packages] :as settings}]
- (->
- session
- (apply-map-> package/package-source (:name package-source) package-source)
- (package/package-manager :update)
- (when-> (= package-source :debian-backports)
- (debian-backports/add-debian-backports)
- (package/package-manager :update))
- (for-> [pkg packages] (package pkg))))
-
-(defmethod install-method :rpm
- [session {:keys [rpm] :as settings}]
- (->
- session
- (action/with-precedence {:always-before `package/package}
- (apply-map-> package/add-rpm (:name rpm) rpm))))
-
-(defmethod install-method :rpm-repo
- [session {:keys [rpm packages] :as settings}]
- (->
- session
- (action/with-precedence {:always-before `package/package}
- (apply-map-> package/add-rpm (:name rpm) rpm))
- (for-> [pkg packages] (package pkg))))
-
+(defn postgres-rpm-settings
+ "Returns a settings map for install via the Postgres RPM repository."
+ [version components os-family os-version arch]
+ (let [arch (if (is-64bit? (target-node)) "x86_64" "i386")]
+ {:install-strategy :rpm-repo
+ :rpm {:name "pgdg.rpm"
+ :url (kb/pgdg-url
+ (version-string version) os-family os-version arch)}
+ :packages (kb/pgdg-packages
+ (version-string version)
+ components)
+ :layout :pgdg}))
+
+(defn postgres-apt-settings
+ [version]
+ {:install-strategy :package-source
+ :package-source
+ {:name "Postgres Apt"
+ :aptitude kb/postgres-apt
+ :apt kb/postgres-apt}
+ :packages (kb/postgres-apt-packages (version-string version))
+ :layout :debian-base})
+
+(defn packages-settings
+ [version components]
+ {:install-strategy :packages
+ :packages (kb/package-names
+ (os-family)
+ (version-string version)
+ components)})
+
+(defmulti-version-plan install-strategy
+ ;; Default install strategy, if none supplied.
+ [version settings])
+
+(defmethod-version-plan install-strategy {:os :rh-base}
+ [os os-version version settings]
+ (packages-settings version nil))
+
+(defmethod-version-plan install-strategy {:os :debian-base}
+ [os os-version version settings]
+ (packages-settings version nil))
;;; Default settings
(def default-settings-map
@@ -239,7 +136,8 @@ Links:
:shared_buffers "24MB"
:log_line_prefix "%t "
:datestyle "iso, ymd"
- :default_text_search_config "pg_catalog.english"}
+ :default_text_search_config "pg_catalog.english"
+ :logging_collector "on"}
:permissions [["local" "all" "postgres" "ident" ""]
["local" "postgres" "postgres" "ident" ""]]
:start {:start :auto}
@@ -266,222 +164,6 @@ Links:
[:permissions]))))
settings))
-(defmulti default-settings
- "Determine the default settings for the specified "
- (fn [session os-family layout settings]
- layout))
-
-(defn base-settings [session]
- {:service "postgresql"
- :owner "postgres"
- :initdb-via :initdb
- :options {:external_pid_file (str (stevedore/script (~lib/pid-root))
- "/postgresql.pid")}})
-
-(defmethod default-settings :debian-base
- [session os-family layout settings]
- (let [version (:version settings)]
- (merge-settings
- (base-settings session)
- {:default-cluster-name "main"
- :bin (format "/usr/lib/postgresql/%s/bin/" version)
- :share (format "/usr/lib/postgresql/%s/share/" version)
- :wal_directory (format "/var/lib/postgresql/%s/%%s/archive" version)
- :postgresql_file (format
- "/etc/postgresql/%s/%%s/postgresql.conf" version)
- :has-pg-wrapper true
- :has-multicluster-service true
- :options
- {:data_directory (format "/var/lib/postgresql/%s/%%s" version)
- :hba_file (format "/etc/postgresql/%s/%%s/pg_hba.conf" version)
- :ident_file (format "/etc/postgresql/%s/%%s/pg_ident.conf" version)
- :external_pid_file (format "/var/run/postgresql/%s-%%s.pid" version)
- :unix_socket_directory "/var/run/postgresql"}})))
-
-(defmethod default-settings :rh-base
- [session os-family layout settings]
- (let [version (:version settings)]
- (merge-settings
- (base-settings session)
- {:default-cluster-name "data"
- :wal_directory (format "/var/lib/pgsql/%s/%%s/archive" version)
- :postgresql_file (format "/var/lib/pgsql/%s/%%s/postgresql.conf" version)
- :options
- {:data_directory (format "/var/lib/pgsql/%s/%%s" version)
- :hba_file (format "/var/lib/pgsql/%s/%%s/pg_hba.conf" version)
- :ident_file (format "/var/lib/pgsql/%s/%%s/pg_ident.conf" version)
- :external_pid_file (format "/var/run/postmaster-%s-%%s.pid" version)}})))
-
-(defmethod default-settings :pgdg
- [session os-family package-source settings]
- (let [version (:version settings)]
- (merge-settings
- (base-settings session)
- (default-settings session os-family :rh-base settings)
- {:bin (format "/usr/pgsql-%s/bin/" version)
- :share (format "/usr/pgsql-%s/share/" version)
- :default-cluster-name "data"
- :service (str "postgresql-" version "-%s")
- :default-service (str "postgresql-" version)
- :use-port-in-pidfile true
- :wal_directory (format "/var/lib/pgsql/%s/%%s/archive" version)
- :postgresql_file (format "/var/lib/pgsql/%s/%%s/postgresql.conf" version)
- :options
- {:data_directory (format "/var/lib/pgsql/%s/%%s" version)
- :hba_file (format "/var/lib/pgsql/%s/%%s/pg_hba.conf" version)
- :ident_file (format "/var/lib/pgsql/%s/%%s/pg_ident.conf" version)}})))
-
-(defmethod default-settings :arch
- [session os-family package-source settings]
- (let [version (:version settings)]
- (merge-settings
- (base-settings session)
- {:components []
- :default-cluster-name "data"
- :initdb-via :initdb
- :wal_directory "/var/lib/postgres/%%s/archive/"
- :postgresql_file "/var/lib/postgres/%%s/postgresql.conf"
- :options
- {:data_directory "/var/lib/postgres/%%s/"
- :hba_file "/var/lib/postgres/%%s/pg_hba.conf"
- :ident_file "/var/lib/postgres/%%s/pg_ident.conf"}})))
-
-;;; pg_hba.conf
-
-(def ^{:private true}
- auth-methods #{"trust" "reject" "md5" "password" "gss" "sspi" "krb5"
- "ident" "ldap" "radius" "cert" "pam"})
-(def ^{:private true}
- ip-addr-regex #"[0-9]{1,3}.[0-9]{1,3}+.[0-9]{1,3}+.[0-9]{1,3}+")
-
-(defn- valid-hba-record?
- "Takes an hba-record as input and minimally checks that it could be a valid
- record."
- [{:keys [connection-type database user auth-method address ip-mask]
- :as record-map}]
- (and (#{"local" "host" "hostssl" "hostnossl"} (name connection-type))
- (every? #(not (nil? %)) [database user auth-method])
- (auth-methods (name auth-method))))
-
-(defn- vector-to-map
- [record]
- (case (name (first record))
- "local" (apply
- hash-map
- (interleave
- [:connection-type :database :user :auth-method
- :auth-options]
- record))
- ("host"
- "hostssl"
- "hostnossl") (let [[connection-type database user address
- & remainder] record]
- (if (re-matches
- ip-addr-regex (first remainder))
- ;; Not nil so must be an IP mask.
- (apply
- hash-map
- (interleave
- [:connection-type :database :user
- :address :ip-mask :auth-method
- :auth-options]
- record))
- ;; Otherwise, it may be an auth-method.
- (if (auth-methods
- (name (first remainder)))
- (apply
- hash-map
- (interleave
- [:connection-type :database :user
- :address :auth-method
- :auth-options]
- record))
- (throw+
- {:type :postgres-invalid-hba-record
- :message
- (format
- "The fifth item in %s does not appear to be an IP mask or auth method."
- (pr-str record))}))))
- (throw+
- {:type :postgres-invalid-hba-record
- :message (format
- "The first item in %s is not a valid connection type."
- (name record))})))
-
-(defn- record-to-map
- "Takes a record given as a map or vector, and turns it into the map version."
- [record]
- (cond
- (map? record) record
- (vector? record) (vector-to-map record)
- :else
- (throw+
- {:type :postgres-invalid-hba-record
- :message (format "The record %s must be a vector or map." (name record))})))
-
-(defn- format-auth-options
- "Given the auth-options map, returns a string suitable for inserting into the
- file."
- [auth-options]
- (string/join "," (map #(str (first %) "=" (second %)) auth-options)))
-
-(defn- format-hba-record
- [record]
- (let [record-map (record-to-map record)
- record-map (assoc record-map :auth-options
- (format-auth-options (:auth-options record-map)))
- ordered-fields (map #(% record-map "")
- [:connection-type :database :user :address :ip-mask
- :auth-method :auth-options])
- ordered-fields (map name ordered-fields)]
- (if (valid-hba-record? record-map)
- (str (string/join "\t" ordered-fields) "\n"))))
-
-;;; postgresql.conf
-
-(defn database-data-directory
- "Given a settings map and a database name, return the data directory
- for the database."
- [settings cluster]
- (format "%s/%s/recovery.conf" (-> settings :options :data_directory) cluster))
-
-(defn- parameter-escape-string
- "Given a string, escapes any single-quotes."
- [string]
- (apply str (replace {\' "''"} string)))
-
-(defn- format-parameter-value
- [value]
- (cond (number? value)
- (str value)
- (string? value)
- (str "'" value "'")
- (vector? value)
- (str "'" (string/join "," (map name value)) "'")
- (or (= value true) (= value false))
- (str value)
- :else
- (throw+
- {:type :postgres-invalid-parameter
- :message (format
- (str
- "Parameters must be numbers, strings, or vectors of such. "
- "Invalid value %s") (pr-str value))
- :value value})))
-
-(defn- format-parameter
- "Given a key/value pair in a vector, formats it suitably for the
- postgresql.conf file.
- The value should be either a number, a string, or a vector of such."
- [[key value]]
- (let [key-str (name key)
- parameter-str (format-parameter-value value)]
- (str key-str " = " parameter-str "\n")))
-
-(defn- format-start
- [[key value]]
- (name value))
-
;;; database cluster variants
(defn hot-standby-master
@@ -551,61 +233,56 @@ Links:
(defn settings-for-cluster
"Returns the settings for the specified cluster"
- [session cluster & {:keys [instance]}]
+ [cluster {:keys [instance-id] :as options}]
(get-in
- (parameter/get-target-settings session :postgresql instance)
+ (get-settings facility options)
[:clusters (keyword cluster)]))
(defn check-settings
"Check that settings are valid"
- [session settings cluster-settings cluster & keys]
- (let [error-fn (fn [session ^String message]
+ [settings cluster-settings cluster & keys]
+ (let [error-fn (fn [^String message]
(logging/error (format message cluster settings))
- (assert false)
- session)
+ (assert false))
missing-keys (remove #(get-in cluster-settings %) keys)]
- (->
- session
- (thread-expr/when->
- (not settings)
+ (when (not settings)
(error-fn "No settings found %s %s"))
- (thread-expr/when->
- (not cluster-settings)
+ (when (not cluster-settings)
(error-fn "No cluster settings found %s %s"))
- (thread-expr/when->
- (seq missing-keys)
- (error-fn (format "Missing keys %s %%s %%s" (vec missing-keys)))))))
+ (when (seq missing-keys)
+ (error-fn (format "Missing keys %s %%s %%s" (vec missing-keys))))))
(defn conf-file
"Generates a postgresql configuration file"
- [session file-keys values-kw formatter & {:keys [instance cluster]}]
- (let [settings (parameter/get-target-settings session :postgresql instance)
+ [file-keys values-kw formatter {:keys [instance-id cluster] :as options}]
+ (let [settings (get-settings facility options)
cluster (or cluster (:default-cluster-name settings))
- cluster-settings (settings-for-cluster
- session cluster :instance instance)
+ cluster-settings (settings-for-cluster cluster options)
conf-path (get-in cluster-settings file-keys)
- hba-contents (apply str pallet-cfg-preamble
- (map formatter (values-kw cluster-settings)))]
- (->
- session
- (check-settings settings cluster-settings cluster file-keys)
- (directory/directory
- (stevedore/script @(~lib/dirname ~conf-path))
- :owner (:owner settings "postgres") :mode "0700" :path true)
- (remote-file/remote-file
- conf-path
- :content hba-contents
- :literal true
- :flag-on-changed postgresql-config-changed-flag
- :owner (:owner settings)))))
+ hba-contents (str pallet-cfg-preamble
+ (formatter (values-kw cluster-settings)))]
+ (check-settings settings cluster-settings cluster file-keys)
+ (directory
+ (stevedore/script @(~lib/dirname ~conf-path))
+ :owner (:owner settings "postgres") :mode "0700" :path true)
+ (remote-file
+ conf-path
+ :content hba-contents
+ :literal true
+ :flag-on-changed postgresql-config-changed-flag
+ :owner (:owner settings))
+ (when-let [t (:selunix-file-t settings)]
+ (exec-checked-script
+ (str "SELinux chcon " conf-path " type " t)
+ (lib/selinux-file-type ~conf-path ~t)))))
(defn default-cluster-name
"Returns the default cluster name"
- [session & {:keys [instance]}]
- (let [settings (parameter/get-target-settings session :postgresql instance)]
+ [& {:keys [instance-id] :as options}]
+ (let [settings (get-settings facility options)]
(:default-cluster-name settings)))
-;;; Crate functions
+;;; # Crate functions
(defn settings-map
"Build a settings map for postgresql.
@@ -631,65 +308,64 @@ Links:
`settings`.
Options:
- - instance Specify the postgres instance to use for the cluster
+ - instance-id Specify the postgres instance to use for the cluster
- variant Specify a variant for the cluster. Current options are
:hot-standby-master and :hot-standby-replica
For variant :hot-standby-replica, you will need to pass :primary_conninfo
in the `settings-map`"
- [session cluster-name settings-map & {:keys [instance variant]}]
- (let [settings (parameter/get-target-settings session :postgresql instance)
+ [cluster-name settings-map & {:keys [instance-id variant] :as options}]
+ (let [settings (get-settings facility options)
settings (cluster-settings-with-defaults
cluster-name settings-map settings)
settings (case variant
:hot-standby-master (hot-standby-master settings)
:hot-standby-replica (hot-standby-replica settings)
settings)]
- (parameter/update-target-settings
- session :postgresql instance
+ (logging/debugf "Postgresql cluster %s settings %s" cluster-name settings)
+ (update-settings
+ facility instance-id
assoc-in [:clusters (keyword cluster-name)]
settings)))
-(defn postgres-settings
+;; (defn base-distribution
+;; "Base distribution of the target-node."
+;; []
+;; (compute/base-distribution (target-node)))
+
+(defn settings
"Add postgresql settings to the session map."
- [session
- {:keys [version]
- :or {version (version-string (postgres-package-version session))}
- :as settings}
- & {:keys [instance]}]
- (let [settings (assoc settings :version version)
- settings (install-strategy session version settings)
+ [{:keys [instance-id version]
+ :or {version (version-string (os-map-lookup @kb/postgres-package-version))}
+ :as settings}]
+ (let [options (select-keys settings [:instance-id])
+ settings (-> settings
+ (assoc :version version)
+ (dissoc :instance-id))
+ settings (if (:install-strategy settings)
+ settings
+ (merge (install-strategy version settings) settings))
settings (merge-settings
- (default-settings
- session
- (session/base-distribution session)
- (:layout settings) settings)
+ (kb/layout-settings
+ (os-family) (:layout settings (os-family)) version)
settings)
- old-settings (parameter/get-target-settings
- session :postgresql instance nil)]
+ old-settings (get-settings facility options)]
(logging/debugf "Postgresql Settings %s" settings)
- (->
- session
- (parameter/assoc-target-settings
- :postgresql instance
- (assoc settings :clusters (:clusters old-settings)))
- (thread-expr/when-let->
- [cluster-name (:default-cluster-name settings)]
- (cluster-settings cluster-name {} :instance instance)))))
+ (assoc-settings
+ facility (assoc settings :clusters (:clusters old-settings))
+ options)
+ (when-let [cluster-name (:default-cluster-name settings)]
+ (cluster-settings cluster-name {} :instance-id instance-id))))
-(defn install-postgres
+;;; ## Install
+(defn install
"Install postgres."
- [session & {:keys [instance]}]
- (let [os-family (session/os-family session)
- settings (parameter/get-target-settings session :postgresql instance)
- packages (:packages settings)
- package-source (:package-source settings)
- version (:version settings)]
- (logging/debugf
- "postgresql %s from %s packages [%s]"
- version (:name package-source) (string/join ", " packages))
- (install-method session settings)))
+ [{:keys [instance-id] :as options}]
+ (logging/debugf "install postgresql")
+ (crate-install/install facility instance-id))
+
+;;; ## Configure
(defn hba-conf
"Generates a pg_hba.conf file from the arguments. Each record is either a
@@ -705,33 +381,27 @@ Links:
Options:
:cluster The database cluster to use
- :instance The postgres instance to use"
- [session & {:keys [instance cluster]}]
- (conf-file
- session [:options :hba_file] :permissions format-hba-record
- :instance instance :cluster cluster))
+ :instance-id The postgres instance to use"
+ [{:keys [instance-id cluster] :as options}]
+ (conf-file [:options :hba_file] :permissions config/hba options))
(defn postgresql-conf
"Generates a postgresql.conf file from the arguments.
Options:
:cluster The database cluster to use
- :instance The postgres instance to use"
- [session & {:keys [instance cluster]}]
- (conf-file
- session [:postgresql_file] :options format-parameter
- :instance instance :cluster cluster))
+ :instance-id The postgres instance to use"
+ [{:keys [instance-id cluster] :as options}]
+ (conf-file [:postgresql_file] :options config/conf options))
(defn recovery-conf
"Generates a recovery.conf file from the arguments.
Options:
:cluster The database cluster to use
- :instance The postgres instance to use"
- [session & {:keys [instance cluster]}]
- (conf-file
- session [:recovery_file] :recovery format-parameter
- :instance instance :cluster cluster))
+ :instance-id The postgres instance to use"
+ [{:keys [instance-id cluster] :as options}]
+ (conf-file [:recovery_file] :recovery config/conf options))
(defn start-conf
"Generates a start.conf file from the arguments. This is debian specific. See
@@ -739,11 +409,9 @@ Links:
Options:
:cluster The database cluster to use
- :instance The postgres instance to use"
- [session & {:keys [instance cluster]}]
- (conf-file
- session [:start_file] :start format-start
- :instance instance :cluster cluster))
+ :instance-id The postgres instance to use"
+ [{:keys [instance-id cluster] :as options}]
+ (conf-file [:start_file] :start config/start options))
(defn install-service
"Generates a start.conf file from the arguments. This is specific to
@@ -752,65 +420,103 @@ Links:
Options:
:cluster The database cluster to use
- :instance The postgres instance to use"
- [session & {:keys [instance cluster]}]
- (let [settings (parameter/get-target-settings session :postgresql instance)]
- (->
- session
- (thread-expr/for->
- [cluster (keys (:clusters settings))]
- (thread-expr/let->
- [cluster-name (name cluster)
- cluster-settings (settings-for-cluster session cluster-name)]
- (thread-expr/when->
- (not= cluster-name (:default-cluster-name settings))
- (service/init-script
- (:service cluster-settings)
- :remote-file (service/init-script-path (:default-service settings)))
- (etc-default/write
- (str "pgsql/" (:service cluster-settings))
- :PGDATA (-> cluster-settings :options :data_directory)
- :PGPORT (-> cluster-settings :options :port))
- (thread-expr/if->
- (= :auto (-> cluster-settings :start :start))
- (service/service (:service cluster-settings) :action :enable)
- (service/service (:service cluster-settings) :action :disable))))))))
+ :instance-id The postgres instance to use"
+ [{:keys [instance-id cluster] :as options}]
+ (let [settings (get-settings facility options)]
+ (doseq [cluster (keys (:clusters settings))]
+ (let [cluster-name (name cluster)
+ cluster-settings (settings-for-cluster cluster-name options)]
+ (when (not= cluster-name (:default-cluster-name settings))
+ ;; TODO
+ ;; (service/init-script
+ ;; (:service cluster-settings)
+ ;; :remote-file (service/init-script-path (:default-service settings)))
+ (etc-default/write
+ (str "pgsql/" (:service cluster-settings))
+ :PGDATA (-> cluster-settings :options :data_directory)
+ :PGPORT (-> cluster-settings :options :port))
+ ;; TODO
+ ;; (if (= :auto (-> cluster-settings :start :start))
+ ;; (service/service (:service cluster-settings) :action :enable)
+ ;; (service/service (:service cluster-settings) :action :disable))
+ )))))
(defn service-config
"Configure the service architecture."
- [session & {:keys [instance cluster]}]
- (let [settings (parameter/get-target-settings session :postgresql instance)]
+ [{:keys [instance-id cluster] :as options}]
+ (let [settings (get-settings facility options)]
(if (:has-multicluster-service settings)
- (start-conf session :instance instance :cluster cluster)
- (install-service session :instance instance :cluster cluster))))
-
-(declare service)
+ (start-conf options)
+ (install-service options))))
+
+(defn- port-config* [settings]
+ (when-let [t (:selunix-port-t settings)]
+ (let [p (-> settings :options :port)]
+ (exec-checked-script
+ (str "SELinux manage port " p " type " t)
+ (if (&& (lib/has-command? semanage)
+ (&& (directory? "/etc/selinux")
+ (file-exists? "/selinux/enforce")))
+ (if (pipe ("semanage" port -l) ("fgrep" ~p))
+ ("semanage" port -m -t ~t -p tcp ~p)
+ ("semanage" port -a -t ~t -p tcp ~p)))))))
+
+(defn port-config
+ "Manage the SELinux port type of the configured port"
+ [{:keys [instance-id cluster] :as options}]
+ (let [settings (get-settings facility options)]
+ (if (:has-multicluster-service settings)
+ (doseq [cluster (keys (:clusters settings))
+ :let [cluster-name (name cluster)
+ cluster-settings (settings-for-cluster
+ cluster-name options)]]
+ (port-config* cluster-settings))
+ (port-config* settings))))
+
+(defn dir-config*
+ [{:keys [owner selunix-file-t options] :as settings}]
+ (let [d (:unix_socket_directory options)]
+ (directory d :owner owner)
+ (when selunix-file-t
+ (exec-checked-script
+ (str "SELinux chcon " d " type " selunix-file-t)
+ (lib/selinux-file-type ~d ~selunix-file-t)))))
+
+(defn dir-config
+ "Ensure required directories exist"
+ [{:keys [instance-id cluster] :as options}]
+ (let [settings (get-settings facility options)]
+ (if (:has-multicluster-service settings)
+ (doseq [cluster (keys (:clusters settings))
+ :let [cluster-name (name cluster)
+ cluster-settings (settings-for-cluster
+ cluster-name options)]]
+ (dir-config* settings))
+ (dir-config* settings))))
(defn initdb
"Initialise a cluster"
- [session & {:keys [instance cluster]}]
- (let [settings (parameter/get-target-settings session :postgresql instance)
+ [{:keys [instance-id cluster] :as options}]
+ (let [settings (get-settings facility options)
cluster (or cluster (:default-cluster-name settings))
initdb-via (:initdb-via settings :initdb)
- cluster-settings (settings-for-cluster
- session cluster :instance instance)
+ cluster-settings (settings-for-cluster cluster options)
data-dir (-> cluster-settings :options :data_directory)]
(case initdb-via
- :service (service session :action :initdb)
- :initdb (->
- session
- (directory/directory
- data-dir
- :owner (:owner settings "postgres")
- :mode "0700"
- :path true)
- (exec-script/exec-checked-script
- "initdb"
- (if (not (file-exists? ~(str data-dir "/PG_VERSION")))
- (sudo
- -u ~(:owner settings "postgres")
- (str ~(or (:bin settings) "") initdb)
- -D ~data-dir)))))))
+ :service (actions/service :action :initdb)
+ :initdb (do
+ (directory
+ data-dir
+ :owner (:owner settings "postgres")
+ :mode "0700"
+ :path true)
+ (exec-checked-script
+ "initdb"
+ (if (not (file-exists? ~(str data-dir "/PG_VERSION")))
+ ("sudo"
+ -u ~(:owner settings "postgres")
+ (lib/file ~(:bin settings) initdb)
+ -D ~data-dir)))))))
;;; Scripts
@@ -825,52 +531,51 @@ Links:
user. Default: postgres
:db-name database - the name of the database to connect to
:cluster cluster-name - the name of the cluster to connect to
- :instance instance-name - the instance (pg install) to use
+ :instance-id instance-name - the instance (pg install) to use
:ignore-result - Ignore any error return value out of psql
:title string - A title to be used in script output."
- [session & {:keys [as-user instance cluster db-name ignore-result show-stdout
- title]
- :or {show-stdout true}
- :as options}]
- (let [settings (parameter/get-target-settings session :postgresql instance)
+ [& {:keys [as-user instance-id cluster db-name ignore-result show-stdout
+ title]
+ :or {show-stdout true}
+ :as options}]
+ (let [settings (get-settings facility options)
cluster (or cluster (:default-cluster-name settings))
- cluster-settings (settings-for-cluster session cluster)
+ cluster-settings (settings-for-cluster cluster options)
as-user (or as-user (-> settings :owner))
file (str (stevedore/script @TMPDIR:-/tmp) "/"
(gensym "postgresql") ".sql")]
- (-> session
- (apply-map->
- remote-file/remote-file
- file
- :no-versioning true
- :owner as-user
- (select-keys options remote-file/content-options))
- (exec-script/exec-checked-script
- ;; Note that we stuff all output. This is because certain commands in
- ;; PostgreSQL are idempotent but spit out an error and an error exit
- ;; anyways (eg, create database on a database that already exists does
- ;; nothing, but is counted as an error).
- ;; Subshell used to isolate any cd
- (str "psql script" (if title (str " - " title) ""))
- ("(\n"
- cd (~lib/user-home ~as-user) "&&"
- sudo "-u" ~as-user
- ~(if (:has-pg-wrapper settings)
- ""
- (format
- "env PGDATA=%s PGPORT=%s"
- (-> cluster-settings :options :data_directory)
- (-> cluster-settings :options :port)))
- psql
- ~(if (:has-pg-wrapper settings)
- (format "--cluster %s/%s" (:version settings) cluster)
- "")
- ~(if db-name (str "-d " db-name) "")
- "-f" ~file
- ~(if show-stdout "" ">-")
- ~(if ignore-result "2>-" "")
- ~(if ignore-result "|| true" "") "\n )"))
- (remote-file/remote-file file :action :delete))))
+
+ (apply-map remote-file file
+ :no-versioning true
+ :owner as-user
+ (select-keys options content-options))
+ (exec-checked-script
+ ;; Note that we stuff all output. This is because certain commands in
+ ;; PostgreSQL are idempotent but spit out an error and an error exit
+ ;; anyways (eg, create database on a database that already exists does
+ ;; nothing, but is counted as an error).
+ ;; Subshell used to isolate any cd
+ (str "psql script" (if title (str " - " title) ""))
+ ("(\n"
+ cd (~lib/user-home ~as-user) "&&"
+ sudo "-u" ~as-user
+ ~(if (:has-pg-wrapper settings)
+ ""
+ (format
+ "env PGHOST=%s PGDATA=%s PGPORT=%s"
+ (-> cluster-settings :options :unix_socket_directory)
+ (-> cluster-settings :options :data_directory)
+ (-> cluster-settings :options :port)))
+ psql
+ ~(if (:has-pg-wrapper settings)
+ (format "--cluster %s/%s" (:version settings) cluster)
+ "")
+ ~(if db-name (str "-d " db-name) "")
+ "-f" ~file
+ ~(if show-stdout "" ">-")
+ ~(if ignore-result "2>-" "")
+ ~(if ignore-result "|| true" "") "\n )"))
+ (remote-file file :action :delete)))
(defn create-database
"Create a database if it does not exist.
@@ -882,19 +587,19 @@ Links:
Example: (create-database
\"my-database\" :db-parameters [:encoding \"'LATIN1'\"])"
- [session db-name & rest]
- (let [{:keys [db-parameters db] :as options} rest
- db-parameters-str (string/join " " (map name db-parameters))]
+ [db-name & {:keys [db-parameters db] :as options}]
+ (let [db-parameters-str (string/join " " (map name db-parameters))]
;; Postgres simply has no way to check if a database exists and issue a
;; "CREATE DATABASE" only in the case that it doesn't. That would require a
;; function, but create database can't be done within a transaction, so
;; you're screwed. Instead, we just use the fact that trying to create an
;; existing database does nothing and stuff the output/error return.
- (apply postgresql-script
- session
- :content (format "CREATE DATABASE %s %s;" db-name db-parameters-str)
- :literal true
- (conj (vec rest) :ignore-result true))))
+ (apply-map
+ postgresql-script
+ :content (format "CREATE DATABASE %s %s;" db-name db-parameters-str)
+ :literal true
+ :ignore-result true
+ options)))
;; This is a format string that generates a temporary PL/pgsql function to
;; check if a given role exists, and if not create it. The first argument
@@ -933,20 +638,19 @@ END$$;"
Example (create-role
\"myuser\" :user-parameters [:encrypted :password \"'mypasswd'\"])"
- [session username & rest]
- (let [{:keys [user-parameters db instance] :as options} rest
- settings (parameter/get-target-settings session :postgresql instance)
+ [username & {:keys [user-parameters db instance-id] :as options}]
+ (let [settings (get-settings facility options)
user-parameters-str (string/join " " (map name user-parameters))]
- (apply postgresql-script
- session
- :content (format
- (create-role-pgsql (:version settings))
- username
- (if (string/blank? user-parameters-str)
- ""
- (str "WITH " user-parameters-str)))
- :literal true
- rest)))
+ (apply-map
+ postgresql-script
+ :content (format
+ (create-role-pgsql (:version settings))
+ username
+ (if (string/blank? user-parameters-str)
+ ""
+ (str "WITH " user-parameters-str)))
+ :literal true
+ options)))
(defn service
@@ -957,35 +661,29 @@ END$$;"
Other options are as for `pallet.action.service/service`. The service
name is looked up in the request parameters."
- [session & {:keys [action if-config-changed if-flag instance] :as options}]
- (let [settings (parameter/get-target-settings session :postgresql instance)
- service (:service settings)
+ [& {:keys [action if-config-changed if-flag instance-id] :as options}]
+ (let [settings (get-settings facility options)
+ service-name (:service settings)
options (if if-config-changed
(assoc options :if-flag postgresql-config-changed-flag)
options)]
- (->
- session
- (thread-expr/if->
- (:has-multicluster-service settings)
- (thread-expr/apply-map-> service/service service options)
- (thread-expr/for->
- [cluster (keys (:clusters settings))]
- (thread-expr/let->
- [cluster-name (name cluster)
- cluster-settings (settings-for-cluster session cluster-name)]
- (thread-expr/if->
- (= :auto (-> cluster-settings :start :start))
- (thread-expr/apply-map->
- service/service (:service cluster-settings) options))))))))
+ (if (:has-multicluster-service settings)
+ (apply-map actions/service service-name options)
+ (doseq [cluster (keys (:clusters settings))]
+ (let [cluster-name (name cluster)
+ cluster-settings (settings-for-cluster cluster-name options)]
+ (if (= :auto (-> cluster-settings :start :start))
+ (apply-map
+ actions/service (:service cluster-settings) options)))))))
(defn controldata-script
- [session {:keys [as-user instance cluster] :as options}]
- (let [settings (parameter/get-target-settings session :postgresql instance)
+ [{:keys [as-user instance-id cluster] :as options}]
+ (let [settings (get-settings facility options)
cluster (or cluster (:default-cluster-name settings))
- cluster-settings (settings-for-cluster session cluster)
+ cluster-settings (settings-for-cluster cluster options)
as-user (or as-user (-> settings :owner))]
(stevedore/script
- (sudo "-u" ~as-user
+ ("sudo" "-u" ~as-user
~(if-let [bin (:bin settings)]
(str bin "/pg_controldata")
"pg_controldata")
@@ -993,28 +691,39 @@ END$$;"
(defn controldata
"Execute pg_controldata."
- [session & {:keys [as-user instance cluster] :as options}]
- (-> session
- (exec-script/exec-checked-script
- "pg_controldata"
- (~controldata-script session options))))
+ [session & {:keys [as-user instance-id cluster] :as options}]
+ (exec-checked-script
+ "pg_controldata"
+ (~controldata-script session options)))
(defn log-settings
"Log postgresql settings"
- [session & {:keys [instance level] :or {level :info}}]
- (let [settings (parameter/get-target-settings session :postgresql instance)]
- (logging/log level (format "Postgresql %s %s" (or instance "") settings))
- session))
-
-(defn postgres
- [settings]
- (server-spec
- :phases {:settings (phase-fn
- (postgres-settings (settings-map settings)))
- :configure (phase-fn
- (initdb)
- (hba-conf)
- (postgresql-conf)
- (service-config)
- (service
- :action :restart :if-config-changed true))}))
+ [& {:keys [instance-id level] :or {level :info} :as options}]
+ (let [settings (get-settings facility options)]
+ (logging/log level
+ (format "Postgresql %s %s" (or instance-id "") settings))))
+
+(defplan configure
+ [{:keys [instance-id] :as options}]
+ (initdb options)
+ (hba-conf options)
+ (postgresql-conf options)
+ (service-config options)
+ (port-config options)
+ (dir-config options))
+
+
+(defn server-spec
+ "Return a postgres server-spec using the specified `settings`."
+ [settings & {:keys [instance-id] :as options}]
+ (api/server-spec
+ :phases {:settings (plan-fn
+ (pallet.crate.postgres/settings
+ (settings-map settings)))
+ :install (plan-fn
+ (install options))
+ :configure (plan-fn
+ (configure options)
+ (service
+ :action :restart :if-config-changed true))}
+ :default-phases [:install :configure]))
diff --git a/src/pallet/crate/postgres/config.clj b/src/pallet/crate/postgres/config.clj
new file mode 100644
index 0000000..48fefd1
--- /dev/null
+++ b/src/pallet/crate/postgres/config.clj
@@ -0,0 +1,161 @@
+(ns pallet.crate.postgres.config
+ "Postgres configuration"
+ (:require
+ [clojure.string :as string :refer [join]]))
+
+;;; pg_hba.conf
+
+(def ^{:private true}
+ auth-methods #{"trust" "reject" "md5" "password" "gss" "sspi" "krb5"
+ "ident" "ldap" "radius" "cert" "pam"})
+(def ^{:private true}
+ ip-addr-regex #"[0-9]{1,3}.[0-9]{1,3}+.[0-9]{1,3}+.[0-9]{1,3}+")
+
+(defn- valid-hba-record?
+ "Takes an hba-record as input and minimally checks that it could be a valid
+ record."
+ [{:keys [connection-type database user auth-method address ip-mask]
+ :as record-map}]
+ (and (#{"local" "host" "hostssl" "hostnossl"} (name connection-type))
+ (every? #(not (nil? %)) [database user auth-method])
+ (auth-methods (name auth-method))))
+
+(defn- vector-to-map
+ [record]
+ (case (name (first record))
+ "local" (apply
+ hash-map
+ (interleave
+ [:connection-type :database :user :auth-method
+ :auth-options]
+ record))
+ ("host"
+ "hostssl"
+ "hostnossl") (let [[connection-type database user address
+ & remainder] record]
+ (if (re-matches
+ ip-addr-regex (first remainder))
+ ;; Not nil so must be an IP mask.
+ (apply
+ hash-map
+ (interleave
+ [:connection-type :database :user
+ :address :ip-mask :auth-method
+ :auth-options]
+ record))
+ ;; Otherwise, it may be an auth-method.
+ (if (auth-methods
+ (name (first remainder)))
+ (apply
+ hash-map
+ (interleave
+ [:connection-type :database :user
+ :address :auth-method
+ :auth-options]
+ record))
+ (throw
+ (ex-info
+ (format
+ "The fifth item in %s does not appear to be an IP mask or auth method."
+ (pr-str record))
+ {:type :postgres-invalid-hba-record})))))
+ (throw
+ (ex-info
+ (format
+ "The first item in %s is not a valid connection type."
+ (name record)))
+ {:type :postgres-invalid-hba-record})))
+
+(defn- record-to-map
+ "Takes a record given as a map or vector, and turns it into the map version."
+ [record]
+ (cond
+ (map? record) record
+ (vector? record) (vector-to-map record)
+ :else
+ (throw
+ (ex-info
+ (format "The record %s must be a vector or map." (name record))
+ {:type :postgres-invalid-hba-record}))))
+
+(defn- format-auth-options
+ "Given the auth-options map, returns a string suitable for inserting into the
+ file."
+ [auth-options]
+ (string/join "," (map #(str (first %) "=" (second %)) auth-options)))
+
+(defn format-hba
+ [record]
+ (let [record-map (record-to-map record)
+ record-map (assoc record-map :auth-options
+ (format-auth-options (:auth-options record-map)))
+ ordered-fields (map #(% record-map "")
+ [:connection-type :database :user :address :ip-mask
+ :auth-method :auth-options])
+ ordered-fields (map name ordered-fields)]
+ (if (valid-hba-record? record-map)
+ (str (string/join "\t" ordered-fields) "\n"))))
+
+(defn hba
+ "Return content for pg_hba.conf given a sequence of hba permission
+ entries."
+ [permissions]
+ (join (map format-hba permissions)))
+
+;;; postgresql.conf, recovery.conf
+
+(defn database-data-directory
+ "Given a settings map and a database name, return the data directory
+ for the database."
+ [settings cluster]
+ (format "%s/%s/recovery.conf" (-> settings :options :data_directory) cluster))
+
+(defn- parameter-escape-string
+ "Given a string, escapes any single-quotes."
+ [string]
+ (apply str (replace {\' "''"} string)))
+
+(defn- format-parameter-value
+ [value]
+ (cond (number? value)
+ (str value)
+ (string? value)
+ (str "'" value "'")
+ (vector? value)
+ (str "'" (string/join "," (map name value)) "'")
+ (or (= value true) (= value false))
+ (str value)
+ :else
+ (throw
+ (ex-info
+ (format
+ (str
+ "Parameters must be numbers, strings, or vectors of such. "
+ "Invalid value %s") (pr-str value))
+ {:type :postgres-invalid-parameter
+ :value value}))))
+
+(defn format-conf
+ "Given a key/value pair in a vector, formats it suitably for the
+ postgresql.conf file.
+ The value should be either a number, a string, or a vector of such."
+ [[key value]]
+ (let [key-str (name key)
+ parameter-str (format-parameter-value value)]
+ (str key-str " = " parameter-str "\n")))
+
+(defn conf
+ "Return content for postgresql.conf given a sequence of entries."
+ [entries]
+ (join (map format-conf entries)))
+
+;;; start.conf
+
+(defn format-start
+ [[key value]]
+ (name value))
+
+(defn start
+ "Return content for postgresql.conf given a sequence of entries."
+ [entries]
+ (join (map format-start entries)))
diff --git a/src/pallet/crate/postgres/kb.clj b/src/pallet/crate/postgres/kb.clj
new file mode 100644
index 0000000..227c4aa
--- /dev/null
+++ b/src/pallet/crate/postgres/kb.clj
@@ -0,0 +1,273 @@
+(ns pallet.crate.postgres.kb
+ "Knowledge base for postgres install and configuration"
+ (:require
+ [clojure.string :as string :refer [split]]
+ [pallet.version-dispatch :refer [os-map]]
+ [pallet.compute :refer [os-hierarchy]]
+ [pallet.utils :refer [deep-merge]]
+ [schema.core :as schema :refer [enum maybe validate]]))
+
+(def Layout
+ {:bin String
+ :default-cluster-name String
+ ;; :default-service String
+ :has-multicluster-service schema/Bool
+ :has-pg-wrapper schema/Bool
+ :initdb-via (enum :initdb :service)
+ :postgresql_file String
+ :service String
+ :share String
+ :use-port-in-pidfile schema/Bool
+ :owner String
+ :wal_directory String
+ :selunix-port-t (maybe String)
+ :selunix-file-t (maybe String)
+ :options {:external_pid_file String
+ :data_directory String
+ :hba_file String
+ :ident_file String
+ :unix_socket_directory String
+ schema/Keyword schema/Any}})
+
+(defmulti layout-settings
+ "Determine the layout of packages for the specified os-family or layout."
+ (fn [os-family layout version]
+ {:pre [(keyword? layout)
+ (string? version)]}
+ layout)
+ :hierarchy #'os-hierarchy)
+
+(prefer-method layout-settings :amzn-linux :rh-base)
+
+(defn base-layout
+ "Base layout used as a default with common options."
+ []
+ {:service "postgresql"
+ :owner "postgres"
+ :has-pg-wrapper false
+ :has-multicluster-service false
+ :initdb-via :initdb
+ :use-port-in-pidfile false
+ :selunix-port-t nil
+ :selunix-file-t nil
+ :options {:external_pid_file "/var/run/postgresql.pid"}})
+
+
+;;; # System Packages
+
+;;; Default Postgres package version
+
+(def postgres-package-version
+ "Default version for distros."
+ (atom ; allow for open extension
+ (os-map
+ {{:os :linux} [8]
+ {:os :centos :os-version [6]} [8 4]
+ {:os :amzn-linux :os-version [[2013]]} [9 2]
+ {:os :debian :os-version [6]} [8 4]
+ {:os :debian :os-version [7]} [9 1]
+ {:os :debian :os-version [8]} [9 3]
+ {:os :ubuntu :os-version [[12] [13 10]]} [9 1]
+ {:os :ubuntu :os-version [[14 04]]} [9 3]})))
+
+
+;;; ## Yum system packages
+(defmulti package-names
+ "Return a sequence of package names for system packages."
+ (fn [os version components]
+ os)
+ :hierarchy #'os-hierarchy)
+
+(prefer-method package-names :amzn-linux :rh-base)
+
+(defmethod package-names :rh-base
+ [os version components]
+ {:pre [(string? version)]}
+ (conj
+ (map
+ #(format "postgresql-%s" (name %))
+ (or components #{:server :libs}))
+ "postgresql"))
+
+(defmethod package-names :amzn-linux
+ [os version components]
+ {:pre [(string? version)]}
+ (map
+ #(format "postgresql%s-%s" (first (split version #"\.")) (name %))
+ (or components #{:server :libs})))
+
+;;; ## Apt system packages
+(defmethod package-names :debian-base
+ [os version components]
+ {:pre [(string? version)]}
+ (conj
+ (map
+ #(format "postgresql-%s-%s" version (name %))
+ components)
+ (format "postgresql-%s" version)))
+
+(prefer-method package-names :amzn-linux :rh-base)
+
+;;; # Postgres RPM Repository
+
+;;; See http://yum.postgresql.org/
+
+(def ^{:dynamic true} *pgdg-repo-versions*
+ "Versions available from the postgres RPM repository."
+ {"9.0" "9.0-5"
+ "9.1" "9.1-6"
+ "9.2" "9.2-7"
+ "9.3" "9.3-1"})
+
+(defn base-name
+ [os-family]
+ (if (= os-family :fedora)
+ "fedora"
+ "redhat"))
+
+(defn base-pkg-name
+ [os-family]
+ (if (= os-family :fedora)
+ "fedora"
+ "rhel"))
+
+(defn distro-name
+ [os-family]
+ (name os-family))
+
+(def pkg-distro-names
+ {:rhel "redhat"})
+
+(defn pkg-distro-name
+ [os-family]
+ (os-family pkg-distro-names (name os-family)))
+
+(defn pgdg-url
+ [version os-family os-version arch]
+ {:pre [(string? version)
+ (#{"i386" "x86_64"} arch)]}
+ (format
+ "http://yum.postgresql.org/%s/%s/%s-%s-%s/pgdg-%s%s-%s.noarch.rpm"
+ version
+ (base-name os-family)
+ (base-pkg-name os-family) os-version arch
+ (pkg-distro-name os-family)
+ (string/replace version "." "")
+ (*pgdg-repo-versions* version)))
+
+(defn pgdg-packages
+ "Return package names for Postgres RPM repository packages, for the given
+ postgres version and sequence of component keywords."
+ [version components]
+ (map
+ #(str "postgresql" (string/replace version "." "") "-" (name %))
+ components))
+
+;;; # Postgres APT Repository
+
+;;; See http://wiki.postgresql.org/wiki/Apt
+
+(def postgres-apt
+ "Repository for postgres Apt packages."
+ {:url "http://apt.postgresql.org/pub/repos/apt/"
+ :key-url "https://www.postgresql.org/media/keys/ACCC4CF8.asc"})
+
+(defn postgres-apt-packages
+ "Return a sequence of package names for the given version."
+ [version]
+ {:pre [(string? version)]}
+ [(str "postgresql-" version)])
+
+
+(defmethod layout-settings :debian-base
+ [os-family layout version]
+ {:post [(validate Layout %)]}
+ (deep-merge
+ (base-layout)
+ {:default-cluster-name "main"
+ :bin (format "/usr/lib/postgresql/%s/bin/" version)
+ :share (format "/usr/lib/postgresql/%s/share/" version)
+ :wal_directory (format "/var/lib/postgresql/%s/%%s/archive" version)
+ :postgresql_file (format
+ "/etc/postgresql/%s/%%s/postgresql.conf" version)
+ :has-pg-wrapper true
+ :has-multicluster-service true
+ :options
+ {:data_directory (format "/var/lib/postgresql/%s/%%s" version)
+ :hba_file (format "/etc/postgresql/%s/%%s/pg_hba.conf" version)
+ :ident_file (format "/etc/postgresql/%s/%%s/pg_ident.conf" version)
+ :external_pid_file (format "/var/run/postgresql/%s-%%s.pid" version)
+ :unix_socket_directory "/var/run/postgresql"}}))
+
+(defmethod layout-settings :rh-base
+ [os-family layout version]
+ {:post [(validate Layout %)]}
+ (let [major (first (split version #"\."))]
+ (deep-merge
+ (base-layout)
+ {:bin "/usr/bin"
+ :default-cluster-name "data"
+ :share "/usr/share/pgsql"
+ :wal_directory "/var/lib/pgsql/archive"
+ :postgresql_file "/var/lib/pgsql/data/postgresql.conf"
+ :selunix-port-t "postgresql_port_t"
+ :selunix-file-t "postgresql_db_t"
+ :options
+ {:data_directory "/var/lib/pgsql/data"
+ :hba_file "/var/lib/pgsql/data/pg_hba.conf"
+ :ident_file "/var/lib/pgsql/data/pg_ident.conf"
+ :external_pid_file "/var/run/postmaster.pid"
+ :unix_socket_directory "/var/run/postgresql"}})))
+
+(defmethod layout-settings :amzn-linux
+ [os-family layout version]
+ {:post [(validate Layout %)]}
+ (let [major (first (split version #"\."))
+ data (format "/var/lib/pgsql%s/data/" major)]
+ (deep-merge
+ (base-layout)
+ {:bin "/usr/bin"
+ :default-cluster-name "data"
+ :share "/usr/share/pgsql"
+ :wal_directory (format "%s/%%s/archive" data)
+ :postgresql_file (format "%s/%%s/postgresql.conf" data)
+ :options
+ {:data_directory data
+ :hba_file (format "%s/pg_hba.conf" data)
+ :ident_file (format "%s/pg_ident.conf" data)
+ :external_pid_file (format "/var/run/postmaster-%s.pid" version)
+ :unix_socket_directory "/var/run/postgresql"}})))
+
+(defmethod layout-settings :pgdg
+ [os-family package-source version]
+ {:post [(validate Layout %)]}
+ (deep-merge
+ (base-layout)
+ (layout-settings os-family :rh-base version)
+ {:bin (format "/usr/pgsql-%s/bin/" version)
+ :share (format "/usr/pgsql-%s/share/" version)
+ :default-cluster-name "data"
+ :service (str "postgresql-" version "-%s")
+ :default-service (str "postgresql-" version)
+ :use-port-in-pidfile true
+ :wal_directory (format "/var/lib/pgsql/%s/%%s/archive" version)
+ :postgresql_file (format "/var/lib/pgsql/%s/%%s/postgresql.conf" version)
+ :options
+ {:data_directory (format "/var/lib/pgsql/%s/%%s" version)
+ :hba_file (format "/var/lib/pgsql/%s/%%s/pg_hba.conf" version)
+ :ident_file (format "/var/lib/pgsql/%s/%%s/pg_ident.conf" version)}}))
+
+(defmethod layout-settings :arch
+ [os-family package-source version]
+ {:post [(validate Layout %)]}
+ (deep-merge
+ (base-layout)
+ {:components []
+ :default-cluster-name "data"
+ :initdb-via :initdb
+ :wal_directory "/var/lib/postgres/%%s/archive/"
+ :postgresql_file "/var/lib/postgres/%%s/postgresql.conf"
+ :options
+ {:data_directory "/var/lib/postgres/%%s/"
+ :hba_file "/var/lib/postgres/%%s/pg_hba.conf"
+ :ident_file "/var/lib/postgres/%%s/pg_ident.conf"}}))
diff --git a/test/pallet/crate/postgres/config_test.clj b/test/pallet/crate/postgres/config_test.clj
new file mode 100644
index 0000000..dd01d19
--- /dev/null
+++ b/test/pallet/crate/postgres/config_test.clj
@@ -0,0 +1,10 @@
+(ns pallet.crate.postgres.config-test
+ (:require
+ [clojure.test :refer :all]
+ [pallet.crate.postgres.config :refer [conf hba]]))
+
+(deftest hba-test
+ (is (= "" (hba []))))
+
+(deftest conf-test
+ (is (= "" (conf []))))
diff --git a/test/pallet/crate/postgres/kb_test.clj b/test/pallet/crate/postgres/kb_test.clj
new file mode 100644
index 0000000..5dc21da
--- /dev/null
+++ b/test/pallet/crate/postgres/kb_test.clj
@@ -0,0 +1,21 @@
+(ns pallet.crate.postgres.kb-test
+ (:require
+ [clojure.test :refer :all]
+ [pallet.crate.postgres.kb :as kb]))
+
+;; This is brittle
+(deftest pgdg-url-test
+ (is (= "http://yum.postgresql.org/9.3/fedora/fedora-19-x86_64/pgdg-fedora93-9.3-1.noarch.rpm"
+ (kb/pgdg-url "9.3" :fedora "19" "x86_64")))
+ (is (= "http://yum.postgresql.org/9.3/fedora/fedora-20-i386/pgdg-fedora93-9.3-1.noarch.rpm"
+ (kb/pgdg-url "9.3" :fedora "20" "i386")))
+ (is (= "http://yum.postgresql.org/9.3/redhat/rhel-6-i386/pgdg-redhat93-9.3-1.noarch.rpm"
+ (kb/pgdg-url "9.3" :rhel "6" "i386")))
+ (is (= "http://yum.postgresql.org/9.3/redhat/rhel-6-x86_64/pgdg-centos93-9.3-1.noarch.rpm"
+ (kb/pgdg-url "9.3" :centos "6" "x86_64"))))
+
+(deftest layout-settings-test
+ (is
+ (->
+ (kb/layout-settings :ubuntu :debian-base "9.1")
+ :options :data_directory)))
diff --git a/test/pallet/crate/postgres/support_test.clj b/test/pallet/crate/postgres/support_test.clj
new file mode 100644
index 0000000..acc26ac
--- /dev/null
+++ b/test/pallet/crate/postgres/support_test.clj
@@ -0,0 +1,102 @@
+(ns pallet.crate.postgres.support-test
+ (:require
+ [clojure.test :refer :all]
+ [pallet.actions
+ :refer [exec-checked-script package package-manager minimal-packages]]
+ [pallet.api :refer [lift plan-fn group-spec]]
+ [pallet.core.api :refer [phase-errors]]
+ [pallet.crate.automated-admin-user :as automated-admin-user]
+ [pallet.crate.network-service :refer [wait-for-port-listen]]
+ [pallet.crate.postgres :as postgres]
+ [pallet.crates.test-nodes :as test-nodes]
+ [pallet.repl :refer [explain-session]]
+ [pallet.test-env
+ :refer [*compute-service* *node-spec-meta*
+ with-group-spec test-env unique-name]]
+ [pallet.test-env.project :as project]))
+
+(test-env test-nodes/node-specs project/project)
+
+(deftest ^:support port-listen-test
+ (let [spec (group-spec (unique-name)
+ :node-spec (:node-spec *node-spec-meta*)
+ :extends [automated-admin-user/with-automated-admin-user
+ (postgres/server-spec
+ (postgres/settings-map
+ {:options {:listen_addresses "*"}
+ :permissions
+ [{:connection-type "host"
+ :database "all"
+ :user "all"
+ :address "10.0.2.2/24"
+ :auth-method "md5"}
+ {:connection-type "host"
+ :database "all"
+ :user "all"
+ :address "192.168.56.1/24"
+ :auth-method "md5"}]}))]
+ :phases {:settings (plan-fn
+ ;; (postgres/cluster-settings
+ ;; "db1" {:options {:port 5432}})
+ )
+ :init (plan-fn
+ (postgres/create-database "db")
+ (postgres/create-role
+ "u3"
+ :user-parameters [:login :encrypted
+ :password ""'mypasswd'""]))
+ :test (plan-fn
+ (wait-for-port-listen 5432))})]
+ (with-group-spec spec
+ (let [session (lift spec
+ :phase [:install :configure :init :test]
+ :compute *compute-service*)]
+ (testing "configure postgres"
+ (is session)
+ (is (not (phase-errors session)))
+ (when (phase-errors session)
+ (explain-session session)))))))
+
+(deftest postgres
+ (let [spec (group-spec (unique-name)
+ :phases
+ {:bootstrap (plan-fn
+ (minimal-packages)
+ (package-manager :update)
+ (automated-admin-user/automated-admin-user))
+ :settings (plan-fn
+ (postgres/settings (postgres/settings-map {}))
+ (postgres/cluster-settings "db1" {:options {:port 5433}}))
+ :configure (plan-fn (postgres/install))
+ :verify (plan-fn
+ (postgres/log-settings)
+ (postgres/initdb)
+ (postgres/initdb :cluster "db1")
+ (postgres/hba-conf)
+ (postgres/hba-conf :cluster "db1")
+ (postgres/postgresql-conf)
+ (postgres/postgresql-conf :cluster "db1")
+ (postgres/service-config)
+ (postgres/service :action :restart :if-config-changed false)
+ (postgres/create-database "db")
+ (postgres/postgresql-script
+ :content "create temporary table table1 ();"
+ :show-stdout true)
+ (postgres/create-role "user1")
+ (postgres/create-database "db" :cluster "db1")
+ (postgres/create-role "user1" :cluster "db1")
+ (postgres/postgresql-script
+ :content "create temporary table table2 ();"
+ :show-stdout true :cluster "db1")
+ (wait-for-port-listen 5432)
+ (wait-for-port-listen 5433))}
+ :count 1
+ :node-spec (:node-spec *node-spec-meta*))]
+ (let [session (lift spec
+ :phase [:settings :install :configure :init :verify]
+ :compute *compute-service*)]
+ (testing "configure postgres"
+ (is session)
+ (is (not (phase-errors session)))
+ (when (phase-errors session)
+ (explain-session session))))))
diff --git a/test/pallet/crate/postgres_test.clj b/test/pallet/crate/postgres_test.clj
index f996016..f7d8d23 100644
--- a/test/pallet/crate/postgres_test.clj
+++ b/test/pallet/crate/postgres_test.clj
@@ -1,14 +1,15 @@
(ns pallet.crate.postgres-test
(:require
- [pallet.action.exec-script :as exec-script]
- [pallet.action.package :as package]
- [pallet.build-actions :as build-actions]
- [pallet.core :as core]
+ [pallet.actions
+ :refer [exec-checked-script package package-manager minimal-packages]]
+ [pallet.build-actions :refer [build-actions]]
+ [pallet.api :refer [lift node-spec plan-fn server-spec] :as api]
[pallet.crate.automated-admin-user :as automated-admin-user]
- [pallet.crate.network-service :as network-service]
+ [pallet.crate.network-service :refer [wait-for-port-listen]]
[pallet.crate.postgres :as postgres]
[pallet.live-test :as live-test]
- [pallet.phase :as phase]
+ [pallet.script :refer [with-script-context]]
+ [pallet.stevedore :refer [with-script-language]]
[pallet.test-utils :as test-utils]
[clojure.tools.logging :as logging])
(:use clojure.test))
@@ -28,113 +29,46 @@
:recovery {:bb 2}
:start {:start :disable}}))))
-(deftest default-settings-test
- (is
- (->
- (pallet.stevedore/with-script-language
- :pallet.stevedore.bash/bash
- (pallet.script/with-script-context
- [:ubuntu :aptitude]
- (postgres/default-settings
- {:server {:image {:os-family :ubuntu} :node-id :id}}
- :debian :debian-base (postgres/settings-map {}))))
- :options :data_directory)))
(deftest settings-test
- (let [settings (pallet.stevedore/with-script-language
- :pallet.stevedore.bash/bash
- (pallet.script/with-script-context
- [:ubuntu :aptitude]
- (pallet.crate.postgres/postgres-settings
- {:server {:image {:os-family :ubuntu} :node-id :id}}
- (pallet.crate.postgres/settings-map
- {:layout :debian-base}))))]
- (is
- (->
- settings
- :parameters :host :id :postgresql :default :options :data_directory))))
+ (build-actions {}
+ (let [settings (postgres/settings
+ (postgres/settings-map
+ {:layout :debian-base}))]
+ (is
+ (get-in
+ settings
+ [:plan-state :host :id postgres/facility nil :options :data_directory])))))
(deftest postgres-test
- (is ; just check for compile errors for now
- (build-actions/build-actions
- {}
- (postgres/postgres-settings (postgres/settings-map {:version "8.0"}))
- (postgres/install-postgres)
- (postgres/postgres-settings (postgres/settings-map {:version "9.0"}))
- (postgres/cluster-settings "db1" {})
- (postgres/install-postgres)
- (postgres/hba-conf)
- (postgres/postgresql-script :content "some script")
- (postgres/create-database "db")
- (postgres/create-role "user"))))
+ (is ; just check for compile errors for now
+ (build-actions {}
+ (postgres/settings (postgres/settings-map {:version "8.0"}))
+ (postgres/install {})
+ (postgres/settings (postgres/settings-map {:version "9.0"}))
+ (postgres/cluster-settings "db1" {})
+ (postgres/install {})
+ (postgres/hba-conf {})
+ (postgres/postgresql-script :content "some script")
+ (postgres/create-database "db")
+ (postgres/create-role "user"))))
(deftest cluster-settings-test
(let [settings
- (second (build-actions/build-actions
- {}
- (postgres/postgres-settings
- (postgres/settings-map
- {:version "9.0"
- :wal_directory "/var/lib/postgres/%s/archive/"}))
- (postgres/cluster-settings "db1" {})
- (postgres/cluster-settings "db2" {})
- (postgres/postgres-settings
- (postgres/settings-map {:version "9.0"}))))
- pg-settings (-> settings :parameters :host :id :postgresql :default)]
+ (second (build-actions {}
+ (postgres/settings
+ (postgres/settings-map
+ {:version "9.0"
+ :wal_directory "/var/lib/postgres/%s/archive/"}))
+ (postgres/cluster-settings "db1" {})
+ (postgres/cluster-settings "db2" {})
+ (postgres/settings
+ (postgres/settings-map {:version "9.0"}))))
+ pg-settings (get-in settings
+ [:plan-state :host :id postgres/facility nil])]
(is (-> pg-settings :clusters :db1))
(is (-> pg-settings :clusters :db2))
(is
(re-find #"db1/archive" (-> pg-settings :clusters :db1 :wal_directory)))
(is
(re-find #"db2/archive" (-> pg-settings :clusters :db2 :wal_directory)))))
-
-(def pgsql-9-unsupported
- [{:os-family :debian :os-version-matches "5.0.7"}
- {:os-family :debian :os-version-matches "5.0"}])
-
-(deftest live-test
- (live-test/test-for
- [image (live-test/exclude-images (live-test/images) pgsql-9-unsupported)]
- (logging/tracef "postgres live test: image %s" (pr-str image))
- (live-test/test-nodes
- [compute node-map node-types]
- {:pgtest
- (->
- (core/server-spec
- :phases
- {:bootstrap (phase/phase-fn
- (package/minimal-packages)
- (package/package-manager :update)
- (automated-admin-user/automated-admin-user))
- :settings (phase/phase-fn
- (postgres/postgres-settings (postgres/settings-map {}))
- (postgres/cluster-settings "db1" {:options {:port 5433}}))
- :configure (phase/phase-fn
- (postgres/install-postgres))
- :verify (phase/phase-fn
- (postgres/log-settings)
- (postgres/initdb)
- (postgres/initdb :cluster "db1")
- (postgres/hba-conf)
- (postgres/hba-conf :cluster "db1")
- (postgres/postgresql-conf)
- (postgres/postgresql-conf :cluster "db1")
- (postgres/service-config)
- (postgres/service :action :restart :if-config-changed false)
- (postgres/create-database "db")
- (postgres/postgresql-script
- :content "create temporary table table1 ();"
- :show-stdout true)
- (postgres/create-role "user1")
- (postgres/create-database "db" :cluster "db1")
- (postgres/create-role "user1" :cluster "db1")
- (postgres/postgresql-script
- :content "create temporary table table2 ();"
- :show-stdout true :cluster "db1")
- (pallet.crate.network-service/wait-for-port-listen 5432)
- (pallet.crate.network-service/wait-for-port-listen 5433))}
- :count 1
- :node-spec (core/node-spec :image image)))}
- (is
- (core/lift
- (val (first node-types)) :phase [:settings :verify] :compute compute)))))