Skip to content

Allow conf/data directory separation #228

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jun 20, 2018

Conversation

noelmcloughlin
Copy link
Contributor

@noelmcloughlin noelmcloughlin commented Jun 16, 2018

This PR adds PostgreSQL support for different data_dir and conf_dir directories.

Supersedes #187 which listed following advantages-

  1. User may want separation of data and configuration.

  2. Ubuntu postgresql-server stores config in /etc, and data into /var. The postgres state fails horribly if /etc/postgresql/../postgresql.conf exists, perhaps after postgres.dropped runs.

  3. This is current situation where conf_dir variable exists but not data_dir.

codenamemap.yaml:  conf_dir: /etc/postgresql/{{ version }}/main
defaults.yaml:  conf_dir: /var/lib/pgsql/data
osmap.yaml:  conf_dir: /var/lib/postgres/data
osmap.yaml:  conf_dir: /var/lib/pgsql/{{ repo.version }}/data
osmap.yaml:  conf_dir: /usr/local/var/postgres
  1. postgres install always fails after 'dropped' (or remove Add basic postgres.server.remove state #182) states, because conf_dir remains.

  2. If conf_dir and data_dir have same value, pg_ctl throws permissions error.
    pg_ctl[8774]: FATAL: data directory "/var/lib/pgsql/data" has group or world access

Backwards Compatibility: Depreciated postgres.create_cluster.command pillar is supported.

@noelmcloughlin noelmcloughlin force-pushed the confdata1 branch 4 times, most recently from e6b4bee to 24d6900 Compare June 17, 2018 11:58
@noelmcloughlin
Copy link
Contributor Author

Sample output on Ubuntu

         ID: postgresql-repo
    Function: pkgrepo.managed
        Name: deb http://apt.postgresql.org/pub/repos/apt xenial-pgdg main 9.5
      Result: True
     Comment: Package repo 'deb http://apt.postgresql.org/pub/repos/apt xenial-pgdg main 9.5' already configured
     Started: 06:00:11.405949
    Duration: 111.208 ms
     Changes:   
----------
          ID: postgresql-server
    Function: pkg.installed
      Result: True
     Comment: All specified packages are already installed
     Started: 06:00:12.249551
    Duration: 800.838 ms
     Changes:   
----------
          ID: postgresql-cluster-prepared
    Function: file.directory
        Name: /etc/postgresql/9.5/main
      Result: True
     Comment: Directory /etc/postgresql/9.5/main updated
     Started: 06:00:13.054608
    Duration: 3.415 ms
     Changes:   
              ----------
              /etc/postgresql/9.5/main:
                  New Dir
----------
          ID: postgresql-cluster-prepared
    Function: cmd.run
        Name: pg_createcluster 9.5 main -d  /var/lib/postgresql/9.5/main
      Result: True
     Comment: Command "pg_createcluster 9.5 main -d  /var/lib/postgresql/9.5/main" run
     Started: 06:00:13.059996
    Duration: 11420.288 ms
     Changes:   
              ----------
              pid:
                  597064
              retcode:
                  0
              stderr:
              stdout:
                  Creating new PostgreSQL cluster 9.5/main ...
                  /usr/lib/postgresql/9.5/bin/initdb -D /var/lib/postgresql/9.5/main --auth-local peer --auth-host md5
                  The files belonging to this database system will be owned by user "postgres".
                  This user must also own the server process.
                  
                  The database cluster will be initialized with locale "C".
                  The default database encoding has accordingly been set to "SQL_ASCII".
                  The default text search configuration will be set to "english".
                  
                  Data page checksums are disabled.
                  
                  fixing permissions on existing directory /var/lib/postgresql/9.5/main ... ok
                  creating subdirectories ... ok
                  selecting default max_connections ... 100
                  selecting default shared_buffers ... 128MB
                  selecting dynamic shared memory implementation ... posix
                  creating configuration files ... ok
                  creating template1 database in /var/lib/postgresql/9.5/main/base/1 ... ok
                  initializing pg_authid ... ok
                  initializing dependencies ... ok
                  creating system views ... ok
                  loading system objects' descriptions ... ok
                  creating collations ... ok
                  creating conversions ... ok
                  creating dictionaries ... ok
                  setting privileges on built-in objects ... ok
                  creating information schema ... ok
                  loading PL/pgSQL server-side language ... ok
                  vacuuming database template1 ... ok
                  copying template1 to template0 ... ok
                  copying template1 to postgres ... ok
                  syncing data to disk ... ok
                  
                  Success. You can now start the database server using:
                  
                      /usr/lib/postgresql/9.5/bin/pg_ctl -D /var/lib/postgresql/9.5/main -l logfile start
                  
                  Ver Cluster Port Status Owner    Data directory               Log file
                  9.5 main    5432 down   postgres /var/lib/postgresql/9.5/main /var/log/postgresql/postgresql-9.5-main.log
----------
          ID: postgresql-config-dir
    Function: file.directory
        Name: /var/lib/postgresql/9.5/main
      Result: True
     Comment: Directory /var/lib/postgresql/9.5/main updated
     Started: 06:00:24.481635
    Duration: 971.997 ms
     Changes:   
              ----------
              mode:
                  0644
----------
          ID: postgresql-config-dir
    Function: file.directory
        Name: /etc/postgresql/9.5/main
      Result: True
     Comment: Directory /etc/postgresql/9.5/main updated
     Started: 06:00:25.454164
    Duration: 5.309 ms
     Changes:   
              ----------
              mode:
                  0644
----------
          ID: postgresql-conf
    Function: file.blockreplace
        Name: /etc/postgresql/9.5/main/postgresql.conf
      Result: True
     Comment: Changes were made
     Started: 06:00:25.460286
    Duration: 9.067 ms
     Changes:   
              ----------
              diff:
                  --- 
                  +++ 
                  @@ -623,3 +623,6 @@
                   #------------------------------------------------------------------------------
                   
                   # Add settings for extensions here
                  +# Managed by SaltStack: listen_addresses: please do not edit
                  +listen_addresses = '*'  # listen on all interfaces
                  +# Managed by SaltStack: end of salt managed zone --
----------
          ID: postgresql-pg_hba
    Function: file.managed
        Name: /etc/postgresql/9.5/main/pg_hba.conf
      Result: True
     Comment: File /etc/postgresql/9.5/main/pg_hba.conf updated
     Started: 06:00:25.470057
    Duration: 43826.111 ms
     Changes:   
              ----------
              diff:
                  --- 
                  +++ 
                  @@ -1,99 +1,31 @@
                  +######################################################################
                  +# ATTENTION! Managed by SaltStack.                                   #
                  +# DO NOT EDIT THIS FILE BY HAND -- YOUR CHANGES WILL BE OVERWRITTEN! #
                  +######################################################################
                  +#
                   # PostgreSQL Client Authentication Configuration File
                   # ===================================================
                   #
                   # Refer to the "Client Authentication" section in the PostgreSQL
                  -# documentation for a complete description of this file.  A short
                  -# synopsis follows.
                  -#
                  -# This file controls: which hosts are allowed to connect, how clients
                  -# are authenticated, which PostgreSQL user names they can use, which
                  -# databases they can access.  Records take one of these forms:
                  -#
                  -# local      DATABASE  USER  METHOD  [OPTIONS]
                  -# host       DATABASE  USER  ADDRESS  METHOD  [OPTIONS]
                  -# hostssl    DATABASE  USER  ADDRESS  METHOD  [OPTIONS]
                  -# hostnossl  DATABASE  USER  ADDRESS  METHOD  [OPTIONS]
                  -#
                  -# (The uppercase items must be replaced by actual values.)
                  -#
                  -# The first field is the connection type: "local" is a Unix-domain
                  -# socket, "host" is either a plain or SSL-encrypted TCP/IP socket,
                  -# "hostssl" is an SSL-encrypted TCP/IP socket, and "hostnossl" is a
                  -# plain TCP/IP socket.
                  -#
                  -# DATABASE can be "all", "sameuser", "samerole", "replication", a
                  -# database name, or a comma-separated list thereof. The "all"
                  -# keyword does not match "replication". Access to replication
                  -# must be enabled in a separate record (see example below).
                  -#
                  -# USER can be "all", a user name, a group name prefixed with "+", or a
                  -# comma-separated list thereof.  In both the DATABASE and USER fields
                  -# you can also write a file name prefixed with "@" to include names
                  -# from a separate file.
                  -#
                  -# ADDRESS specifies the set of hosts the record matches.  It can be a
                  -# host name, or it is made up of an IP address and a CIDR mask that is
                  -# an integer (between 0 and 32 (IPv4) or 128 (IPv6) inclusive) that
                  -# specifies the number of significant bits in the mask.  A host name
                  -# that starts with a dot (.) matches a suffix of the actual host name.
                  -# Alternatively, you can write an IP address and netmask in separate
                  -# columns to specify the set of hosts.  Instead of a CIDR-address, you
                  -# can write "samehost" to match any of the server's own IP addresses,
                  -# or "samenet" to match any address in any subnet that the server is
                  -# directly connected to.
                  -#
                  -# METHOD can be "trust", "reject", "md5", "password", "gss", "sspi",
                  -# "ident", "peer", "pam", "ldap", "radius" or "cert".  Note that
                  -# "password" sends passwords in clear text; "md5" is preferred since
                  -# it sends encrypted passwords.
                  -#
                  -# OPTIONS are a set of options for the authentication in the format
                  -# NAME=VALUE.  The available options depend on the different
                  -# authentication methods -- refer to the "Client Authentication"
                  -# section in the documentation for a list of which options are
                  -# available for which authentication methods.
                  -#
                  -# Database and user names containing spaces, commas, quotes and other
                  -# special characters must be quoted.  Quoting one of the keywords
                  -# "all", "sameuser", "samerole" or "replication" makes the name lose
                  -# its special character, and just match a database or username with
                  -# that name.
                  -#
                  -# This file is read on server startup and when the postmaster receives
                  -# a SIGHUP signal.  If you edit the file on a running system, you have
                  -# to SIGHUP the postmaster for the changes to take effect.  You can
                  -# use "pg_ctl reload" to do that.
                  -
                  -# Put your actual configuration here
                  -# ----------------------------------
                  -#
                  -# If you want to allow non-local connections, you need to add more
                  -# "host" records.  In that case you will also need to make PostgreSQL
                  -# listen on a non-local interface via the listen_addresses
                  -# configuration parameter, or via the -i or -h command line switches.
                  -
                  -
                  -
                  +# documentation for a complete description of this file.
                   
                   # DO NOT DISABLE!
                   # If you change this first entry you will need to make sure that the
                   # database superuser can access the database using some other method.
                   # Noninteractive access to all databases is required during automatic
                   # maintenance (custom daily cronjobs, replication, and similar tasks).
                  -#
                  +
                   # Database administrative login by Unix domain socket
                   local   all             postgres                                peer
                   
                   # TYPE  DATABASE        USER            ADDRESS                 METHOD
                  -
                  -# "local" is for Unix domain socket connections only
                  -local   all             all                                     peer
                  -# 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     postgres                                peer
                  -#host    replication     postgres        127.0.0.1/32            md5
                  -#host    replication     postgres        ::1/128                 md5
                  +local   db1             localUser                               md5
                  +host    db2             remoteUser      192.168.33.0/24         md5
                  +local   all             postgres                                ident
                  +local   citrix-confdb   root                                    ident
                  +local   citrix-confdb   ctxsrvr                                 ident
                  +local   citrix-confdb   guest                                   trust
                  +host    citrix-confdb   ctxvda          127.0.0.1/32            password
                  +host    citrix-confdb   guest           127.0.0.1/32            trust
                  +host    citrix-confdb   ctxvda          ::1/128                 password
                  +host    citrix-confdb   guest           ::1/128                 trust
              mode:
                  0600
----------
          ID: postgresql-pg_ident
    Function: file.managed
        Name: /etc/postgresql/9.5/main/pg_ident.conf
      Result: True
     Comment: 
     Started: 06:01:09.297097
    Duration: 2.776 ms
     Changes:   
              ----------
              mode:
                  0600
----------
          ID: postgresql-tablespace-dir-my_space
    Function: file.directory
        Name: /srv/my_tablespace
      Result: True
     Comment: Directory /srv/my_tablespace is in the correct state
              Directory /srv/my_tablespace updated
     Started: 06:01:09.300458
    Duration: 261.818 ms
     Changes:   
----------
          ID: postgresql-running
    Function: service.running
        Name: postgresql
      Result: True
     Comment: Service reloaded
     Started: 06:01:09.642742
    Duration: 135.383 ms
     Changes:   
              ----------
              postgresql:
                  True

Copy link
Contributor

@vutny vutny left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hi @noelmcloughlin

That's gonna be a great PR! Let's polish it little bit together 😃

{% else %}
{% set fromrepo = name %}
{% set conf_dir = defaults.conf_dir %}
{% set data_dir = defaults.data_dir %}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have checked Ubuntu docs on PostgreSQL, and it appears that "downstream" packages also store all configuration files in /etc as well. Tried to install PG on Debian: same thing there.

So we need to separate conf and data directory for the whole Debian OS family.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I checked my commits on #187 (which was tested heavily) and you're correct. Fixed.

@@ -40,13 +46,19 @@
{% if repo.use_upstream_repo == true %}
{% set fromrepo = repo.fromrepo|default(name ~ '-pgdg', true) %}
{% set version = repo.version %}
{% set conf_dir = '/etc/postgresql/' + version|string + '/main' %}
{% set data_dir = '/var/lib/postgresql/' + version|string + '/main' %}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this really applicable to Fedora? I'm not sure.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I checked my commits on #187 (which was tested heavily) and you're correct. Not needed. Fixed.

@@ -40,13 +46,19 @@
{% if repo.use_upstream_repo == true %}
{% set fromrepo = repo.fromrepo|default(name ~ '-pgdg', true) %}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess I missed this before, but the fromrepo for RedHat family should be equal to pkg_repo.name value (pgdg{{ release }}). This need to be corrected.

- name: {{ postgres.prepare_cluster.command }}
- unless: {{ postgres.prepare_cluster.test }}
{%- else %}
- name: {{ postgres.prepare_cluster.pgcommand + ' ' }} {{ postgres.data_dir }}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I saw you have reconstructed the pgcommand defaults... I like that.
But just consider to use short option for all platforms except Debians: initdb -D. In such case adding that space in the template would be unnecessary.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So I can replace {{ postgres.prepare_cluster.pgcommand + ' ' }} with initdb -D for all except Debian?

@@ -15,12 +15,13 @@ postgres:
group: postgres

prepare_cluster:
command: initdb --pgdata=/var/lib/pgsql/data
test: test -f /var/lib/pgsql/data/PG_VERSION
pgcommand: initdb --pgdata=
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Having initdb -D here will simplify your final command for the postgresql-cluster-prepared state.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Cool!! I'm only realizing now initdb -D and initdb --pgdata= are equilivent. ;-)

command: initdb -D /var/lib/postgres/data
test: test -f /var/lib/postgres/data/PG_VERSION
pgcommand: initdb -D
pgtestfile: PG_VERSION
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since these values would exactly match the default ones, no need to override them here. Same for other distros below.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Good point. I'll fix that. thanks @vutny

@noelmcloughlin noelmcloughlin force-pushed the confdata1 branch 2 times, most recently from 248cb85 to 9349335 Compare June 17, 2018 20:48
Copy link
Contributor

@vutny vutny left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@noelmcloughlin This looks promising, just need to finish some cleanup and fixup for Fedora. Thanks!

@@ -1,6 +1,7 @@
### Set parameters based on PostgreSQL version supplied with particular distro

{% import_yaml "postgres/repo.yaml" as repo %}
{% import_yaml "postgres/defaults.yaml" as defaults %}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This line becomes unnecessary.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes, thanks.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't forget about it 😃

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ha ha - think I nailed it this time!! ;-)


