From 6f273d7d9795a47b8cd31c507eac2bbec49c3752 Mon Sep 17 00:00:00 2001 From: Mike Reeves Date: Thu, 14 May 2026 15:53:00 -0400 Subject: [PATCH 1/8] Rename init-users.sh to init-db.sh and update all references --- salt/postgres/config.sls | 6 +++--- salt/postgres/enabled.sls | 8 ++++---- salt/postgres/files/{init-users.sh => init-db.sh} | 0 salt/postgres/telegraf_users.sls | 2 +- 4 files changed, 8 insertions(+), 8 deletions(-) rename salt/postgres/files/{init-users.sh => init-db.sh} (100%) diff --git a/salt/postgres/config.sls b/salt/postgres/config.sls index 11ca52649..e458e8455 100644 --- a/salt/postgres/config.sls +++ b/salt/postgres/config.sls @@ -46,10 +46,10 @@ postgresinitdir: - require: - file: postgresconfdir -postgresinitusers: +postgresinitdb: file.managed: - - name: /opt/so/conf/postgres/init/init-users.sh - - source: salt://postgres/files/init-users.sh + - name: /opt/so/conf/postgres/init/init-db.sh + - source: salt://postgres/files/init-db.sh - user: 939 - group: 939 - mode: 755 diff --git a/salt/postgres/enabled.sls b/salt/postgres/enabled.sls index b3abb621e..20d256ae8 100644 --- a/salt/postgres/enabled.sls +++ b/salt/postgres/enabled.sls @@ -31,7 +31,7 @@ so-postgres: - POSTGRES_DB=securityonion # Passwords are delivered via mounted 0600 secret files, not plaintext env vars. # The upstream postgres image resolves POSTGRES_PASSWORD_FILE; entrypoint.sh and - # init-users.sh resolve SO_POSTGRES_PASS_FILE the same way. + # init-db.sh resolve SO_POSTGRES_PASS_FILE the same way. - POSTGRES_PASSWORD_FILE=/run/secrets/postgres_password - SO_POSTGRES_USER={{ SO_POSTGRES_USER }} - SO_POSTGRES_PASS_FILE=/run/secrets/so_postgres_pass @@ -46,7 +46,7 @@ so-postgres: - /opt/so/conf/postgres/postgresql.conf:/conf/postgresql.conf:ro - /opt/so/conf/postgres/pg_hba.conf:/conf/pg_hba.conf:ro - /opt/so/conf/postgres/secrets:/run/secrets:ro - - /opt/so/conf/postgres/init/init-users.sh:/docker-entrypoint-initdb.d/init-users.sh:ro + - /opt/so/conf/postgres/init/init-db.sh:/docker-entrypoint-initdb.d/init-db.sh:ro - /etc/pki/postgres.crt:/conf/postgres.crt:ro - /etc/pki/postgres.key:/conf/postgres.key:ro - /etc/pki/tls/certs/intca.crt:/conf/ca.crt:ro @@ -70,7 +70,7 @@ so-postgres: - watch: - file: postgresconf - file: postgreshba - - file: postgresinitusers + - file: postgresinitdb - file: postgres_super_secret - file: postgres_app_secret - x509: postgres_crt @@ -78,7 +78,7 @@ so-postgres: - require: - file: postgresconf - file: postgreshba - - file: postgresinitusers + - file: postgresinitdb - file: postgres_super_secret - file: postgres_app_secret - x509: postgres_crt diff --git a/salt/postgres/files/init-users.sh b/salt/postgres/files/init-db.sh similarity index 100% rename from salt/postgres/files/init-users.sh rename to salt/postgres/files/init-db.sh diff --git a/salt/postgres/telegraf_users.sls b/salt/postgres/telegraf_users.sls index 62490ea52..1ac7c80ed 100644 --- a/salt/postgres/telegraf_users.sls +++ b/salt/postgres/telegraf_users.sls @@ -39,7 +39,7 @@ postgres_wait_ready: - require: - docker_container: so-postgres -# Ensure the shared Telegraf database exists. init-users.sh only runs on a +# Ensure the shared Telegraf database exists. init-db.sh only runs on a # fresh data dir, so hosts upgraded onto an existing /nsm/postgres volume # would otherwise never get so_telegraf. postgres_create_telegraf_db: From b7a13899f776c48cff48d7c9af9add92ee3dd298 Mon Sep 17 00:00:00 2001 From: Mike Reeves Date: Thu, 14 May 2026 15:56:04 -0400 Subject: [PATCH 2/8] Suppress output logging for postgres telegraf role provisioning --- salt/postgres/telegraf_users.sls | 1 + 1 file changed, 1 insertion(+) diff --git a/salt/postgres/telegraf_users.sls b/salt/postgres/telegraf_users.sls index 1ac7c80ed..6d6a30d84 100644 --- a/salt/postgres/telegraf_users.sls +++ b/salt/postgres/telegraf_users.sls @@ -118,6 +118,7 @@ postgres_telegraf_role_{{ u }}: GRANT CONNECT ON DATABASE so_telegraf TO "{{ u }}"; GRANT so_telegraf TO "{{ u }}"; EOSQL + - hide_output: True - require: - cmd: postgres_telegraf_group_role From 450eacca417fcc7503b06e491f5b8cbbb1bdcd92 Mon Sep 17 00:00:00 2001 From: Mike Reeves Date: Thu, 14 May 2026 16:15:54 -0400 Subject: [PATCH 3/8] Move telegraf role provisioning to external script with env vars --- salt/postgres/config.sls | 8 ++++++++ salt/postgres/files/telegraf_role.sh | 23 +++++++++++++++++++++++ salt/postgres/telegraf_users.sls | 21 ++++++--------------- 3 files changed, 37 insertions(+), 15 deletions(-) create mode 100644 salt/postgres/files/telegraf_role.sh diff --git a/salt/postgres/config.sls b/salt/postgres/config.sls index e458e8455..f5bf856eb 100644 --- a/salt/postgres/config.sls +++ b/salt/postgres/config.sls @@ -94,6 +94,14 @@ postgres_app_secret: - require: - file: postgressecretsdir +postgrestelegrafrole: + file.managed: + - name: /usr/local/bin/telegraf_role.sh + - source: salt://postgres/files/telegraf_role.sh + - user: root + - group: root + - mode: 755 + postgres_sbin: file.recurse: - name: /usr/sbin diff --git a/salt/postgres/files/telegraf_role.sh b/salt/postgres/files/telegraf_role.sh new file mode 100644 index 000000000..352efa018 --- /dev/null +++ b/salt/postgres/files/telegraf_role.sh @@ -0,0 +1,23 @@ +#!/bin/bash +set -e + +# Provision or update a Telegraf postgres role. +# Expects ROLE_USER and ROLE_PASS environment variables. + +docker exec -i so-postgres psql \ + -v ON_ERROR_STOP=1 \ + -v role_user="$ROLE_USER" \ + -v role_pass="$ROLE_PASS" \ + -U postgres -d so_telegraf <<'EOSQL' +DO $$ +BEGIN + IF NOT EXISTS (SELECT FROM pg_catalog.pg_roles WHERE rolname = :role_user) THEN + EXECUTE format('CREATE ROLE %I WITH LOGIN PASSWORD %L', :role_user, :role_pass); + ELSE + EXECUTE format('ALTER ROLE %I WITH LOGIN PASSWORD %L', :role_user, :role_pass); + END IF; +END +$$; +GRANT CONNECT ON DATABASE so_telegraf TO :"role_user"; +GRANT so_telegraf TO :"role_user"; +EOSQL diff --git a/salt/postgres/telegraf_users.sls b/salt/postgres/telegraf_users.sls index 6d6a30d84..bafa781cc 100644 --- a/salt/postgres/telegraf_users.sls +++ b/salt/postgres/telegraf_users.sls @@ -100,26 +100,17 @@ postgres_telegraf_group_role: {% for mid, entry in creds.items() %} {% if entry.get('user') and entry.get('pass') %} {% set u = entry.user %} -{% set p = entry.pass | replace("'", "''") %} +{% set p = entry.pass %} postgres_telegraf_role_{{ u }}: cmd.run: - - name: | - docker exec -i so-postgres psql -v ON_ERROR_STOP=1 -U postgres -d so_telegraf <<'EOSQL' - DO $$ - BEGIN - IF NOT EXISTS (SELECT FROM pg_catalog.pg_roles WHERE rolname = '{{ u }}') THEN - EXECUTE format('CREATE ROLE %I WITH LOGIN PASSWORD %L', '{{ u }}', '{{ p }}'); - ELSE - EXECUTE format('ALTER ROLE %I WITH PASSWORD %L', '{{ u }}', '{{ p }}'); - END IF; - END - $$; - GRANT CONNECT ON DATABASE so_telegraf TO "{{ u }}"; - GRANT so_telegraf TO "{{ u }}"; - EOSQL + - name: /usr/local/bin/telegraf_role.sh + - env: + - ROLE_USER: {{ u }} + - ROLE_PASS: {{ p }} - hide_output: True - require: + - file: postgrestelegrafrole - cmd: postgres_telegraf_group_role {% endif %} From 03fa01a705db80ff9ef146400d5c62115ce0e08b Mon Sep 17 00:00:00 2001 From: Mike Reeves Date: Thu, 14 May 2026 16:18:01 -0400 Subject: [PATCH 4/8] Move telegraf_role.sh to postgres tools/sbin --- salt/postgres/config.sls | 8 -------- salt/postgres/telegraf_users.sls | 4 ++-- salt/postgres/{files => tools/sbin}/telegraf_role.sh | 0 3 files changed, 2 insertions(+), 10 deletions(-) rename salt/postgres/{files => tools/sbin}/telegraf_role.sh (100%) diff --git a/salt/postgres/config.sls b/salt/postgres/config.sls index f5bf856eb..e458e8455 100644 --- a/salt/postgres/config.sls +++ b/salt/postgres/config.sls @@ -94,14 +94,6 @@ postgres_app_secret: - require: - file: postgressecretsdir -postgrestelegrafrole: - file.managed: - - name: /usr/local/bin/telegraf_role.sh - - source: salt://postgres/files/telegraf_role.sh - - user: root - - group: root - - mode: 755 - postgres_sbin: file.recurse: - name: /usr/sbin diff --git a/salt/postgres/telegraf_users.sls b/salt/postgres/telegraf_users.sls index bafa781cc..369e30dbc 100644 --- a/salt/postgres/telegraf_users.sls +++ b/salt/postgres/telegraf_users.sls @@ -104,13 +104,13 @@ postgres_telegraf_group_role: postgres_telegraf_role_{{ u }}: cmd.run: - - name: /usr/local/bin/telegraf_role.sh + - name: /usr/sbin/telegraf_role.sh - env: - ROLE_USER: {{ u }} - ROLE_PASS: {{ p }} - hide_output: True - require: - - file: postgrestelegrafrole + - file: postgres_sbin - cmd: postgres_telegraf_group_role {% endif %} diff --git a/salt/postgres/files/telegraf_role.sh b/salt/postgres/tools/sbin/telegraf_role.sh similarity index 100% rename from salt/postgres/files/telegraf_role.sh rename to salt/postgres/tools/sbin/telegraf_role.sh From b9f2d56932d870a9b8bd9b0daacd4f96a9191587 Mon Sep 17 00:00:00 2001 From: Mike Reeves Date: Thu, 14 May 2026 16:37:08 -0400 Subject: [PATCH 5/8] Consolidate telegraf postgres SQL into multi-mode script Replace inline psql heredocs in telegraf_users.sls with subcommand dispatcher telegraf_postgres.sh: create_db, group_role, user, retention. --- salt/postgres/telegraf_users.sls | 63 ++-------- salt/postgres/tools/sbin/telegraf_postgres.sh | 108 ++++++++++++++++++ salt/postgres/tools/sbin/telegraf_role.sh | 23 ---- 3 files changed, 117 insertions(+), 77 deletions(-) create mode 100644 salt/postgres/tools/sbin/telegraf_postgres.sh delete mode 100644 salt/postgres/tools/sbin/telegraf_role.sh diff --git a/salt/postgres/telegraf_users.sls b/salt/postgres/telegraf_users.sls index 369e30dbc..4b95ac45b 100644 --- a/salt/postgres/telegraf_users.sls +++ b/salt/postgres/telegraf_users.sls @@ -44,12 +44,10 @@ postgres_wait_ready: # would otherwise never get so_telegraf. postgres_create_telegraf_db: cmd.run: - - name: | - if ! docker exec so-postgres psql -U postgres -tAc "SELECT 1 FROM pg_database WHERE datname='so_telegraf'" | grep -q 1; then - docker exec so-postgres psql -v ON_ERROR_STOP=1 -U postgres -c "CREATE DATABASE so_telegraf" - fi + - name: /usr/sbin/telegraf_postgres.sh create_db - require: - cmd: postgres_wait_ready + - file: postgres_sbin # Provision the shared group role and schema once. Every per-minion role is a # member of so_telegraf, and each Telegraf connection does SET ROLE so_telegraf @@ -57,44 +55,10 @@ postgres_create_telegraf_db: # on first write are owned by the group role and every member can INSERT/SELECT. postgres_telegraf_group_role: cmd.run: - - name: | - docker exec -i so-postgres psql -v ON_ERROR_STOP=1 -U postgres -d so_telegraf <<'EOSQL' - DO $$ - BEGIN - IF NOT EXISTS (SELECT FROM pg_catalog.pg_roles WHERE rolname = 'so_telegraf') THEN - CREATE ROLE so_telegraf NOLOGIN; - END IF; - END - $$; - GRANT CONNECT ON DATABASE so_telegraf TO so_telegraf; - CREATE SCHEMA IF NOT EXISTS telegraf AUTHORIZATION so_telegraf; - GRANT USAGE, CREATE ON SCHEMA telegraf TO so_telegraf; - CREATE SCHEMA IF NOT EXISTS partman; - CREATE EXTENSION IF NOT EXISTS pg_partman SCHEMA partman; - CREATE EXTENSION IF NOT EXISTS pg_cron; - -- Telegraf (running as so_telegraf) calls partman.create_parent() - -- on first write of each metric, which needs USAGE on the partman - -- schema, EXECUTE on its functions/procedures, and write access to - -- partman.part_config so it can register new partitioned parents. - GRANT USAGE, CREATE ON SCHEMA partman TO so_telegraf; - GRANT SELECT, INSERT, UPDATE, DELETE ON ALL TABLES IN SCHEMA partman TO so_telegraf; - GRANT EXECUTE ON ALL FUNCTIONS IN SCHEMA partman TO so_telegraf; - GRANT EXECUTE ON ALL PROCEDURES IN SCHEMA partman TO so_telegraf; - -- partman creates per-parent template tables (partman.template_*) at - -- runtime; default privileges extend DML/sequence access to them. - ALTER DEFAULT PRIVILEGES IN SCHEMA partman - GRANT SELECT, INSERT, UPDATE, DELETE ON TABLES TO so_telegraf; - ALTER DEFAULT PRIVILEGES IN SCHEMA partman - GRANT USAGE, SELECT, UPDATE ON SEQUENCES TO so_telegraf; - -- Hourly partman maintenance. cron.schedule is idempotent by jobname. - SELECT cron.schedule( - 'telegraf-partman-maintenance', - '17 * * * *', - 'CALL partman.run_maintenance_proc()' - ); - EOSQL + - name: /usr/sbin/telegraf_postgres.sh group_role - require: - cmd: postgres_create_telegraf_db + - file: postgres_sbin {% set creds = salt['pillar.get']('telegraf:postgres_creds', {}) %} {% for mid, entry in creds.items() %} @@ -104,7 +68,7 @@ postgres_telegraf_group_role: postgres_telegraf_role_{{ u }}: cmd.run: - - name: /usr/sbin/telegraf_role.sh + - name: /usr/sbin/telegraf_postgres.sh user - env: - ROLE_USER: {{ u }} - ROLE_PASS: {{ p }} @@ -122,21 +86,12 @@ postgres_telegraf_role_{{ u }}: {% set retention = salt['pillar.get']('postgres:telegraf:retention_days', 14) | int %} postgres_telegraf_retention_reconcile: cmd.run: - - name: | - docker exec -i so-postgres psql -v ON_ERROR_STOP=1 -U postgres -d so_telegraf <<'EOSQL' - DO $$ - BEGIN - IF EXISTS (SELECT 1 FROM pg_catalog.pg_extension WHERE extname = 'pg_partman') THEN - UPDATE partman.part_config - SET retention = '{{ retention }} days', - retention_keep_table = false - WHERE parent_table LIKE 'telegraf.%'; - END IF; - END - $$; - EOSQL + - name: /usr/sbin/telegraf_postgres.sh retention + - env: + - RETENTION_DAYS: {{ retention }} - require: - cmd: postgres_telegraf_group_role + - file: postgres_sbin {% endif %} diff --git a/salt/postgres/tools/sbin/telegraf_postgres.sh b/salt/postgres/tools/sbin/telegraf_postgres.sh new file mode 100644 index 000000000..7f2061543 --- /dev/null +++ b/salt/postgres/tools/sbin/telegraf_postgres.sh @@ -0,0 +1,108 @@ +#!/bin/bash +set -e + +# Provision Telegraf state inside the so-postgres container. +# Usage: telegraf_postgres.sh +# create_db Ensure the so_telegraf database exists. +# group_role Provision the so_telegraf group role, telegraf/partman schemas, +# pg_partman, pg_cron, and the hourly partman maintenance job. +# user Create or update a per-minion login role granted to so_telegraf. +# Env: ROLE_USER, ROLE_PASS. +# retention Reconcile partman retention on telegraf parents. +# Env: RETENTION_DAYS. + +cmd="${1:?subcommand required}" + +case "$cmd" in + create_db) + if ! docker exec so-postgres psql -U postgres -tAc \ + "SELECT 1 FROM pg_database WHERE datname='so_telegraf'" | grep -q 1; then + docker exec so-postgres psql -v ON_ERROR_STOP=1 -U postgres \ + -c "CREATE DATABASE so_telegraf" + fi + ;; + + group_role) + docker exec -i so-postgres psql -v ON_ERROR_STOP=1 -U postgres -d so_telegraf <<'EOSQL' +DO $$ +BEGIN + IF NOT EXISTS (SELECT FROM pg_catalog.pg_roles WHERE rolname = 'so_telegraf') THEN + CREATE ROLE so_telegraf NOLOGIN; + END IF; +END +$$; +GRANT CONNECT ON DATABASE so_telegraf TO so_telegraf; +CREATE SCHEMA IF NOT EXISTS telegraf AUTHORIZATION so_telegraf; +GRANT USAGE, CREATE ON SCHEMA telegraf TO so_telegraf; +CREATE SCHEMA IF NOT EXISTS partman; +CREATE EXTENSION IF NOT EXISTS pg_partman SCHEMA partman; +CREATE EXTENSION IF NOT EXISTS pg_cron; +-- Telegraf (running as so_telegraf) calls partman.create_parent() +-- on first write of each metric, which needs USAGE on the partman +-- schema, EXECUTE on its functions/procedures, and write access to +-- partman.part_config so it can register new partitioned parents. +GRANT USAGE, CREATE ON SCHEMA partman TO so_telegraf; +GRANT SELECT, INSERT, UPDATE, DELETE ON ALL TABLES IN SCHEMA partman TO so_telegraf; +GRANT EXECUTE ON ALL FUNCTIONS IN SCHEMA partman TO so_telegraf; +GRANT EXECUTE ON ALL PROCEDURES IN SCHEMA partman TO so_telegraf; +-- partman creates per-parent template tables (partman.template_*) at +-- runtime; default privileges extend DML/sequence access to them. +ALTER DEFAULT PRIVILEGES IN SCHEMA partman + GRANT SELECT, INSERT, UPDATE, DELETE ON TABLES TO so_telegraf; +ALTER DEFAULT PRIVILEGES IN SCHEMA partman + GRANT USAGE, SELECT, UPDATE ON SEQUENCES TO so_telegraf; +-- Hourly partman maintenance. cron.schedule is idempotent by jobname. +SELECT cron.schedule( + 'telegraf-partman-maintenance', + '17 * * * *', + 'CALL partman.run_maintenance_proc()' +); +EOSQL + ;; + + user) + : "${ROLE_USER:?ROLE_USER is required}" + : "${ROLE_PASS:?ROLE_PASS is required}" + docker exec -i so-postgres psql \ + -v ON_ERROR_STOP=1 \ + -v role_user="$ROLE_USER" \ + -v role_pass="$ROLE_PASS" \ + -U postgres -d so_telegraf <<'EOSQL' +DO $$ +BEGIN + IF NOT EXISTS (SELECT FROM pg_catalog.pg_roles WHERE rolname = :role_user) THEN + EXECUTE format('CREATE ROLE %I WITH LOGIN PASSWORD %L', :role_user, :role_pass); + ELSE + EXECUTE format('ALTER ROLE %I WITH LOGIN PASSWORD %L', :role_user, :role_pass); + END IF; +END +$$; +GRANT CONNECT ON DATABASE so_telegraf TO :"role_user"; +GRANT so_telegraf TO :"role_user"; +EOSQL + ;; + + retention) + : "${RETENTION_DAYS:?RETENTION_DAYS is required}" + docker exec -i so-postgres psql \ + -v ON_ERROR_STOP=1 \ + -v retention_days="$RETENTION_DAYS" \ + -U postgres -d so_telegraf <<'EOSQL' +DO $$ +BEGIN + IF EXISTS (SELECT 1 FROM pg_catalog.pg_extension WHERE extname = 'pg_partman') THEN + UPDATE partman.part_config + SET retention = :'retention_days' || ' days', + retention_keep_table = false + WHERE parent_table LIKE 'telegraf.%'; + END IF; +END +$$; +EOSQL + ;; + + *) + echo "Unknown subcommand: $cmd" >&2 + exit 1 + ;; +esac diff --git a/salt/postgres/tools/sbin/telegraf_role.sh b/salt/postgres/tools/sbin/telegraf_role.sh deleted file mode 100644 index 352efa018..000000000 --- a/salt/postgres/tools/sbin/telegraf_role.sh +++ /dev/null @@ -1,23 +0,0 @@ -#!/bin/bash -set -e - -# Provision or update a Telegraf postgres role. -# Expects ROLE_USER and ROLE_PASS environment variables. - -docker exec -i so-postgres psql \ - -v ON_ERROR_STOP=1 \ - -v role_user="$ROLE_USER" \ - -v role_pass="$ROLE_PASS" \ - -U postgres -d so_telegraf <<'EOSQL' -DO $$ -BEGIN - IF NOT EXISTS (SELECT FROM pg_catalog.pg_roles WHERE rolname = :role_user) THEN - EXECUTE format('CREATE ROLE %I WITH LOGIN PASSWORD %L', :role_user, :role_pass); - ELSE - EXECUTE format('ALTER ROLE %I WITH LOGIN PASSWORD %L', :role_user, :role_pass); - END IF; -END -$$; -GRANT CONNECT ON DATABASE so_telegraf TO :"role_user"; -GRANT so_telegraf TO :"role_user"; -EOSQL From 8e38bff0c31ddbf7603dead157a741fafc708664 Mon Sep 17 00:00:00 2001 From: Mike Reeves Date: Thu, 14 May 2026 16:55:53 -0400 Subject: [PATCH 6/8] Rename telegraf_postgres.sh to so-telegraf-postgres --- salt/postgres/telegraf_users.sls | 8 ++++---- .../sbin/{telegraf_postgres.sh => so-telegraf-postgres} | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) rename salt/postgres/tools/sbin/{telegraf_postgres.sh => so-telegraf-postgres} (98%) diff --git a/salt/postgres/telegraf_users.sls b/salt/postgres/telegraf_users.sls index 4b95ac45b..b4226f1fd 100644 --- a/salt/postgres/telegraf_users.sls +++ b/salt/postgres/telegraf_users.sls @@ -44,7 +44,7 @@ postgres_wait_ready: # would otherwise never get so_telegraf. postgres_create_telegraf_db: cmd.run: - - name: /usr/sbin/telegraf_postgres.sh create_db + - name: /usr/sbin/so-telegraf-postgres create_db - require: - cmd: postgres_wait_ready - file: postgres_sbin @@ -55,7 +55,7 @@ postgres_create_telegraf_db: # on first write are owned by the group role and every member can INSERT/SELECT. postgres_telegraf_group_role: cmd.run: - - name: /usr/sbin/telegraf_postgres.sh group_role + - name: /usr/sbin/so-telegraf-postgres group_role - require: - cmd: postgres_create_telegraf_db - file: postgres_sbin @@ -68,7 +68,7 @@ postgres_telegraf_group_role: postgres_telegraf_role_{{ u }}: cmd.run: - - name: /usr/sbin/telegraf_postgres.sh user + - name: /usr/sbin/so-telegraf-postgres user - env: - ROLE_USER: {{ u }} - ROLE_PASS: {{ p }} @@ -86,7 +86,7 @@ postgres_telegraf_role_{{ u }}: {% set retention = salt['pillar.get']('postgres:telegraf:retention_days', 14) | int %} postgres_telegraf_retention_reconcile: cmd.run: - - name: /usr/sbin/telegraf_postgres.sh retention + - name: /usr/sbin/so-telegraf-postgres retention - env: - RETENTION_DAYS: {{ retention }} - require: diff --git a/salt/postgres/tools/sbin/telegraf_postgres.sh b/salt/postgres/tools/sbin/so-telegraf-postgres similarity index 98% rename from salt/postgres/tools/sbin/telegraf_postgres.sh rename to salt/postgres/tools/sbin/so-telegraf-postgres index 7f2061543..e15d4c450 100644 --- a/salt/postgres/tools/sbin/telegraf_postgres.sh +++ b/salt/postgres/tools/sbin/so-telegraf-postgres @@ -2,7 +2,7 @@ set -e # Provision Telegraf state inside the so-postgres container. -# Usage: telegraf_postgres.sh +# Usage: so-telegraf-postgres # create_db Ensure the so_telegraf database exists. # group_role Provision the so_telegraf group role, telegraf/partman schemas, # pg_partman, pg_cron, and the hourly partman maintenance job. From 249b126312641375450f0614e9b928948df2aa79 Mon Sep 17 00:00:00 2001 From: Mike Reeves Date: Thu, 14 May 2026 17:08:51 -0400 Subject: [PATCH 7/8] Quote telegraf role env vars to survive YAML-special chars in passwords --- salt/postgres/telegraf_users.sls | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/salt/postgres/telegraf_users.sls b/salt/postgres/telegraf_users.sls index b4226f1fd..28d9d6247 100644 --- a/salt/postgres/telegraf_users.sls +++ b/salt/postgres/telegraf_users.sls @@ -70,8 +70,8 @@ postgres_telegraf_role_{{ u }}: cmd.run: - name: /usr/sbin/so-telegraf-postgres user - env: - - ROLE_USER: {{ u }} - - ROLE_PASS: {{ p }} + - ROLE_USER: {{ u | tojson }} + - ROLE_PASS: {{ p | tojson }} - hide_output: True - require: - file: postgres_sbin From 64731c73ba954df47c4fad887d265f12ee1ca20b Mon Sep 17 00:00:00 2001 From: Mike Reeves Date: Thu, 14 May 2026 17:17:49 -0400 Subject: [PATCH 8/8] Fix psql :var substitution in telegraf role and retention SQL psql does not substitute :var references inside dollar-quoted strings, so the DO blocks in the user and retention subcommands were receiving literal colons and failing (silently for user, via hide_output: True). Rewrite the conditional CREATE/ALTER ROLE with SELECT format(...) \\gexec and guard the retention UPDATE with \\gset + \\if. --- salt/postgres/tools/sbin/so-telegraf-postgres | 40 ++++++++++--------- 1 file changed, 21 insertions(+), 19 deletions(-) diff --git a/salt/postgres/tools/sbin/so-telegraf-postgres b/salt/postgres/tools/sbin/so-telegraf-postgres index e15d4c450..ef7c3f9e6 100644 --- a/salt/postgres/tools/sbin/so-telegraf-postgres +++ b/salt/postgres/tools/sbin/so-telegraf-postgres @@ -63,20 +63,22 @@ EOSQL user) : "${ROLE_USER:?ROLE_USER is required}" : "${ROLE_PASS:?ROLE_PASS is required}" + # psql does not substitute :vars inside dollar-quoted strings, so the + # conditional CREATE/ALTER is built outside any DO block and dispatched + # with \gexec. format() handles identifier/literal quoting. docker exec -i so-postgres psql \ -v ON_ERROR_STOP=1 \ -v role_user="$ROLE_USER" \ -v role_pass="$ROLE_PASS" \ -U postgres -d so_telegraf <<'EOSQL' -DO $$ -BEGIN - IF NOT EXISTS (SELECT FROM pg_catalog.pg_roles WHERE rolname = :role_user) THEN - EXECUTE format('CREATE ROLE %I WITH LOGIN PASSWORD %L', :role_user, :role_pass); - ELSE - EXECUTE format('ALTER ROLE %I WITH LOGIN PASSWORD %L', :role_user, :role_pass); - END IF; -END -$$; +SELECT format( + CASE WHEN EXISTS (SELECT FROM pg_catalog.pg_roles WHERE rolname = :'role_user') + THEN 'ALTER ROLE %I WITH LOGIN PASSWORD %L' + ELSE 'CREATE ROLE %I WITH LOGIN PASSWORD %L' + END, + :'role_user', + :'role_pass' +) \gexec GRANT CONNECT ON DATABASE so_telegraf TO :"role_user"; GRANT so_telegraf TO :"role_user"; EOSQL @@ -84,20 +86,20 @@ EOSQL retention) : "${RETENTION_DAYS:?RETENTION_DAYS is required}" + # \gset + \if guards against a missing pg_partman without using a DO + # block (psql :var substitution doesn't reach into dollar-quoted code). docker exec -i so-postgres psql \ -v ON_ERROR_STOP=1 \ -v retention_days="$RETENTION_DAYS" \ -U postgres -d so_telegraf <<'EOSQL' -DO $$ -BEGIN - IF EXISTS (SELECT 1 FROM pg_catalog.pg_extension WHERE extname = 'pg_partman') THEN - UPDATE partman.part_config - SET retention = :'retention_days' || ' days', - retention_keep_table = false - WHERE parent_table LIKE 'telegraf.%'; - END IF; -END -$$; +SELECT CASE WHEN EXISTS (SELECT 1 FROM pg_catalog.pg_extension WHERE extname = 'pg_partman') + THEN 'true' ELSE 'false' END AS has_partman \gset +\if :has_partman +UPDATE partman.part_config +SET retention = :'retention_days' || ' days', + retention_keep_table = false +WHERE parent_table LIKE 'telegraf.%'; +\endif EOSQL ;;