From b3fbd5c7a46f99e02081aca011b48a63dd097431 Mon Sep 17 00:00:00 2001 From: Mike Reeves Date: Fri, 17 Apr 2026 14:55:13 -0400 Subject: [PATCH] Use Go-template placeholders and shell-guarded CREATE DATABASE - Telegraf's outputs.postgresql plugin uses Go text/template syntax, not uppercase tokens. The {TABLE}/{COLUMNS}/{TABLELITERAL} strings were passed through to Postgres literally, producing syntax errors on every metric's first write. Switch to {{ .table }}, {{ .columns }}, and {{ .table|quoteLiteral }} so partitioned parents and the partman create_parent() call succeed. - Replace the \gexec "CREATE DATABASE ... WHERE NOT EXISTS" idiom in both init-users.sh and telegraf_users.sls with an explicit shell conditional. The prior idiom occasionally fired CREATE DATABASE even when so_telegraf already existed, producing duplicate-key failures. --- salt/postgres/files/init-users.sh | 7 +++---- salt/postgres/telegraf_users.sls | 7 +++---- salt/telegraf/etc/telegraf.conf | 4 ++-- 3 files changed, 8 insertions(+), 10 deletions(-) diff --git a/salt/postgres/files/init-users.sh b/salt/postgres/files/init-users.sh index b07dfcdb0..e1be5df19 100644 --- a/salt/postgres/files/init-users.sh +++ b/salt/postgres/files/init-users.sh @@ -20,7 +20,6 @@ EOSQL # Bootstrap the Telegraf metrics database. Per-minion roles + schemas are # reconciled on every state.apply by postgres/telegraf_users.sls; this block # only ensures the shared database exists on first initialization. -psql -v ON_ERROR_STOP=1 --username "$POSTGRES_USER" --dbname "$POSTGRES_DB" <<-EOSQL - SELECT 'CREATE DATABASE so_telegraf' - WHERE NOT EXISTS (SELECT FROM pg_database WHERE datname = 'so_telegraf')\gexec -EOSQL +if ! psql -U "$POSTGRES_USER" -tAc "SELECT 1 FROM pg_database WHERE datname='so_telegraf'" | grep -q 1; then + psql -v ON_ERROR_STOP=1 -U "$POSTGRES_USER" -c "CREATE DATABASE so_telegraf" +fi diff --git a/salt/postgres/telegraf_users.sls b/salt/postgres/telegraf_users.sls index 920367fab..8972ce510 100644 --- a/salt/postgres/telegraf_users.sls +++ b/salt/postgres/telegraf_users.sls @@ -34,10 +34,9 @@ postgres_wait_ready: postgres_create_telegraf_db: cmd.run: - name: | - docker exec -i so-postgres psql -v ON_ERROR_STOP=1 -U postgres -d postgres <<'EOSQL' - SELECT 'CREATE DATABASE so_telegraf' - WHERE NOT EXISTS (SELECT FROM pg_database WHERE datname = 'so_telegraf')\gexec - EOSQL + 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 - require: - cmd: postgres_wait_ready diff --git a/salt/telegraf/etc/telegraf.conf b/salt/telegraf/etc/telegraf.conf index 334b62888..fd614a68b 100644 --- a/salt/telegraf/etc/telegraf.conf +++ b/salt/telegraf/etc/telegraf.conf @@ -110,8 +110,8 @@ # Every metric table is a daily time-range partitioned parent managed by # pg_partman. Retention drops old partitions instead of row-by-row DELETEs. create_templates = [ - '''CREATE TABLE {TABLE} ({COLUMNS}) PARTITION BY RANGE ("time")''', - '''SELECT partman.create_parent(p_parent_table := {TABLELITERAL}, p_control := 'time', p_type := 'range', p_interval := '1 day', p_premake := 3)''' + '''CREATE TABLE {{ .table }} ({{ .columns }}) PARTITION BY RANGE ("time")''', + '''SELECT partman.create_parent(p_parent_table := {{ .table|quoteLiteral }}, p_control := 'time', p_type := 'range', p_interval := '1 day', p_premake := 3)''' ] {%- endif %}