{{ codename|default(name, true) }}:
# PostgreSQL packages are mostly downloaded from `main` repo component
conf_dir: {{ conf_dir }}
data_dir: {{ data_dir }}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since these values become global for all Debian derivatives, we should move them to the OS family map.

Copy link
Contributor Author

@noelmcloughlin noelmcloughlin Jun 18, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The version calculated by oscodename is passed to fedora_codename macro and used ..

  {% set conf_dir = '/etc/postgresql/' + version|string + '/main' %}
  {% set data_dir = '/var/lib/postgresql/' + version|string + '/main' %}

If version calculated by OS map is different to version calculated here, problems will result? What do you think?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, you're right, absolutely. I've completely forgot that the version for distro-provided packages is handled here as well. Thanks, keep insisting on right things! 👍

@@ -46,7 +48,7 @@

{{ codename|default(name, true) }}:
# PostgreSQL packages are mostly downloaded from `main` repo component
fromrepo: {{ name }}
fromrepo: {{ fromrepo }}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This really needs to be fixed. The fromrepo for "downstream" installations should be None by default, but for the upstream it should match the pkg_repo.name value across RedHat-based distros. I see that it is already done at upper mapping level in the OS family map. So we can just remove manipulations on fromrepo here.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, its handled correctly for "upstream" repos in OS family map file. The fromrepo: '' is defaults.yaml should evaluate to None, for Debian it should be name but for Fedora/Redhat what should the "downstream" fromrepo value be?

