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"

Reply via email to