Skip to content

Commit 3aa4348

Browse files
committed
Add configurable catalogs.conf path via GUC
New GUC pg_lake_iceberg.catalogs_conf_path controls the location of the catalog credentials file. Defaults to "catalogs.conf", which resolves to $PGDATA/catalogs.conf. Absolute paths are used as-is. The GUC is PGC_SIGHUP (reloadable) and superuser-only. Signed-off-by: sfc-gh-npuka <naisila.puka@snowflake.com>
1 parent 36b145f commit 3aa4348

4 files changed

Lines changed: 81 additions & 6 deletions

File tree

pg_lake_iceberg/include/pg_lake/rest_catalog/rest_catalog.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
#define REST_CATALOG_AUTH_TYPE_OAUTH2 (0)
2929
#define REST_CATALOG_AUTH_TYPE_HORIZON (1)
3030

31+
extern char *CatalogsConfPath;
3132
extern PGDLLEXPORT char *RestCatalogHost;
3233
extern char *RestCatalogOauthHostPath;
3334
extern char *RestCatalogClientId;

pg_lake_iceberg/src/init.c

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -253,6 +253,16 @@ _PG_init(void)
253253
GUC_UNIT_KB,
254254
NULL, NULL, NULL);
255255

256+
DefineCustomStringVariable("pg_lake_iceberg.catalogs_conf_path",
257+
gettext_noop("Path to the catalog credentials file. "
258+
"Defaults to $PGDATA/catalogs.conf."),
259+
NULL,
260+
&CatalogsConfPath,
261+
"catalogs.conf",
262+
PGC_SIGHUP,
263+
GUC_SUPERUSER_ONLY,
264+
NULL, NULL, NULL);
265+
256266
DefineCustomEnumVariable("pg_lake_iceberg.rest_catalog_auth_type",
257267
gettext_noop("Determines the format for the initial OAuth token requests."),
258268
NULL,

pg_lake_iceberg/src/rest_catalog/rest_catalog.c

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@
5959

6060

6161
/* determined by GUC */
62+
char *CatalogsConfPath = NULL;
6263
char *RestCatalogHost = "http://localhost:8181";
6364
char *RestCatalogOauthHostPath = "";
6465
char *RestCatalogClientId = NULL;
@@ -470,8 +471,6 @@ BlockDDLOnExtensionCatalogs(ProcessUtilityParams *processUtilityParams,
470471
}
471472

472473

473-
#define CATALOGS_CONF_FILENAME "catalogs.conf"
474-
475474
/*
476475
* LookupUserMappingOptions returns the user mapping options for the current
477476
* user on the given server, or NULL if no mapping exists. Checks for a
@@ -509,9 +508,13 @@ LookupUserMappingOptions(Oid serverid)
509508

510509

511510
/*
512-
* ReadCatalogsConfCredentials reads $PGDATA/catalogs.conf and extracts
513-
* credentials for the given server name. The file uses PostgreSQL's
514-
* standard key = value format with dotted keys:
511+
* ReadCatalogsConfCredentials reads the catalog credentials file and
512+
* extracts credentials for the given server name.
513+
*
514+
* The file path is pg_lake_iceberg.catalogs_conf_path. Relative paths
515+
* are resolved against the data directory.
516+
*
517+
* The file uses PostgreSQL's standard key = value format with dotted keys:
515518
*
516519
* horizon.client_id = 'platform_id'
517520
* horizon.client_secret = 'platform_secret'
@@ -535,7 +538,10 @@ ReadCatalogsConfCredentials(const char *serverName,
535538
bool found = false;
536539
int serverNameLen = strlen(serverName);
537540

538-
snprintf(path, MAXPGPATH, "%s/%s", DataDir, CATALOGS_CONF_FILENAME);
541+
if (is_absolute_path(CatalogsConfPath))
542+
strlcpy(path, CatalogsConfPath, MAXPGPATH);
543+
else
544+
snprintf(path, MAXPGPATH, "%s/%s", DataDir, CatalogsConfPath);
539545

540546
fp = AllocateFile(path, "r");
541547
if (fp == NULL)

pg_lake_table/tests/pytests/test_iceberg_catalog_server.py

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
import os
2+
import tempfile
3+
24
import pytest
35
from utils_pytest import *
46

@@ -852,6 +854,62 @@ def test_credentials_from_catalogs_conf_for_rest_server(
852854
pg_conn.rollback()
853855

854856

857+
def test_catalogs_conf_path_outside_pgdata(
858+
pg_conn,
859+
superuser_conn,
860+
s3,
861+
extension,
862+
with_default_location,
863+
):
864+
"""catalogs_conf_path GUC accepts an absolute path for the credentials file."""
865+
fd, tmp_path = tempfile.mkstemp(suffix=".conf", prefix="catalogs_")
866+
try:
867+
with os.fdopen(fd, "w") as f:
868+
f.write(
869+
"rest.client_id = 'external-id'\n"
870+
"rest.client_secret = 'external-secret'\n"
871+
)
872+
873+
run_command_outside_tx(
874+
[
875+
"ALTER SYSTEM SET pg_lake_iceberg.rest_catalog_client_id TO ''",
876+
"ALTER SYSTEM SET pg_lake_iceberg.rest_catalog_client_secret TO ''",
877+
f"ALTER SYSTEM SET pg_lake_iceberg.catalogs_conf_path TO '{tmp_path}'",
878+
"SELECT pg_reload_conf()",
879+
],
880+
)
881+
882+
# Use a fresh connection so its backend reads the updated
883+
# postgresql.auto.conf on startup — avoids SIGHUP race.
884+
fresh = open_pg_conn()
885+
try:
886+
err = run_command(
887+
"""
888+
CREATE TABLE test_ext_conf_tbl ()
889+
USING iceberg
890+
WITH (catalog = 'rest', read_only = 'true',
891+
catalog_namespace = 'ns', catalog_table_name = 'tbl')
892+
""",
893+
fresh,
894+
raise_error=False,
895+
)
896+
assert err is not None
897+
assert "no credentials found" not in str(err)
898+
finally:
899+
fresh.close()
900+
finally:
901+
run_command_outside_tx(
902+
[
903+
"ALTER SYSTEM RESET pg_lake_iceberg.catalogs_conf_path",
904+
"ALTER SYSTEM RESET pg_lake_iceberg.rest_catalog_client_id",
905+
"ALTER SYSTEM RESET pg_lake_iceberg.rest_catalog_client_secret",
906+
"SELECT pg_reload_conf()",
907+
],
908+
)
909+
if os.path.exists(tmp_path):
910+
os.remove(tmp_path)
911+
912+
855913
# ── Backward compatibility ─────────────────────────────────────────────────
856914

857915

0 commit comments

Comments
 (0)