Copy link
Contributor

@vutny vutny Jun 18, 2018

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we should leave that default value and do not handle the fromrepo parameter for downstream at all. That's rarely applicable use-case and would be to complex to handle for now.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Okay, so fromrepo is not used for Fedora. For Ubuntu I do need to set fromrepo jinja variable to some value, either {% set fromrepo = name %} or {% set fromrepo = '' %} or {% set fromrepo = None %} in codenamemap.yaml. The SLS files will check {% if postgres.fromrepo } so just need to set correct value so condition fails. Is this how you see it too?

@noelmcloughlin noelmcloughlin force-pushed the confdata1 branch 2 times, most recently from 7b13803 to 194370a Compare June 18, 2018 15:13
Copy link
Contributor

@vutny vutny left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@noelmcloughlin Keep up the good work! Just that import of defaults to remove and we go merge this.


{{ codename|default(name, true) }}:
# PostgreSQL packages are mostly downloaded from `main` repo component
conf_dir: {{ conf_dir }}
data_dir: {{ data_dir }}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh, you're right, absolutely. I've completely forgot that the version for distro-provided packages is handled here as well. Thanks, keep insisting on right things! 👍

{% if repo.use_upstream_repo == true %}
{% set version = repo.version %}
{% set fromrepo = repo.fromrepo|default(name ~ '-pgdg', true) %}
{% else %}
{% set fromrepo = name %}
{% endif %}
{% set conf_dir = '/etc/postgresql/' + version|string + '/main' %}
{% set data_dir = '/var/lib/postgresql/' + version|string + '/main' %}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's OK, but generally better to use Jinja concatenation operator ~ (tilde) or file.join Salt's function here instead of type casting on variables.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Forgot about tilde - very useful operand in this case. thx

