Allow port to be configurable#218
Conversation
Regex:
- `^` Line start
- `#*\s*` Find line even if commented out
- `(port)` 'port' -- capture as backreference `\1`
- `\s*=\s*` Equals sign, whether or not surrounded by whitespace
- `\d{4,5}` Existing port value, expected at 4/5 digits
- `(.*)` Remainder (i.e. comment) -- capture as backreference `\2`
- `$` Line end
Current deficienciesOne way this method could be disadvantageous is that there is no comment/warning that the port is being managed by Salt. Couple of suggestions how this could be resolved:
|
Comment appended to same lineUsed the simplest solution to append the warning to the same line: ---
+++
@@ -60,7 +60,7 @@
# comma-separated list of addresses;
# defaults to 'localhost'; use '*' for all
# (change requires restart)
-port = 5433 # (change requires restart)
+port = 5433 # Managed by SaltStack: please do not edit
max_connections = 100 # (change requires restart)
#superuser_reserved_connections = 3 # (change requires restart)
unix_socket_directories = '/var/run/postgresql' # comma-separated list of directories |
* Regex modified: - Ensure whitespace before comment is maintained - Consistent with surrounding lines in the file * Used YAML pipe `>-` due to the colon-space (`: `) in the comment
vutny
left a comment
There was a problem hiding this comment.
@myii Thanks for your PR!
Adding support for non-standard PG port is a tricky task here. You have did that well, but I hope you might consider another way, which should be more solid comparing to regex magic :)
-
Salt uses it's own configuration for transparent work with PostgreSQL, which could be exposed via Pillar. This allows to enable custom port usage in all other
postgresmodules right away. -
And you can reuse this setting to append to the content in
postgresql-confstate directly in the SLS if it exists. Since theportsetting is commented in the PG distribution, this is rather safe.
I have added some details inline.
pillar.example
Outdated
There was a problem hiding this comment.
With what I said above, we could provide top level postgres.port Pillar setting. This would be reused directly in the server SLS and automatically enable correct port resolution for all Salt routines related to PostgreSQL.
But just better to keep it default mentioning it could be changed.
postgres/macros.jinja
Outdated
There was a problem hiding this comment.
With setting postgres.port this would be unnecessary.
postgres/server/init.sls
Outdated
There was a problem hiding this comment.
I think having two states handling a single service is not that good idea, since this could be very easy overlooked in further development...
But I understand we'd have to deal with port setting could be defined outside of Managed by SaltStack protected zone. So we can add a file.comment state with rather simple regex to force commenting out string matching /port = .+/ only when postgres.port is defined and there would be changes in postgresql-conf:
{%- if salt['pillar.get']('postgres.port') %}
postgresql-alter-port:
file.comment:
- name: {{ postgres.conf_dir }}/postgresql.conf
- regex: ^port = .+
- prereq:
- file: postgresql-conf
{%- endif %}|
@vutny Thanks for your feedback. I'll get back to you once I get the chance to go over the points you've raised. |
|
@vutny Apologies for the delay, needed to find some free time to work on this. Changes should be clear enough, since mainly an incorporation of your suggestions. |
| # Append the lines under this item to your postgresql.conf file. | ||
| # Pay attention to indent exactly with 4 spaces for all lines. | ||
| postgresconf: | | ||
| postgresconf: |- |
There was a problem hiding this comment.
Otherwise an unnecessary blank line rendered, more noticeable if both listen_addresses and port are given.
| - cmd: postgresql-cluster-prepared | ||
|
|
||
| {%- if postgres.postgresconf %} | ||
| {%- set db_port = salt['config.option']('postgres.port') %} |
There was a problem hiding this comment.
Instead of the suggested:
{%- if salt['pillar.get']('postgres.port') %}config.optiongets the value from the minion configuration first, otherwise the pillar (which then works correctly with thepostgres.managestates)- Same as the method used in the code for
salt.modules.postgres
| postgresql-conf: | ||
| file.blockreplace: | ||
| - name: {{ postgres.conf_dir }}/postgresql.conf | ||
| - marker_start: "# Managed by SaltStack: listen_addresses: please do not edit" |
There was a problem hiding this comment.
Obviously can't change this marker to mention that the managed block is also for the port.
| {%- set db_port = salt['config.option']('postgres.port') %} | ||
| {%- if db_port %} | ||
|
|
||
| postgresql-conf-comment-port: |
There was a problem hiding this comment.
Since the
portsetting is commented in the PG distribution, this is rather safe.
Unfortunately, the port is set as part of the installation process, at least on Ubuntu.
So commenting out all and then letting the file.blockreplace below do its job. Works without changes for subsequent runs.
There was a problem hiding this comment.
Yeah, it appears that file.comment state is more intelligent than I thought, and it does not comment out other strings matching same pattern when encounter the first one already commented. Interesting, I was not aware of that...
postgres/server/init.sls
Outdated
There was a problem hiding this comment.
This is the simplest way to reuse the same state but I'm sure it could be improved. What is the right way to only restart the service when the port has been changed?
There was a problem hiding this comment.
Technically, many settings inside postgresql.confrequired full restart of PG cluster, listen_address and port are just obvious ones.
Probably we could use separate module.run state to force restart when necessary, but better leave it for another PR addressing this issue.
| # Append the lines under this item to your postgresql.conf file. | ||
| # Pay attention to indent exactly with 4 spaces for all lines. | ||
| postgresconf: | | ||
| postgresconf: |- |
| - cmd: postgresql-cluster-prepared | ||
|
|
||
| {%- if postgres.postgresconf %} | ||
| {%- set db_port = salt['config.option']('postgres.port') %} |
postgres/server/init.sls
Outdated
There was a problem hiding this comment.
Technically, many settings inside postgresql.confrequired full restart of PG cluster, listen_address and port are just obvious ones.
Probably we could use separate module.run state to force restart when necessary, but better leave it for another PR addressing this issue.
postgres/server/init.sls
Outdated
| {%- set db_port = salt['config.option']('postgres.port') %} | ||
| {%- if db_port %} | ||
|
|
||
| postgresql-conf-comment-port: |
There was a problem hiding this comment.
Yeah, it appears that file.comment state is more intelligent than I thought, and it does not comment out other strings matching same pattern when encounter the first one already commented. Interesting, I was not aware of that...
| - enable: True | ||
| {% if grains.os not in ('MacOS',) %} | ||
| {% if grains.os not in ('MacOS',) and not db_port %} | ||
| - reload: True |
There was a problem hiding this comment.
I think we could do something like:
- reload: {{ not postgres.postgresconf and not db_port and not db_port == '5432' }}|
@vutny I've opted for reintroducing a separated state for restarting the service. Every other Jinja-based method is either not 100% reliable (won't restart when it needs to) or results in unnecessary restarts. Some examples:
I'm sure there are more examples. What the real issue here is that the Jinja isn't 100% deterministic, so will always cause one issue or the other. The only way of being definitive is to use one state for watching when reloads can take place and another to watch for when restarts should take place. Keeping the reload/restart states next to each other will minimise developmental issues. Using requisites (i.e. Unless there is some way of:
|
postgres/server/init.sls
Outdated
There was a problem hiding this comment.
@myii I like the idea of using onchanges requisite much better. We could do something like this.
{%- if postgres.postgresconf or db_port %}
postgresql-service-restart:
module.run:
- name: service.restart
- m_name: {{ postgres.service }}
- onchanges:
- file: postgresql-conf
{%- endif %}There was a problem hiding this comment.
@vutny Of course that can be done. I have a couple of questions:
- I'm curious: while I've used
module.runfor my own formulas, I've been under the impression that it should only be used as a last resort, when there isn't an available state -- for my understanding, would you mind explaining the advantage of using this instead? - To save having to keep the Jinja (
{%- if postgres.postgresconf or db_port %}in sync with the one being used above, how about moving this into that block above, i.e.:
{%- if postgres.postgresconf or db_port %}
postgresql-conf:
file.blockreplace:
- name: {{ postgres.conf_dir }}/postgresql.conf
- marker_start: "# Managed by SaltStack: listen_addresses: please do not edit"
- marker_end: "# Managed by SaltStack: end of salt managed zone --"
- content: |
{%- if postgres.postgresconf %}
{{ postgres.postgresconf|indent(8) }}
{%- endif %}
{%- if db_port %}
port = {{ db_port }}
{%- endif %}
- show_changes: True
- append_if_not_found: True
{#- Detect empty values (none, '') in the config_backup #}
- backup: {{ postgres.config_backup|default(false, true) }}
- require:
- file: postgresql-config-dir
{%- if db_port %}
- file: postgresql-conf-comment-port
{%- endif %}
module.run:
- name: service.restart
- m_name: {{ postgres.service }}
- onchanges:
- file: postgresql-conf
{%- endif %}Further advantages of less lines and keeping logically related states together.
There was a problem hiding this comment.
or just use listen_in:
https://docs.saltstack.com/en/latest/ref/states/requisites.html#listen-listen-in
There was a problem hiding this comment.
@aboe76 Unfortunately, can't use listen/listen_in because the service needs to be restarted before the postgres.manage states run.
There was a problem hiding this comment.
@aboe76 @vutny module.wait + watch/watch_in looks like an improvement, thanks for that @aboe76. However, the other issues raised above still remain. At the very least, where should this be positioned? In the same {%- if postgres.postgresconf or db_port %} block as shown above or at the bottom next to service.running?
There was a problem hiding this comment.
@myii I think it is OK to group together postgresql-conf and future postgres-restart states, just better name them separately, because that's a good practice.
In case of initial installation, when PG cluster is not running yet, the restart state would simply bring it up. Later postgresql-running state will just do reload when necessary, that's fast and safe. And it would bring the service back in case of any earlier failures. But this will prevent from unnecessary restarts then there would be no changes to postgresql.conf file.
With that said, your approach is good. Please update the PR and I'm sure we'll merge it in.
Thank you for your contribution!
|
@vutny @aboe76 So I've applied those changes using Using the work in this PR, I've been able to adapt the formula to work with multiple clusters/versions. While this has far-reaching impact the implementation is relatively simple, primarily wrapping the existing code in At this stage, the implementation is rudimentary, i.e. "works for me". Is there any appetite for including this functionality? If there is, I'll start a new PR where it can be discussed further. |
|
@vutny would you like to take a second look? |
|
Done |
References
Discussion
I've been using this formula for a while now and like the comment linked above, I've been able to use
db_portto adapt to clusters not using the default port of5432.The implementation does not affect existing configurations. The non-standard
portwould have to be explicitly provided in the pillar.Changing the port requires a service restart, so the existing service reload state doesn't work -- hence using
service.runningagain. More could be done to check the various situations but I preferred simplicity to efficiency, at least when introducing this functionality.I envisage that this is a useful first step towards adding support for multiple clusters / versions (i.e. #174).
Concerns
The will probably necessitate modification of:
postgres-formula/test/integration/default/serverspec/postgres_spec.rb
Line 10 in 800259d
Regex description