This is an automated email from the ASF dual-hosted git repository. github-merge-queue[bot] pushed a commit to branch gh-readonly-queue/main/pr-3864-042165ace7e96b7d0da61810d1540c01ffff5157 in repository https://gitbox.apache.org/repos/asf/iceberg-python.git
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"