~
Converts all operands into strings and concatenates them.

@@ -1,6 +1,7 @@
### Set parameters based on PostgreSQL version supplied with particular distro

{% import_yaml "postgres/repo.yaml" as repo %}
{% import_yaml "postgres/defaults.yaml" as defaults %}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't forget about it 😃

@noelmcloughlin noelmcloughlin force-pushed the confdata1 branch 2 times, most recently from 8865637 to fef23e6 Compare June 18, 2018 22:42
@noelmcloughlin
Copy link
Contributor Author

One question. If we choose non-standard data_dir or conf_dir will Apparmor block PG? See https://blogs.oracle.com/jsmyth/apparmor-and-mysql. I cannot find any documented issue and saw no issue in testing. Did not test in Docker however.

Copy link
Contributor

@vutny vutny left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good to me. Thanks @noelmcloughlin

Regarding security context. If AppArmor or SELinux are enforcing policies provided by the distribution, any path or listening port customizations would require modifications of those policies. It is applicable to any service, not just PotgreSQL.

I think our formula has nothing to do about that, because security hardening automation has too much broad scope and very specific to a platform in particular environment. Here we provide a baseline of how do things directly related to PG operations. Everything else could be build on top, with or without the help of Salt.

@aboe76 aboe76 merged commit 9865664 into saltstack-formulas:master Jun 20, 2018
@aboe76
Copy link
Contributor

aboe76 commented Jun 20, 2018

@noelmcloughlin and @vutny merged!

@noelmcloughlin noelmcloughlin deleted the confdata1 branch June 20, 2018 08:47
@noelmcloughlin
Copy link
Contributor Author

Cool thanks!!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants