HIVE-29685: Fix LLAP UI status for non-YARN deployments - #6656
Conversation
|
There was a problem hiding this comment.
Pull request overview
This PR fixes the HiveServer2 LLAP status endpoint/UI (GET /llap and /llap.html) for non-YARN deployments (e.g., Kubernetes/Docker) by routing status discovery to the LLAP ZooKeeper registry when appropriate, while keeping the existing YARN path intact. It also cleans up the UI’s boolean rendering behavior and adds unit coverage for the new registry-based helpers.
Changes:
- Add config-based routing in
LlapStatusServiceDriverto populate status from the LLAP registry for non-YARN deployments, including running-threshold updates. - Harden/adjust LLAP UI rendering (avoid missing boolean PNG assets; add cache-busting query params).
- Add unit tests covering registry fallback behavior and helper logic.
Reviewed changes
Copilot reviewed 6 out of 6 changed files in this pull request and generated 3 comments.
Show a summary per file
| File | Description |
|---|---|
| service/src/resources/hive-webapps/static/js/llap.js | Disables boolean image rendering for LLAP UI JSON viewer options. |
| service/src/resources/hive-webapps/static/js/json.human.js | Adds defensive checks around boolean image rendering (path validation) and disables images when invalid. |
| service/src/resources/hive-webapps/hiveserver2/llap.html | Adds cache-buster query params for JS assets. |
| service/src/java/org/apache/hive/http/LlapServlet.java | Returns HTTP 500 when LLAP status lookup fails (instead of 200 with incomplete JSON). |
| llap-server/src/java/org/apache/hadoop/hive/llap/cli/status/LlapStatusServiceDriver.java | Implements registry-based status path + shared helpers; ensures runningThresholdAchieved is computed after successful lookups. |
| llap-server/src/test/org/apache/hadoop/hive/llap/cli/status/TestLlapStatusRegistryFallback.java | Adds unit tests for registry-only instance creation, state computation, config detection, and running-threshold logic. |
Suppressed comments (1)
service/src/resources/hive-webapps/static/js/json.human.js:445
- Using
String.prototype.startsWithhere can break option validation in older browsers that don't support it (e.g., IE 11). Use an ES5-safe prefix check so the bool image option handling doesn't throw at runtime.
if(boolOptions.showImage){
if(!boolOptions.img || !boolOptions.img.true || !boolOptions.img.false
|| !('' + boolOptions.img.true).startsWith('/static/')
|| !('' + boolOptions.img.false).startsWith('/static/')){
boolOptions.showImage = false;
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
| private static final EnumSet<State> NO_YARN_SERVICE_INFO_STATES = EnumSet.of( | ||
| State.APP_NOT_FOUND, State.COMPLETE, State.LAUNCHING); | ||
| State.COMPLETE, State.LAUNCHING); |
There was a problem hiding this comment.
Added an explicit early return when state is APP_NOT_FOUND on the YARN path, so we don’t continue into YARN Service/registry calls. K8s/Docker still uses the registry-only path via usesRegistryBasedLlapStatus() at the top of run().
| if (boolOpt.showImage && boolOpt.img && boolOpt.img.true && boolOpt.img.false | ||
| && ('' + boolOpt.img.true).startsWith('/static/') | ||
| && ('' + boolOpt.img.false).startsWith('/static/')) { |
There was a problem hiding this comment.
Replaced .startsWith('/static/') with .indexOf('/static/') === 0 in both places for IE11 compatibility.
| if (ret == ExitCode.SUCCESS) { | ||
| driver.outputJson(writer); | ||
| } else { | ||
| response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); | ||
| } |
There was a problem hiding this comment.
Added Cache-Control: no-store on the error path so proxies don’t cache failed status responses.
| if (NO_YARN_SERVICE_INFO_STATES.contains(appStatusBuilder.getState())) { | ||
| updateRunningThresholdAchieved(appStatusBuilder, cl.getRunningNodesThreshold()); |
There was a problem hiding this comment.
is updateRunningThresholdAchieved call needed here? This condition should be true only when state is Complete or Launching, but i believe in that case updateRunningThresholdAchieved just returns ?
There was a problem hiding this comment.
Call was a no-op here since the method only acts on RUNNING_PARTIAL/RUNNING_ALL. Removed it.
| private ExitCode populateAppStatusFromLlapRegistry(AppStatusBuilder appStatusBuilder, long watchTimeoutMs) | ||
| throws LlapStatusCliException { | ||
| return populateAppStatusFromLlapRegistry(appStatusBuilder, watchTimeoutMs, false); | ||
| } |
There was a problem hiding this comment.
there is no usages of this old definition, i think it can be removed.
There was a problem hiding this comment.
Removed the unused 2-arg wrapper; run() calls the 3-arg version directly.
…r YARN path, remove dead code, set no-store on servlet errors, and use IE11-safe path checks in json.human.js.
3cb47bb to
1846842
Compare
| <script src="/static/js/json.human.js?v=1"></script> | ||
| <script src="/static/js/llap.js?v=2"></script> |
There was a problem hiding this comment.
What is the reason for this change?
There was a problem hiding this comment.
Added ?v= during testing because browsers kept serving old cached llap.js/json.human.js (still pointing at missing PNGs), so the UI looked broken until a hard refresh. It's a standard cache-bust for upgrades — doesn't break anything or change how caching works.
That said, the actual fix is in the JS changes, so it's optional. As Per feedback I've removed the cache-busting params in the latest push
| } | ||
| } catch (Exception e) { | ||
| LOG.error("Caught exception while processing llap status request", e); | ||
| response.setStatus(HttpServletResponse.SC_INTERNAL_SERVER_ERROR); |
There was a problem hiding this comment.
Should we consider adding same Cache-Control: no-store in case of error here?
There was a problem hiding this comment.
Added Cache-Control: no-store in the catch block as well, same as the non-success path.
|



What changes were proposed in this pull request?
1.This PR fixes the HiveServer2 LLAP status page (/llap.html, backed by GET /llap) on non-YARN deployments such as Kubernetes and Docker. Today LlapServlet delegates to LlapStatusServiceDriver, which only queries YARN for the LLAP application. On K8s/Docker, LLAP daemons register in ZooKeeper instead of YARN, so the driver returns APP_NOT_FOUND and the UI never shows running instances.
2.The main change is config-based routing in LlapStatusServiceDriver: when the deployment is detected as non-YARN (via hive.server2.tez.use.external.sessions=true, tez.am.framework.mode=STANDALONE_ZOOKEEPER, or the override hive.llapcli.status.use-registry), status is populated from the LLAP ZK registry instead of YARN. For those deployments, worker UUIDs are used as container IDs when YARN container IDs are absent. The YARN path is unchanged for classic YARN LLAP.
3.This PR also fixes runningThresholdAchieved not being set for servlet/one-shot callers by calling updateRunningThresholdAchieved() after a successful registry or YARN status lookup. LlapServlet now returns HTTP 500 when status lookup fails. On the UI side, it removes references to missing boolean PNG assets in llap.js, adds a defensive guard in json.human.js so bool icons are only rendered for valid /static/ paths, and adds cache-buster query params in llap.html. Unit tests are added in TestLlapStatus
Why are the changes needed?
On Kubernetes and Docker, LLAP does not run as a YARN application. Daemons register in ZooKeeper, but the status driver only looked up YARN and returned early with APP_NOT_FOUND before consulting the registry. That broke /llap.html for operators running LLAP on K8s/Docker — they could not see cluster state, instance counts, or daemon web URLs from HiveServer2.
The runningThresholdAchieved field was also never set for the servlet path, so the UI always showed false even when all daemons were up. The broken boolean icon beside runningThresholdAchieved is a separate pre-existing UI bug (missing PNG assets since HIVE-13467); this PR fixes that as well so the page renders cleanly.
Does this PR introduce any user-facing change?
Yes. On non-YARN LLAP deployments, /llap.html and GET /llap now report the correct state (RUNNING_ALL / RUNNING_PARTIAL instead of APP_NOT_FOUND), show live instance counts and daemon web URLs from the registry, and set runningThresholdAchieved to true when the running threshold is met. On YARN LLAP deployments, behavior is unchanged. When status lookup fails, the servlet returns HTTP 500 instead of 200 with incomplete JSON. The LLAP UI no longer shows a broken image icon before boolean fields; it displays plain true/false text instead.
Before :

After:

How was this patch tested?
1.Unit tests were added in TestLlapStatusRegistryFallback.java covering registry instance creation (worker identity vs YARN container ID), state updates from instance counts, config-based detection of registry vs YARN status lookup, and runningThresholdAchieved logic. These were run with mvn test -pl llap-server -Dtest=TestLlapStatusRegistryFallback.
2.End-to-end testing used the Docker LLAP stack in packaging/src/docker/ with ./start-hive.sh --llap and a locally built apache/hive:4.3.0-SNAPSHOT image