Skip to content

Commit b5192a9

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 b5192a9

4 files changed

Lines changed: 78 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: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import os
2+
import tempfile
23
import pytest
34
from utils_pytest import *
45

@@ -852,6 +853,60 @@ def test_credentials_from_catalogs_conf_for_rest_server(
852853
pg_conn.rollback()
853854

854855

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

857912

0 commit comments

Comments
 (0)