This is an automated email from the ASF dual-hosted git repository.
github-merge-queue[bot] pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/iceberg-python.git
The following commit(s) were added to refs/heads/main by this push:
new 9345369e8 Add `hive.kerberos-service-host` configuration option (#3864)
9345369e8 is described below
commit 9345369e8e7411e9351313bda2501df33b99c311
Author: ChanKyeong Won <[email protected]>
AuthorDate: Tue Oct 27 15:52:43 2026 +0000
Add `hive.kerberos-service-host` configuration option (#3864)
* Add hive.kerberos-service-host configuration option
* Skip the Kerberos transport test on Windows
* Resolve the Kerberos service host default in _HiveClient
---
mkdocs/docs/configuration.md | 1 +
pyiceberg/catalog/hive.py | 6 +++++-
tests/catalog/test_hive.py | 44 +++++++++++++++++++++++++++++++++++++++++---
3 files changed, 47 insertions(+), 4 deletions(-)
diff --git a/mkdocs/docs/configuration.md b/mkdocs/docs/configuration.md
index bd4470d08..da336cdcf 100644
--- a/mkdocs/docs/configuration.md
+++ b/mkdocs/docs/configuration.md
@@ -784,6 +784,7 @@ catalog:
| hive.hive2-compatible | true | Set to `true` when using a Hive 2.x
metastore |
| hive.kerberos-authentication | true | Using authentication via Kerberos
|
| hive.kerberos-service-name | hive | Kerberos service name (default
hive) |
+| hive.kerberos-service-host | hive-host | Kerberos service host (default
URI host) |
| ugi | t-1234:secret | Hadoop UGI for Hive
client. |
Hive 3 and newer need no extra configuration. When using a Hive 2.x metastore,
set the compatibility flag:
diff --git a/pyiceberg/catalog/hive.py b/pyiceberg/catalog/hive.py
index 2c48b4846..0f43bbfb8 100644
--- a/pyiceberg/catalog/hive.py
+++ b/pyiceberg/catalog/hive.py
@@ -132,6 +132,7 @@ HIVE_KERBEROS_AUTH = "hive.kerberos-authentication"
HIVE_KERBEROS_AUTH_DEFAULT = False
HIVE_KERBEROS_SERVICE_NAME = "hive.kerberos-service-name"
HIVE_KERBEROS_SERVICE_NAME_DEFAULT = "hive"
+HIVE_KERBEROS_SERVICE_HOST = "hive.kerberos-service-host"
LOCK_CHECK_MIN_WAIT_TIME = "lock-check-min-wait-time"
LOCK_CHECK_MAX_WAIT_TIME = "lock-check-max-wait-time"
@@ -158,10 +159,12 @@ class _HiveClient:
ugi: str | None = None,
kerberos_auth: bool | None = HIVE_KERBEROS_AUTH_DEFAULT,
kerberos_service_name: str | None = HIVE_KERBEROS_SERVICE_NAME,
+ kerberos_service_host: str | None = None,
):
self._uri = uri
self._kerberos_auth = kerberos_auth
self._kerberos_service_name = kerberos_service_name
+ self._kerberos_service_host = kerberos_service_host or
urlparse(uri).hostname
self._ugi = ugi.split(":") if ugi else None
self._transport = self._init_thrift_transport()
self._was_opened = False
@@ -172,7 +175,7 @@ class _HiveClient:
if not self._kerberos_auth:
return TTransport.TBufferedTransport(socket)
else:
- return TTransport.TSaslClientTransport(socket,
host=url_parts.hostname, service=self._kerberos_service_name)
+ return TTransport.TSaslClientTransport(socket,
host=self._kerberos_service_host, service=self._kerberos_service_name)
def _client(self) -> Client:
protocol = TBinaryProtocol.TBinaryProtocol(self._transport)
@@ -320,6 +323,7 @@ class HiveCatalog(MetastoreCatalog):
properties.get("ugi"),
property_as_bool(properties, HIVE_KERBEROS_AUTH,
HIVE_KERBEROS_AUTH_DEFAULT),
properties.get(HIVE_KERBEROS_SERVICE_NAME,
HIVE_KERBEROS_SERVICE_NAME_DEFAULT),
+ properties.get(HIVE_KERBEROS_SERVICE_HOST),
)
except BaseException as e:
last_exception = e
diff --git a/tests/catalog/test_hive.py b/tests/catalog/test_hive.py
index d247fe91a..2b1bb330e 100644
--- a/tests/catalog/test_hive.py
+++ b/tests/catalog/test_hive.py
@@ -52,6 +52,7 @@ from pyiceberg.catalog.hive import (
DO_NOT_UPDATE_STATS,
DO_NOT_UPDATE_STATS_DEFAULT,
HIVE_KERBEROS_AUTH,
+ HIVE_KERBEROS_SERVICE_HOST,
HIVE_KERBEROS_SERVICE_NAME,
LOCK_CHECK_MAX_WAIT_TIME,
LOCK_CHECK_MIN_WAIT_TIME,
@@ -1348,7 +1349,7 @@ def test_create_hive_client_success() -> None:
with patch("pyiceberg.catalog.hive._HiveClient", return_value=MagicMock())
as mock_hive_client:
client = HiveCatalog._create_hive_client(properties)
- mock_hive_client.assert_called_once_with("thrift://localhost:10000",
"user", False, "hive")
+ mock_hive_client.assert_called_once_with("thrift://localhost:10000",
"user", False, "hive", None)
assert client is not None
@@ -1361,7 +1362,21 @@ def test_create_hive_client_with_kerberos_success() ->
None:
}
with patch("pyiceberg.catalog.hive._HiveClient", return_value=MagicMock())
as mock_hive_client:
client = HiveCatalog._create_hive_client(properties)
- mock_hive_client.assert_called_once_with("thrift://localhost:10000",
"user", True, "hiveuser")
+ mock_hive_client.assert_called_once_with("thrift://localhost:10000",
"user", True, "hiveuser", None)
+ assert client is not None
+
+
+def test_create_hive_client_with_kerberos_service_host() -> None:
+ properties = {
+ "uri": "thrift://localhost:10000",
+ "ugi": "user",
+ HIVE_KERBEROS_AUTH: "true",
+ HIVE_KERBEROS_SERVICE_NAME: "hiveuser",
+ HIVE_KERBEROS_SERVICE_HOST: "hive-host.example.com",
+ }
+ with patch("pyiceberg.catalog.hive._HiveClient", return_value=MagicMock())
as mock_hive_client:
+ client = HiveCatalog._create_hive_client(properties)
+ mock_hive_client.assert_called_once_with("thrift://localhost:10000",
"user", True, "hiveuser", "hive-host.example.com")
assert client is not None
@@ -1374,7 +1389,10 @@ def test_create_hive_client_multiple_uris() -> None:
client = HiveCatalog._create_hive_client(properties)
assert mock_hive_client.call_count == 2
mock_hive_client.assert_has_calls(
- [call("thrift://localhost:10000", "user", False, "hive"),
call("thrift://localhost:10001", "user", False, "hive")]
+ [
+ call("thrift://localhost:10000", "user", False, "hive", None),
+ call("thrift://localhost:10001", "user", False, "hive", None),
+ ]
)
assert client is not None
@@ -1463,3 +1481,23 @@ def test_kerberized_client_uses_fresh_transport_on_reuse(
second_transport_id = id(client._transport)
assert first_transport_id != second_transport_id
+
+
[email protected](sys.platform == "win32", reason="Kerberos/puresasl not
available on Windows")
+def test_kerberized_client_uses_configured_service_host() -> None:
+ """The SASL host must come from hive.kerberos-service-host, or the URI
host when unset."""
+ configured = _HiveClient(
+ uri="thrift://metastore-lb:9083",
+ kerberos_auth=True,
+ kerberos_service_name="hive",
+ kerberos_service_host="metastore-host",
+ )
+ assert configured._transport.sasl.host == "metastore-host"
+ assert configured._transport.sasl.service == "hive"
+
+ default = _HiveClient(
+ uri="thrift://metastore-lb:9083",
+ kerberos_auth=True,
+ kerberos_service_name="hive",
+ )
+ assert default._transport.sasl.host == "metastore-lb"