Skip to content

Commit c3ae86f

Browse files
authored
fix: add missing extensions and correct UID defaults for pre-built images (#48)
Fixes #43: Pre-built images use UID 999, but .env defaults assumed host UID Fixes #47: Add missing contrib extensions to CORE_EXTENSION_LIST ## UID/GID Configuration (Issue #43) - Update .env.example to default POSTGRES_UID/GID to 999 (matches pre-built ghcr.io images) - Add documentation in README explaining UID requirements for pre-built vs local builds - Add validation in config render script to clamp PG_EFFECTIVE_IO_CONCURRENCY to range 0-1000 ## Missing Extensions (Issue #47) Add 7 new contrib extensions to CORE_EXTENSION_LIST: - cube (required dependency for earthdistance) - earthdistance (earth distance calculations) - intarray (integer array functions) - ltree (hierarchical tree structures) - pg_prewarm (buffer cache preloading) - tablefunc (crosstab/pivot functions) - unaccent (accent removal for text search) ## Tests & Documentation - Update pgtap smoke tests: 29 → 39 tests (add new extensions + bloom + pg_cron) - Update README extension bundle documentation
1 parent de00045 commit c3ae86f

5 files changed

Lines changed: 55 additions & 10 deletions

File tree

.env.example

Lines changed: 8 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -92,9 +92,11 @@ BACKUPS_HOST_PATH=./backups
9292
COMPOSE_PROFILES=valkey,pgbouncer,memcached,rabbitmq
9393

9494
# Container execution context
95-
# Defaults to the invoking user's UID/GID; override only if you need a specific account inside containers.
96-
POSTGRES_UID=
97-
POSTGRES_GID=
95+
# Pre-built images from ghcr.io use UID/GID 999 (the postgres user baked into the image).
96+
# If building locally with CORE_DATA_BUILD_IMAGE=1, you can set these to your host user's UID/GID.
97+
# WARNING: Mismatch between these values and the image's baked-in UID causes permission errors.
98+
POSTGRES_UID=999
99+
POSTGRES_GID=999
98100
POSTGRES_RUNTIME_USER=postgres
99101
POSTGRES_RUNTIME_GECOS=Core\ Data\ PostgreSQL\ Administrator
100102
POSTGRES_RUNTIME_HOME=/home/postgres
@@ -158,8 +160,9 @@ RABBITMQ_DEFAULT_USER=coredata
158160
RABBITMQ_DEFAULT_PASS_FILE=./secrets/rabbitmq_default_pass
159161
RABBITMQ_ERLANG_COOKIE_FILE=./secrets/rabbitmq_erlang_cookie
160162
RABBITMQ_DATA_MOUNT_PATH=/var/lib/rabbitmq
161-
RABBITMQ_UID=
162-
RABBITMQ_GID=
163+
# Pre-built RabbitMQ image uses UID/GID 999. Match POSTGRES_UID/GID for consistency.
164+
RABBITMQ_UID=999
165+
RABBITMQ_GID=999
163166

164167
# Time zone for containers
165168
TZ=UTC

README.md

Lines changed: 20 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -129,6 +129,23 @@ POSTGRES_IMAGE_NAME=ghcr.io/paudley/core-data-postgres
129129
POSTGRES_IMAGE_TAG=17.2-v1.0.0
130130
```
131131

132+
### Important: UID/GID Configuration for Pre-built Images
133+
134+
Pre-built images from `ghcr.io` have the `postgres` user baked in with **UID/GID 999**. Your `.env` must match:
135+
136+
```bash
137+
POSTGRES_UID=999
138+
POSTGRES_GID=999
139+
```
140+
141+
**Why this matters:** The `volume_prep` service uses these values to `chown` data directories. If they don't match the image's baked-in UID, you'll see permission errors like:
142+
143+
```
144+
chmod: changing permissions of '/var/lib/postgresql/data': Operation not permitted
145+
```
146+
147+
**Building locally?** If you set `CORE_DATA_BUILD_IMAGE=1`, you can use your host user's UID/GID instead—the image build process will create the postgres user with your specified IDs.
148+
132149
## Highlights
133150

134151
* Custom Docker image with PostGIS, pgvector, Apache AGE, pg\_cron, pg\_squeeze, pgAudit, pgBadger, pgBackRest, and pgtune baked in.
@@ -145,11 +162,11 @@ POSTGRES_IMAGE_TAG=17.2-v1.0.0
145162

146163
core\_data provisions a batteries-included extension stack in every non-template database at init time:
147164

148-
* **Performance & Observability**`pg_stat_statements`, `auto_explain`, `pg_buffercache`.
165+
* **Performance & Observability**`pg_stat_statements`, `auto_explain`, `pg_buffercache`, `pg_prewarm`, `bloom`.
149166
* **Security & Compliance**`pgaudit`, `pgcrypto`, `"uuid-ossp"`.
150-
* **Developer Ergonomics**`hstore`, `citext`, `pg_trgm`, `btree_gin`, `btree_gist`, `hypopg`.
167+
* **Developer Ergonomics**`hstore`, `citext`, `pg_trgm`, `btree_gin`, `btree_gist`, `hypopg`, `intarray`, `ltree`, `tablefunc`, `unaccent`.
151168
* **Connectivity**`postgres_fdw`, `dblink`.
152-
* **Spatial, Vector, Graph**`postgis`, `postgis_raster`, `postgis_topology`, `vector`, `age`.
169+
* **Spatial, Vector, Graph**`postgis`, `postgis_raster`, `postgis_topology`, `vector`, `age`, `cube`, `earthdistance`.
153170
* **Maintenance & Testing**`pg_cron` (kept in the `postgres` database), `pg_partman`, `pg_repack`, `pg_squeeze`, `pgstattuple`, `pgtap`.
154171
* **Geospatial Extras**`postgis_tiger_geocoder`, `address_standardizer`, `address_standardizer_data_us`, `pgrouting`, `fuzzystrmatch`.
155172

postgres/initdb/00-render-config.sh

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,14 @@ apply_network_allow_entries() {
5353
: "${PG_MAINTENANCE_WORK_MEM:=256MB}"
5454
: "${PG_RANDOM_PAGE_COST:=1.1}"
5555
: "${PG_EFFECTIVE_IO_CONCURRENCY:=200}"
56+
# PostgreSQL 17 accepts effective_io_concurrency in range 0-1000; clamp invalid values
57+
if [[ "${PG_EFFECTIVE_IO_CONCURRENCY}" -lt 0 ]]; then
58+
echo "[core_data] WARNING: PG_EFFECTIVE_IO_CONCURRENCY=${PG_EFFECTIVE_IO_CONCURRENCY} is negative; clamping to 0." >&2
59+
PG_EFFECTIVE_IO_CONCURRENCY=0
60+
elif [[ "${PG_EFFECTIVE_IO_CONCURRENCY}" -gt 1000 ]]; then
61+
echo "[core_data] WARNING: PG_EFFECTIVE_IO_CONCURRENCY=${PG_EFFECTIVE_IO_CONCURRENCY} exceeds max (1000); clamping to 1000." >&2
62+
PG_EFFECTIVE_IO_CONCURRENCY=1000
63+
fi
5664
: "${PG_MAX_WAL_SIZE:=2GB}"
5765
: "${PG_MIN_WAL_SIZE:=1GB}"
5866
: "${PG_WAL_KEEP_SIZE:=2GB}"

scripts/lib/extensions.sh

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -122,7 +122,7 @@ run_pgtap_smoke() {
122122
psql --set ON_ERROR_STOP=on --username "${POSTGRES_SUPERUSER:-postgres}" --dbname "${database}" <<'SQL'
123123
CREATE SCHEMA IF NOT EXISTS test_core_data;
124124
SET search_path = test_core_data, public;
125-
SELECT plan(29);
125+
SELECT plan(39);
126126
SELECT ok(current_schema = 'test_core_data', 'search_path set to test schema');
127127
SELECT has_extension('vector', 'vector extension installed');
128128
SELECT has_extension('postgis', 'postgis extension installed');
@@ -135,10 +135,12 @@ SELECT ok(position('auto_explain' in current_setting('shared_preload_libraries')
135135
SELECT has_extension('pg_buffercache', 'pg_buffercache extension installed');
136136
SELECT has_extension('pgcrypto', 'pgcrypto extension installed');
137137
SELECT has_extension('citext', 'citext extension installed');
138+
SELECT has_extension('cube', 'cube extension installed');
138139
SELECT has_extension('hstore', 'hstore extension installed');
139140
SELECT has_extension('pg_trgm', 'pg_trgm extension installed');
140141
SELECT has_extension('btree_gin', 'btree_gin extension installed');
141142
SELECT has_extension('btree_gist', 'btree_gist extension installed');
143+
SELECT has_extension('bloom', 'bloom extension installed');
142144
SELECT has_extension('postgres_fdw', 'postgres_fdw extension installed');
143145
SELECT has_extension('dblink', 'dblink extension installed');
144146
SELECT has_extension('uuid-ossp', 'uuid-ossp extension installed');
@@ -153,6 +155,13 @@ SELECT has_extension('address_standardizer_data_us', 'address_standardizer_data_
153155
SELECT has_extension('pgrouting', 'pgRouting extension installed');
154156
SELECT has_extension('hypopg', 'hypopg extension installed');
155157
SELECT has_extension('pg_partman', 'pg_partman extension installed');
158+
SELECT has_extension('pg_cron', 'pg_cron extension installed');
159+
SELECT has_extension('earthdistance', 'earthdistance extension installed');
160+
SELECT has_extension('intarray', 'intarray extension installed');
161+
SELECT has_extension('ltree', 'ltree extension installed');
162+
SELECT has_extension('pg_prewarm', 'pg_prewarm extension installed');
163+
SELECT has_extension('tablefunc', 'tablefunc extension installed');
164+
SELECT has_extension('unaccent', 'unaccent extension installed');
156165
SELECT * FROM finish();
157166
SQL
158167
}

scripts/lib/extensions_list.sh

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,19 +3,25 @@
33
# SPDX-License-Identifier: MIT
44

55
# Canonical list of default extensions enabled across bootstrap flows.
6+
# Note: Order matters for dependencies (e.g., cube must come before earthdistance)
67
# shellcheck disable=SC2034
78
CORE_EXTENSION_LIST=(
89
age
910
btree_gin
1011
btree_gist
1112
citext
13+
cube
1214
dblink
13-
hstore
15+
earthdistance
1416
fuzzystrmatch
17+
hstore
18+
intarray
19+
ltree
1520
bloom
1621
pg_buffercache
1722
pg_cron
1823
pg_partman
24+
pg_prewarm
1925
hypopg
2026
pg_repack
2127
pg_squeeze
@@ -33,6 +39,8 @@ CORE_EXTENSION_LIST=(
3339
address_standardizer_data_us
3440
postgis_tiger_geocoder
3541
pgrouting
42+
tablefunc
43+
unaccent
3644
uuid-ossp
3745
vector
3846
)

0 commit comments

Comments
 (0)