This is an automated email from the ASF dual-hosted git repository.

deniskuzZ pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/hive.git


The following commit(s) were added to refs/heads/master by this push:
     new bd177f3d5eb HIVE-30012: Kubernetes operator and Helm fixes for running 
Hive on EKS (#6756)
bd177f3d5eb is described below

commit bd177f3d5ebd1cc202af6baff03bc5aec3c8ab98
Author: Denys Kuzmenko <[email protected]>
AuthorDate: Wed Sep 9 14:14:57 2026 +0200

    HIVE-30012: Kubernetes operator and Helm fixes for running Hive on EKS 
(#6756)
---
 packaging/src/docker/entrypoint.sh                 |   3 +-
 packaging/src/kubernetes/README.md                 |  48 +++---
 .../src/kubernetes/config/operator/deployment.yaml |   5 -
 .../crds/hiveclusters.hive.apache.org-v1.yml       | 170 +++++++++++++--------
 .../helm/hive-operator/templates/deployment.yaml   |   5 -
 .../helm/hive-operator/templates/hivecluster.yaml  |  58 ++++++-
 .../hive/kubernetes/operator/HiveOperatorMain.java |   8 +
 .../operator/dependent/HiveDependentResource.java  |  46 +++---
 .../dependent/HiveServer2DeploymentDependent.java  |  14 +-
 .../operator/dependent/LlapResourceBuilder.java    |  42 ++++-
 .../dependent/MetastoreDeploymentDependent.java    |   8 +-
 .../operator/dependent/ScratchPvcDependent.java    |   6 +-
 .../kubernetes/operator/model/HiveClusterSpec.java |   6 +-
 .../operator/model/spec/HiveServer2Spec.java       |  19 ++-
 .../kubernetes/operator/model/spec/LlapSpec.java   |  32 +++-
 .../operator/model/spec/MetastoreSpec.java         |  19 ++-
 .../model/spec/ResourceRequirementsSpec.java       |  42 -----
 .../kubernetes/operator/model/spec/TezAmSpec.java  |  21 ++-
 .../operator/reconciler/HiveClusterReconciler.java |  29 ++--
 .../operator/reconciler/HiveWorkflowSpec.java      |  13 +-
 .../hive/kubernetes/operator/util/ConfigUtils.java |   7 +-
 .../operator/util/HiveConfigBuilder.java           |  12 +-
 22 files changed, 402 insertions(+), 211 deletions(-)

diff --git a/packaging/src/docker/entrypoint.sh 
b/packaging/src/docker/entrypoint.sh
index a043ef09502..baa540efaf2 100644
--- a/packaging/src/docker/entrypoint.sh
+++ b/packaging/src/docker/entrypoint.sh
@@ -177,7 +177,8 @@ if [ -d "${HIVE_CUSTOM_CONF_DIR:-}" ]; then
   export TEZ_CONF_DIR=$HIVE_CONF_DIR
 fi
 
-export HADOOP_CLIENT_OPTS="${HADOOP_CLIENT_OPTS:-} -Xmx1G ${SERVICE_OPTS:-}"
+# default heap first so user-provided -Xmx wins (last one applies)
+export HADOOP_CLIENT_OPTS="-Xmx1G ${HADOOP_CLIENT_OPTS:-} ${SERVICE_OPTS:-}"
 if [[ "${SKIP_SCHEMA_INIT}" == "false" && ( "${SERVICE_NAME}" == "hiveserver2" 
|| "${SERVICE_NAME}" == "metastore" ) ]]; then
   # handles schema initialization
   initialize_hive
diff --git a/packaging/src/kubernetes/README.md 
b/packaging/src/kubernetes/README.md
index 1135413f612..c1cd9fe87b6 100644
--- a/packaging/src/kubernetes/README.md
+++ b/packaging/src/kubernetes/README.md
@@ -111,12 +111,20 @@ and an equivalent values file.
 Each example below shows both the `helm install` CLI command and the equivalent
 `values.yaml` file. Use whichever approach you prefer.
 
+> **Give each cluster its own release name.** `<release>-hive-operator` is a 
ClusterRole, so
+> a second cluster under the same release name fails even in another 
namespace. Naming the
+> release after its namespace is enough, since namespaces are already unique:
+>
+> ```bash
+> export RELEASE=hive-dev
+> ```
+
 ### Ozone (Full-HA, default behavior)
 
 **CLI:**
 
 ```bash
-helm install hive ./helm/hive-operator \
+helm install "$RELEASE" ./helm/hive-operator \
   --set cluster.database.type=postgres \
   --set 
cluster.database.url="jdbc:postgresql://postgres-postgresql:5432/metastore" \
   --set cluster.database.driver="org.postgresql.Driver" \
@@ -169,7 +177,7 @@ cluster:
 ```
 
 ```bash
-helm install hive ./helm/hive-operator -f values.yaml
+helm install "$RELEASE" ./helm/hive-operator -f values.yaml
 ```
 
 ---
@@ -188,7 +196,7 @@ kubectl create secret generic aws-s3-creds \
 Then install the operator and HiveCluster with the appropriate storage config:
 
 ```bash
-helm install hive ./helm/hive-operator \
+helm install "$RELEASE" ./helm/hive-operator \
   --set cluster.database.type=postgres \
   --set 
cluster.database.url="jdbc:postgresql://postgres-postgresql:5432/metastore" \
   --set cluster.database.driver="org.postgresql.Driver" \
@@ -245,7 +253,7 @@ cluster:
 ```
 
 ```bash
-helm install hive ./helm/hive-operator -f values.yaml
+helm install "$RELEASE" ./helm/hive-operator -f values.yaml
 ```
 
 ---
@@ -261,7 +269,7 @@ kubectl create secret generic gcs-creds  
--from-file=key.json=<PATH>.json
 **CLI:**
 
 ```bash
-helm install hive ./helm/hive-operator \
+helm install "$RELEASE" ./helm/hive-operator \
   --set cluster.database.type=postgres \
   --set 
cluster.database.url="jdbc:postgresql://postgres-postgresql:5432/metastore" \
   --set cluster.database.driver="org.postgresql.Driver" \
@@ -321,7 +329,7 @@ cluster:
 ```
 
 ```bash
-helm install hive ./helm/hive-operator -f values.yaml
+helm install "$RELEASE" ./helm/hive-operator -f values.yaml
 ```
 
 ---
@@ -333,7 +341,7 @@ helm install hive ./helm/hive-operator -f values.yaml
 **CLI:**
 
 ```bash
-helm install hive ./helm/hive-operator \
+helm install "$RELEASE" ./helm/hive-operator \
   --set cluster.database.type=postgres \
   --set 
cluster.database.url="jdbc:postgresql://postgres-postgresql:5432/metastore" \
   --set cluster.database.driver="org.postgresql.Driver" \
@@ -398,7 +406,7 @@ cluster:
 ```
 
 ```bash
-helm install hive ./helm/hive-operator -f values.yaml
+helm install "$RELEASE" ./helm/hive-operator -f values.yaml
 ```
 
 ---
@@ -408,7 +416,7 @@ helm install hive ./helm/hive-operator -f values.yaml
 **CLI:**
 
 ```bash
-helm install hive ./helm/hive-operator \
+helm install "$RELEASE" ./helm/hive-operator \
   --set cluster.zookeeper.quorum="zookeeper:2181" \
   --set cluster.metastore.enabled=false \
   --set cluster.metastore.externalUri="thrift://my-external-metastore:9083" \
@@ -448,7 +456,7 @@ cluster:
 ```
 
 ```bash
-helm install hive ./helm/hive-operator -f values.yaml
+helm install "$RELEASE" ./helm/hive-operator -f values.yaml
 ```
 
 ---
@@ -492,7 +500,7 @@ cluster:
 ```
 
 ```bash
-helm install hive ./helm/hive-operator -f values.yaml
+helm install "$RELEASE" ./helm/hive-operator -f values.yaml
 ```
 
 ---
@@ -609,7 +617,7 @@ cluster:
 ```
 
 ```bash
-helm install hive ./helm/hive-operator -f values-multi-tenant.yaml
+helm install "$RELEASE" ./helm/hive-operator -f values-multi-tenant.yaml
 ```
 
 ### Resulting Kubernetes Resources
@@ -693,7 +701,7 @@ This means scaling up `production` never affects 
`analytics` or `dev` replicas.
 To add a new cluster, append to `llapClusters[]` and run `helm upgrade`:
 
 ```bash
-helm upgrade hive ./helm/hive-operator -f values-multi-tenant.yaml
+helm upgrade "$RELEASE" ./helm/hive-operator -f values-multi-tenant.yaml
 ```
 
 To remove a cluster, delete the entry from `llapClusters[]` and upgrade. The 
operator
@@ -1106,7 +1114,7 @@ Each component has sensible per-component defaults (see 
[Configuration Reference
 Only `enabled=true` is needed to turn on autoscaling:
 
 ```bash
-helm install hive ./helm/hive-operator \
+helm install "$RELEASE" ./helm/hive-operator \
   --set cluster.database.type=postgres \
   --set 
cluster.database.url="jdbc:postgresql://postgres-postgresql:5432/metastore" \
   --set cluster.database.driver="org.postgresql.Driver" \
@@ -1208,7 +1216,7 @@ cluster:
 ```
 
 ```bash
-helm install hive ./helm/hive-operator -f values-autoscaling.yaml
+helm install "$RELEASE" ./helm/hive-operator -f values-autoscaling.yaml
 ```
 
 When autoscaling is enabled, the operator automatically:
@@ -1468,7 +1476,7 @@ controls shared settings (enabled flag, scratch PVC). 
Per-LLAP TezAM settings
 ### Upgrade (values only, no CRD changes)
 
 ```bash
-helm upgrade hive ./helm/hive-operator -f my-values.yaml
+helm upgrade "$RELEASE" ./helm/hive-operator -f my-values.yaml
 ```
 
 ### Upgrade (with CRD schema changes)
@@ -1479,14 +1487,14 @@ re-apply the CRD manually:
 
 ```bash
 kubectl apply -f helm/hive-operator/crds/hiveclusters.hive.apache.org-v1.yml
-helm upgrade hive ./helm/hive-operator -f my-values.yaml
+helm upgrade "$RELEASE" ./helm/hive-operator -f my-values.yaml
 ```
 
 ### Full Uninstall and Reinstall (clean slate)
 
 ```bash
 # Uninstall (removes operator + HiveCluster CR + all managed pods)
-helm uninstall hive
+helm uninstall "$RELEASE"
 
 # IMPORTANT: Always delete the CRD before reinstalling to ensure
 # the updated schema is applied. Helm only creates CRDs on install,
@@ -1494,14 +1502,14 @@ helm uninstall hive
 kubectl delete crd hiveclusters.hive.apache.org
 
 # Reinstall
-helm install hive ./helm/hive-operator -f my-values.yaml
+helm install "$RELEASE" ./helm/hive-operator -f my-values.yaml
 ```
 
 ### Remove Everything (including dependencies)
 
 ```bash
 kubectl delete hivecluster --all -A --wait=false --ignore-not-found
-helm uninstall hive --ignore-not-found
+helm uninstall "$RELEASE" --ignore-not-found
 kubectl delete crd hiveclusters.hive.apache.org --wait=false --ignore-not-found
 helm uninstall ozone --ignore-not-found
 helm uninstall postgres --ignore-not-found
diff --git a/packaging/src/kubernetes/config/operator/deployment.yaml 
b/packaging/src/kubernetes/config/operator/deployment.yaml
index b7d9625daac..106cfdee2c5 100644
--- a/packaging/src/kubernetes/config/operator/deployment.yaml
+++ b/packaging/src/kubernetes/config/operator/deployment.yaml
@@ -35,11 +35,6 @@ spec:
         - name: hive-operator
           image: apache/hive:operator-${HIVE_VERSION}
           imagePullPolicy: IfNotPresent
-          env:
-            - name: OPERATOR_NAMESPACE
-              valueFrom:
-                fieldRef:
-                  fieldPath: metadata.namespace
           resources:
             requests:
               cpu: 200m
diff --git 
a/packaging/src/kubernetes/helm/hive-operator/crds/hiveclusters.hive.apache.org-v1.yml
 
b/packaging/src/kubernetes/helm/hive-operator/crds/hiveclusters.hive.apache.org-v1.yml
index 9bdb3863c52..516e4309d28 100644
--- 
a/packaging/src/kubernetes/helm/hive-operator/crds/hiveclusters.hive.apache.org-v1.yml
+++ 
b/packaging/src/kubernetes/helm/hive-operator/crds/hiveclusters.hive.apache.org-v1.yml
@@ -79,6 +79,11 @@ spec:
               hiveServer2:
                 description: HiveServer2 component configuration
                 properties:
+                  affinity:
+                    description: Affinity override; replaces the default 
spread anti-affinity
+                      when set
+                    type: object
+                    x-kubernetes-preserve-unknown-fields: true
                   autoscaling:
                     description: "Autoscaling configuration (operator-driven, 
no external\
                       \ dependencies)"
@@ -154,6 +159,13 @@ spec:
                       type: string
                     description: Additional configuration overrides as 
key-value pairs
                     type: object
+                  envVars:
+                    description: "Component-scoped env vars, appended after 
the cluster-wide\
+                      \ envVars"
+                    items:
+                      type: object
+                    type: array
+                    x-kubernetes-preserve-unknown-fields: true
                   externalJars:
                     description: 'List of URIs to external JARs to download 
and add
                       to HS2 classpath '
@@ -224,28 +236,24 @@ spec:
                     description: Number of replicas
                     type: integer
                   resources:
+                    default:
+                      requests:
+                        cpu: 500m
+                        memory: 1Gi
                     description: Resource requirements for pods
-                    properties:
-                      limitsCpu:
-                        description: "CPU limit (e.g. 2, 1000m)"
-                        type: string
-                      limitsMemory:
-                        description: "Memory limit (e.g. 2Gi, 1024Mi)"
-                        type: string
-                      requestsCpu:
-                        default: 500m
-                        description: "CPU request (e.g. 500m, 1)"
-                        type: string
-                      requestsMemory:
-                        default: 1Gi
-                        description: "Memory request (e.g. 1Gi, 512Mi)"
-                        type: string
                     type: object
+                    x-kubernetes-preserve-unknown-fields: true
                   serviceType:
                     default: ClusterIP
                     description: "Kubernetes Service type: ClusterIP, 
LoadBalancer,\
                       \ or NodePort"
                     type: string
+                  tolerations:
+                    description: Tolerations for scheduling onto tainted nodes
+                    items:
+                      type: object
+                    type: array
+                    x-kubernetes-preserve-unknown-fields: true
                 type: object
                 x-kubernetes-preserve-unknown-fields: true
               image:
@@ -267,6 +275,11 @@ spec:
                   \ in their session."
                 items:
                   properties:
+                    affinity:
+                      description: Affinity override; replaces the default 
spread
+                        anti-affinity when set
+                      type: object
+                      x-kubernetes-preserve-unknown-fields: true
                     autoscaling:
                       description: "Autoscaling configuration 
(operator-driven, no\
                         \ external dependencies)"
@@ -348,6 +361,13 @@ spec:
                       default: true
                       description: Whether LLAP is enabled
                       type: boolean
+                    envVars:
+                      description: "Component-scoped env vars, appended after 
the\
+                        \ cluster-wide envVars"
+                      items:
+                        type: object
+                      type: array
+                      x-kubernetes-preserve-unknown-fields: true
                     executors:
                       default: 1
                       description: Number of LLAP executors per daemon
@@ -402,23 +422,13 @@ spec:
                       description: Number of replicas
                       type: integer
                     resources:
+                      default:
+                        requests:
+                          cpu: 500m
+                          memory: 1Gi
                       description: Resource requirements for pods
-                      properties:
-                        limitsCpu:
-                          description: "CPU limit (e.g. 2, 1000m)"
-                          type: string
-                        limitsMemory:
-                          description: "Memory limit (e.g. 2Gi, 1024Mi)"
-                          type: string
-                        requestsCpu:
-                          default: 500m
-                          description: "CPU request (e.g. 500m, 1)"
-                          type: string
-                        requestsMemory:
-                          default: 1Gi
-                          description: "Memory request (e.g. 1Gi, 512Mi)"
-                          type: string
                       type: object
+                      x-kubernetes-preserve-unknown-fields: true
                     serviceHosts:
                       description: "LLAP service hosts identifier for 
ZooKeeper registration.\
                         \ Defaults to @{name} (e.g. @llap0)."
@@ -427,6 +437,12 @@ spec:
                       description: Per-LLAP TezAM configuration. Each LLAP 
cluster
                         gets its own TezAM with independent replica count and 
autoscaling.
                       properties:
+                        affinity:
+                          description: "Affinity for this LLAP cluster's 
TezAM, overriding\
+                            \ spec.tezAm.affinity. Set it with more than one 
LLAP\
+                            \ cluster."
+                          type: object
+                          x-kubernetes-preserve-unknown-fields: true
                         autoscaling:
                           description: Autoscaling configuration for this LLAP 
cluster's
                             TezAM
@@ -504,7 +520,21 @@ spec:
                           description: Max number of TezAM replicas for this 
LLAP
                             cluster
                           type: integer
+                        tolerations:
+                          description: "Tolerations for this LLAP cluster's 
TezAM,\
+                            \ overriding spec.tezAm.tolerations"
+                          items:
+                            type: object
+                          type: array
+                          x-kubernetes-preserve-unknown-fields: true
                       type: object
+                      x-kubernetes-preserve-unknown-fields: true
+                    tolerations:
+                      description: Tolerations for scheduling onto tainted 
nodes
+                      items:
+                        type: object
+                      type: array
+                      x-kubernetes-preserve-unknown-fields: true
                   required:
                   - name
                   type: object
@@ -513,6 +543,11 @@ spec:
               metastore:
                 description: Metastore component configuration
                 properties:
+                  affinity:
+                    description: Affinity override; replaces the default 
spread anti-affinity
+                      when set
+                    type: object
+                    x-kubernetes-preserve-unknown-fields: true
                   autoscaling:
                     description: "Autoscaling configuration (operator-driven, 
no external\
                       \ dependencies)"
@@ -625,6 +660,13 @@ spec:
                     default: true
                     description: Whether the operator should deploy and manage 
a Metastore
                     type: boolean
+                  envVars:
+                    description: "Component-scoped env vars, appended after 
the cluster-wide\
+                      \ envVars"
+                    items:
+                      type: object
+                    type: array
+                    x-kubernetes-preserve-unknown-fields: true
                   externalUri:
                     description: Thrift URI of the external Metastore (if 
enabled
                       is false)
@@ -693,23 +735,19 @@ spec:
                     description: Number of replicas
                     type: integer
                   resources:
+                    default:
+                      requests:
+                        cpu: 500m
+                        memory: 1Gi
                     description: Resource requirements for pods
-                    properties:
-                      limitsCpu:
-                        description: "CPU limit (e.g. 2, 1000m)"
-                        type: string
-                      limitsMemory:
-                        description: "Memory limit (e.g. 2Gi, 1024Mi)"
-                        type: string
-                      requestsCpu:
-                        default: 500m
-                        description: "CPU request (e.g. 500m, 1)"
-                        type: string
-                      requestsMemory:
-                        default: 1Gi
-                        description: "Memory request (e.g. 1Gi, 512Mi)"
-                        type: string
                     type: object
+                    x-kubernetes-preserve-unknown-fields: true
+                  tolerations:
+                    description: Tolerations for scheduling onto tainted nodes
+                    items:
+                      type: object
+                    type: array
+                    x-kubernetes-preserve-unknown-fields: true
                   warehouseDir:
                     default: /hive/warehouse
                     description: Warehouse directory path
@@ -727,6 +765,11 @@ spec:
               tezAm:
                 description: Tez Application Master configuration. Enabled by 
default.
                 properties:
+                  affinity:
+                    description: Affinity override; replaces the default 
spread anti-affinity
+                      when set
+                    type: object
+                    x-kubernetes-preserve-unknown-fields: true
                   autoscaling:
                     description: "Autoscaling configuration (operator-driven, 
no external\
                       \ dependencies)"
@@ -806,6 +849,13 @@ spec:
                     default: true
                     description: Whether Tez AM is enabled
                     type: boolean
+                  envVars:
+                    description: "Component-scoped env vars, appended after 
the cluster-wide\
+                      \ envVars"
+                    items:
+                      type: object
+                    type: array
+                    x-kubernetes-preserve-unknown-fields: true
                   extraVolumeMounts:
                     description: Additional volume mounts for the container
                     items:
@@ -824,32 +874,28 @@ spec:
                     description: Number of replicas
                     type: integer
                   resources:
+                    default:
+                      requests:
+                        cpu: 500m
+                        memory: 1Gi
                     description: Resource requirements for pods
-                    properties:
-                      limitsCpu:
-                        description: "CPU limit (e.g. 2, 1000m)"
-                        type: string
-                      limitsMemory:
-                        description: "Memory limit (e.g. 2Gi, 1024Mi)"
-                        type: string
-                      requestsCpu:
-                        default: 500m
-                        description: "CPU request (e.g. 500m, 1)"
-                        type: string
-                      requestsMemory:
-                        default: 1Gi
-                        description: "Memory request (e.g. 1Gi, 512Mi)"
-                        type: string
                     type: object
+                    x-kubernetes-preserve-unknown-fields: true
                   scratchStorageClassName:
                     description: "StorageClass for the shared scratch PVC. 
Must support\
                       \ ReadWriteMany access. If null, uses cluster default."
                     type: string
                   scratchStorageSize:
                     default: 1Gi
-                    description: Storage size for the shared scratch PVC 
(ReadWriteMany)
-                      mounted on HS2 and TezAM at /opt/hive/scratch
+                    description: "Storage size for the shared scratch PVC 
(ReadWriteMany)\
+                      \ mounted on HS2, TezAM and LLAP at /opt/hive/scratch"
                     type: string
+                  tolerations:
+                    description: Tolerations for scheduling onto tainted nodes
+                    items:
+                      type: object
+                    type: array
+                    x-kubernetes-preserve-unknown-fields: true
                 type: object
                 x-kubernetes-preserve-unknown-fields: true
               volumeMounts:
diff --git 
a/packaging/src/kubernetes/helm/hive-operator/templates/deployment.yaml 
b/packaging/src/kubernetes/helm/hive-operator/templates/deployment.yaml
index 1c57badfeec..575fb31db0e 100644
--- a/packaging/src/kubernetes/helm/hive-operator/templates/deployment.yaml
+++ b/packaging/src/kubernetes/helm/hive-operator/templates/deployment.yaml
@@ -37,10 +37,5 @@ spec:
         - name: operator
           image: "{{ .Values.operator.image.repository }}:{{ 
.Values.operator.image.tag }}"
           imagePullPolicy: {{ .Values.operator.image.pullPolicy }}
-          env:
-            - name: OPERATOR_NAMESPACE
-              valueFrom:
-                fieldRef:
-                  fieldPath: metadata.namespace
           resources:
             {{- toYaml .Values.operator.resources | nindent 12 }}
diff --git 
a/packaging/src/kubernetes/helm/hive-operator/templates/hivecluster.yaml 
b/packaging/src/kubernetes/helm/hive-operator/templates/hivecluster.yaml
index a2b465ba0b3..6fd7fcb4fc1 100644
--- a/packaging/src/kubernetes/helm/hive-operator/templates/hivecluster.yaml
+++ b/packaging/src/kubernetes/helm/hive-operator/templates/hivecluster.yaml
@@ -70,6 +70,18 @@ spec:
     extraVolumeMounts:
       {{- toYaml .Values.cluster.metastore.extraVolumeMounts | nindent 6 }}
     {{- end }}
+    {{- if .Values.cluster.metastore.tolerations }}
+    tolerations:
+      {{- toYaml .Values.cluster.metastore.tolerations | nindent 6 }}
+    {{- end }}
+    {{- if .Values.cluster.metastore.affinity }}
+    affinity:
+      {{- toYaml .Values.cluster.metastore.affinity | nindent 6 }}
+    {{- end }}
+    {{- if .Values.cluster.metastore.envVars }}
+    envVars:
+      {{- toYaml .Values.cluster.metastore.envVars | nindent 6 }}
+    {{- end }}
     {{- if and .Values.cluster.metastore.autoscaling 
.Values.cluster.metastore.autoscaling.enabled }}
     autoscaling:
       enabled: true
@@ -103,6 +115,18 @@ spec:
     externalJars:
       {{- toYaml .Values.cluster.hiveServer2.externalJars | nindent 6 }}
     {{- end }}
+    {{- if .Values.cluster.hiveServer2.tolerations }}
+    tolerations:
+      {{- toYaml .Values.cluster.hiveServer2.tolerations | nindent 6 }}
+    {{- end }}
+    {{- if .Values.cluster.hiveServer2.affinity }}
+    affinity:
+      {{- toYaml .Values.cluster.hiveServer2.affinity | nindent 6 }}
+    {{- end }}
+    {{- if .Values.cluster.hiveServer2.envVars }}
+    envVars:
+      {{- toYaml .Values.cluster.hiveServer2.envVars | nindent 6 }}
+    {{- end }}
     {{- if .Values.cluster.hiveServer2.extraVolumes }}
     extraVolumes:
       {{- toYaml .Values.cluster.hiveServer2.extraVolumes | nindent 6 }}
@@ -144,6 +168,10 @@ spec:
     configOverrides:
       {{- toYaml .configOverrides | nindent 6 }}
     {{- end }}
+    {{- if .envVars }}
+    envVars:
+      {{- toYaml .envVars | nindent 6 }}
+    {{- end }}
     {{- if .extraVolumes }}
     extraVolumes:
       {{- toYaml .extraVolumes | nindent 6 }}
@@ -152,6 +180,14 @@ spec:
     extraVolumeMounts:
       {{- toYaml .extraVolumeMounts | nindent 6 }}
     {{- end }}
+    {{- if .tolerations }}
+    tolerations:
+      {{- toYaml .tolerations | nindent 6 }}
+    {{- end }}
+    {{- if .affinity }}
+    affinity:
+      {{- toYaml .affinity | nindent 6 }}
+    {{- end }}
     {{- if and .autoscaling .autoscaling.enabled }}
     autoscaling:
       enabled: true
@@ -166,6 +202,14 @@ spec:
     {{- if .tezAm }}
     tezAm:
       replicas: {{ .tezAm.replicas | default 1 }}
+      {{- if .tezAm.affinity }}
+      affinity:
+        {{- toYaml .tezAm.affinity | nindent 8 }}
+      {{- end }}
+      {{- if .tezAm.tolerations }}
+      tolerations:
+        {{- toYaml .tezAm.tolerations | nindent 8 }}
+      {{- end }}
       {{- if and .tezAm.autoscaling .tezAm.autoscaling.enabled }}
       autoscaling:
         enabled: true
@@ -202,6 +246,18 @@ spec:
     extraVolumeMounts:
       {{- toYaml .Values.cluster.tezAm.extraVolumeMounts | nindent 6 }}
     {{- end }}
+    {{- if .Values.cluster.tezAm.tolerations }}
+    tolerations:
+      {{- toYaml .Values.cluster.tezAm.tolerations | nindent 6 }}
+    {{- end }}
+    {{- if .Values.cluster.tezAm.affinity }}
+    affinity:
+      {{- toYaml .Values.cluster.tezAm.affinity | nindent 6 }}
+    {{- end }}
+    {{- if .Values.cluster.tezAm.envVars }}
+    envVars:
+      {{- toYaml .Values.cluster.tezAm.envVars | nindent 6 }}
+    {{- end }}
     {{- if and .Values.cluster.tezAm.autoscaling 
.Values.cluster.tezAm.autoscaling.enabled }}
     autoscaling:
       enabled: true
@@ -251,5 +307,5 @@ spec:
     {{- end }}
   {{- end }}
 
-  suspend: false
+  suspend: {{ .Values.cluster.suspend | default false }}
 {{- end }}
diff --git 
a/packaging/src/kubernetes/src/java/org/apache/hive/kubernetes/operator/HiveOperatorMain.java
 
b/packaging/src/kubernetes/src/java/org/apache/hive/kubernetes/operator/HiveOperatorMain.java
index a3d23c752c6..319141b1b3e 100644
--- 
a/packaging/src/kubernetes/src/java/org/apache/hive/kubernetes/operator/HiveOperatorMain.java
+++ 
b/packaging/src/kubernetes/src/java/org/apache/hive/kubernetes/operator/HiveOperatorMain.java
@@ -22,6 +22,7 @@
 import io.javaoperatorsdk.operator.Operator;
 import io.javaoperatorsdk.operator.api.config.ControllerConfiguration;
 import io.javaoperatorsdk.operator.api.config.ResolvedControllerConfiguration;
+import io.javaoperatorsdk.operator.api.config.ControllerConfigurationOverrider;
 import org.apache.hive.kubernetes.operator.model.HiveCluster;
 import org.apache.hive.kubernetes.operator.reconciler.HiveClusterReconciler;
 import org.apache.hive.kubernetes.operator.reconciler.HiveWorkflowSpec;
@@ -45,6 +46,13 @@ public static void main(String[] args) {
     // Get the annotation-derived base config, then inject our programmatic 
workflow spec.
     ControllerConfiguration<HiveCluster> baseConfig =
         operator.getConfigurationService().getConfigurationFor(reconciler);
+
+    // Watch only our own namespace: cluster-wide, a HiveCluster elsewhere 
using a field this
+    // build does not know fails to deserialise in the informer, which stops 
the process.
+    baseConfig = ControllerConfigurationOverrider.override(baseConfig)
+        .watchingOnlyCurrentNamespace().build();
+    LOG.info("Watching only this operator's own namespace");
+
     HiveWorkflowSpec workflowSpec = new HiveWorkflowSpec();
     ((ResolvedControllerConfiguration<HiveCluster>) baseConfig)
         .setWorkflowSpec(workflowSpec);
diff --git 
a/packaging/src/kubernetes/src/java/org/apache/hive/kubernetes/operator/dependent/HiveDependentResource.java
 
b/packaging/src/kubernetes/src/java/org/apache/hive/kubernetes/operator/dependent/HiveDependentResource.java
index 4cb348bfd47..bb031b50ac2 100644
--- 
a/packaging/src/kubernetes/src/java/org/apache/hive/kubernetes/operator/dependent/HiveDependentResource.java
+++ 
b/packaging/src/kubernetes/src/java/org/apache/hive/kubernetes/operator/dependent/HiveDependentResource.java
@@ -32,12 +32,12 @@
 import io.fabric8.kubernetes.api.model.EnvVar;
 import io.fabric8.kubernetes.api.model.EnvVarBuilder;
 import io.fabric8.kubernetes.api.model.HasMetadata;
-import io.fabric8.kubernetes.api.model.Quantity;
-import io.fabric8.kubernetes.api.model.ResourceRequirements;
 import io.fabric8.kubernetes.api.model.Probe;
 import io.fabric8.kubernetes.api.model.ProbeBuilder;
 import io.fabric8.kubernetes.api.model.IntOrString;
-import io.fabric8.kubernetes.api.model.ResourceRequirementsBuilder;
+import io.fabric8.kubernetes.api.model.PodSpec;
+import io.fabric8.kubernetes.api.model.Affinity;
+import io.fabric8.kubernetes.api.model.Toleration;
 import io.fabric8.kubernetes.api.model.Volume;
 import io.fabric8.kubernetes.api.model.VolumeBuilder;
 import io.fabric8.kubernetes.api.model.VolumeMount;
@@ -50,7 +50,6 @@
 import org.apache.hive.kubernetes.operator.model.HiveCluster;
 import org.apache.hive.kubernetes.operator.model.spec.AutoscalingSpec;
 import org.apache.hive.kubernetes.operator.model.spec.DatabaseConfig;
-import org.apache.hive.kubernetes.operator.model.spec.ResourceRequirementsSpec;
 
 import org.apache.hive.kubernetes.operator.model.spec.SecretKeyRef;
 import org.apache.hive.kubernetes.operator.model.spec.ProbeSpec;
@@ -452,27 +451,6 @@ protected static void buildMetastoreVolumes(
         HiveConfigMapDependent.Hadoop.resourceName(hiveCluster)));
   }
 
-  /** Builds Kubernetes ResourceRequirements from the operator's spec. */
-  protected static ResourceRequirements 
buildResources(ResourceRequirementsSpec spec) {
-    if (spec == null) {
-      return new ResourceRequirements();
-    }
-    ResourceRequirementsBuilder builder = new ResourceRequirementsBuilder();
-    if (spec.requestsCpu() != null) {
-      builder.addToRequests("cpu", new Quantity(spec.requestsCpu()));
-    }
-    if (spec.requestsMemory() != null) {
-      builder.addToRequests("memory", new Quantity(spec.requestsMemory()));
-    }
-    if (spec.limitsCpu() != null) {
-      builder.addToLimits("cpu", new Quantity(spec.limitsCpu()));
-    }
-    if (spec.limitsMemory() != null) {
-      builder.addToLimits("memory", new Quantity(spec.limitsMemory()));
-    }
-    return builder.build();
-  }
-
   /**
    * Sets a preferred pod anti-affinity on the pod spec if no affinity is
    * already defined. This spreads replicas across nodes while allowing
@@ -499,6 +477,24 @@ protected static void applySpreadAffinityIfAbsent(
         .build());
   }
 
+  /**
+   * Sets the user-provided affinity override, if any. Must run before
+   * {@link #applySpreadAffinityIfAbsent}, which only sets its default when
+   * the pod spec has no affinity yet.
+   */
+  protected static void applyAffinityOverride(PodSpec podSpec, Affinity 
affinity) {
+    if (affinity != null) {
+      podSpec.setAffinity(affinity);
+    }
+  }
+
+  /** Sets the given tolerations on the pod spec, if any. */
+  protected static void applyTolerations(PodSpec podSpec, List<Toleration> 
tolerations) {
+    if (tolerations != null && !tolerations.isEmpty()) {
+      podSpec.setTolerations(tolerations);
+    }
+  }
+
   /**
    * Builds an init container that downloads external JARs via wget
    * (for http/https URLs) or hadoop fs (for HDFS/cloud paths).
diff --git 
a/packaging/src/kubernetes/src/java/org/apache/hive/kubernetes/operator/dependent/HiveServer2DeploymentDependent.java
 
b/packaging/src/kubernetes/src/java/org/apache/hive/kubernetes/operator/dependent/HiveServer2DeploymentDependent.java
index 28d0250856e..aab6c890897 100644
--- 
a/packaging/src/kubernetes/src/java/org/apache/hive/kubernetes/operator/dependent/HiveServer2DeploymentDependent.java
+++ 
b/packaging/src/kubernetes/src/java/org/apache/hive/kubernetes/operator/dependent/HiveServer2DeploymentDependent.java
@@ -51,7 +51,6 @@ public class HiveServer2DeploymentDependent
     extends HiveDependentResource<Deployment, HiveCluster> {
 
   public static final String COMPONENT = ConfigUtils.COMPONENT_HIVESERVER2;
-  private static final String SCRATCH_MOUNT_PATH = "/opt/hive/scratch";
 
   public HiveServer2DeploymentDependent() {
     super(Deployment.class);
@@ -86,6 +85,7 @@ protected Deployment desired(HiveCluster hiveCluster,
     if (spec.envVars() != null) {
       envVars.addAll(spec.envVars());
     }
+    envVars.addAll(hs2.envVars());
 
     // Env vars consumed by the Hive Docker entrypoint.sh to
     // configure Tez execution mode at container startup.
@@ -185,10 +185,10 @@ protected Deployment desired(HiveCluster hiveCluster,
     if (tezAmEnabled) {
       volumeMounts.add(
           new io.fabric8.kubernetes.api.model.VolumeMountBuilder()
-              .withName("scratch")
-              .withMountPath(SCRATCH_MOUNT_PATH).build());
+              .withName(ScratchPvcDependent.COMPONENT)
+              .withMountPath(ConfigUtils.SCRATCH_MOUNT_PATH).build());
       volumes.add(new io.fabric8.kubernetes.api.model.VolumeBuilder()
-          .withName("scratch")
+          .withName(ScratchPvcDependent.COMPONENT)
           .withNewPersistentVolumeClaim()
             .withClaimName(ScratchPvcDependent.resourceName(hiveCluster))
           .endPersistentVolumeClaim()
@@ -262,7 +262,7 @@ protected Deployment desired(HiveCluster hiveCluster,
                 .withPorts(ports)
                 .withReadinessProbe(readinessProbe)
                 .withLivenessProbe(livenessProbe)
-                .withResources(buildResources(hs2.resources()))
+                .withResources(hs2.resources())
                 .withVolumeMounts(volumeMounts)
               .endContainer()
               .withVolumes(volumes)
@@ -271,8 +271,12 @@ protected Deployment desired(HiveCluster hiveCluster,
         .endSpec()
         .build();
 
+    applyAffinityOverride(
+        deployment.getSpec().getTemplate().getSpec(), hs2.affinity());
     applySpreadAffinityIfAbsent(
         deployment.getSpec().getTemplate().getSpec(), selectorLabels);
+    applyTolerations(
+        deployment.getSpec().getTemplate().getSpec(), hs2.tolerations());
 
     // Graceful scale-down: deregister from ZK, then poll JMX Exporter for 
sessions.
     if (autoscaling.isEnabled()) {
diff --git 
a/packaging/src/kubernetes/src/java/org/apache/hive/kubernetes/operator/dependent/LlapResourceBuilder.java
 
b/packaging/src/kubernetes/src/java/org/apache/hive/kubernetes/operator/dependent/LlapResourceBuilder.java
index a144fc12121..a2c10d3688c 100644
--- 
a/packaging/src/kubernetes/src/java/org/apache/hive/kubernetes/operator/dependent/LlapResourceBuilder.java
+++ 
b/packaging/src/kubernetes/src/java/org/apache/hive/kubernetes/operator/dependent/LlapResourceBuilder.java
@@ -392,14 +392,15 @@ private Deployment doBuildTezAmDeployment(HiveCluster 
hiveCluster, LlapSpec llap
     if (spec.envVars() != null) {
       envVars.addAll(spec.envVars());
     }
+    envVars.addAll(spec.tezAm().envVars());
 
     List<io.fabric8.kubernetes.api.model.VolumeMount> volumeMounts = new 
ArrayList<>();
     volumeMounts.add(new io.fabric8.kubernetes.api.model.VolumeMountBuilder()
         .withName(HIVE_CONFIG_VOLUME)
         .withMountPath(CONF_MOUNT_PATH).build());
     volumeMounts.add(new io.fabric8.kubernetes.api.model.VolumeMountBuilder()
-        .withName("scratch")
-        .withMountPath("/opt/hive/scratch").build());
+        .withName(ScratchPvcDependent.COMPONENT)
+        .withMountPath(ConfigUtils.SCRATCH_MOUNT_PATH).build());
 
     List<Volume> volumes = new ArrayList<>();
     // Projected volume: hive-site.xml from HS2 CM, tez-site.xml from per-LLAP 
CM, core-site.xml from Hadoop CM
@@ -408,7 +409,7 @@ private Deployment doBuildTezAmDeployment(HiveCluster 
hiveCluster, LlapSpec llap
     String tezAmCmName = tezAmConfigMapName(hiveCluster, llap);
     volumes.add(buildProjectedConfigVolume(HIVE_CONFIG_VOLUME, hs2CmName, 
tezAmCmName, hadoopCmName));
     volumes.add(new io.fabric8.kubernetes.api.model.VolumeBuilder()
-        .withName("scratch")
+        .withName(ScratchPvcDependent.COMPONENT)
         .withNewPersistentVolumeClaim()
           .withClaimName(ScratchPvcDependent.resourceName(hiveCluster))
         .endPersistentVolumeClaim()
@@ -461,7 +462,7 @@ private Deployment doBuildTezAmDeployment(HiveCluster 
hiveCluster, LlapSpec llap
                 .withImagePullPolicy(spec.imagePullPolicy())
                 .withEnv(envVars)
                 .withPorts(ports)
-                .withResources(buildResources(spec.tezAm().resources()))
+                .withResources(spec.tezAm().resources())
                 .withVolumeMounts(volumeMounts)
               .endContainer()
               .withVolumes(volumes)
@@ -470,8 +471,17 @@ private Deployment doBuildTezAmDeployment(HiveCluster 
hiveCluster, LlapSpec llap
         .endSpec()
         .build();
 
+    // Per-cluster affinity, falling back to the global one: spec.tezAm's is a 
single block
+    // shared by every cluster's TezAM.
+    applyAffinityOverride(
+        deployment.getSpec().getTemplate().getSpec(),
+        llap.tezAm().affinity() != null ? llap.tezAm().affinity() : 
spec.tezAm().affinity());
     applySpreadAffinityIfAbsent(
         deployment.getSpec().getTemplate().getSpec(), selectorLabels);
+    applyTolerations(
+        deployment.getSpec().getTemplate().getSpec(),
+        llap.tezAm().tolerations() != null && 
!llap.tezAm().tolerations().isEmpty()
+            ? llap.tezAm().tolerations() : spec.tezAm().tolerations());
 
     appendUserVolumes(deployment.getSpec().getTemplate().getSpec(),
         spec.volumes(), spec.volumeMounts(),
@@ -522,6 +532,11 @@ private StatefulSet doBuildStatefulSet(HiveCluster 
hiveCluster, LlapSpec llap, I
     if (spec.envVars() != null) {
       envVars.addAll(spec.envVars());
     }
+    // Component-scoped last, so a per-cluster value wins over the 
cluster-wide one -- the same
+    // order HiveServer2/Metastore/TezAm use. Without this LLAP was the one 
component with no
+    // scoped env vars, so LLAP_DAEMON_OPTS and LLAP_DAEMON_HEAPSIZE had to be 
set cluster-wide
+    // and were then present, unread, on every other pod.
+    envVars.addAll(llap.envVars());
 
     int managementPort = ConfigUtils.getInt(llap.configOverrides(),
         ConfigUtils.HIVE_LLAP_MANAGEMENT_RPC_PORT_KEY, null,
@@ -562,6 +577,19 @@ private StatefulSet doBuildStatefulSet(HiveCluster 
hiveCluster, LlapSpec llap, I
     String hadoopCmName = 
HiveConfigMapDependent.Hadoop.resourceName(hiveCluster);
     volumes.add(buildProjectedConfigVolume(LLAP_CONFIG_VOLUME, cmName, 
hadoopCmName));
 
+    // The scratch PVC only exists when the TezAM does, so mount it on the 
same condition.
+    if (spec.tezAm().isEnabled()) {
+      volumeMounts.add(new io.fabric8.kubernetes.api.model.VolumeMountBuilder()
+          .withName(ScratchPvcDependent.COMPONENT)
+          .withMountPath(ConfigUtils.SCRATCH_MOUNT_PATH).build());
+      volumes.add(new io.fabric8.kubernetes.api.model.VolumeBuilder()
+          .withName(ScratchPvcDependent.COMPONENT)
+          .withNewPersistentVolumeClaim()
+            .withClaimName(ScratchPvcDependent.resourceName(hiveCluster))
+          .endPersistentVolumeClaim()
+          .build());
+    }
+
     List<Container> initContainers = new ArrayList<>();
     addExternalJars(spec.image(), spec.externalJars(),
         initContainers, volumeMounts, volumes, envVars);
@@ -609,7 +637,7 @@ private StatefulSet doBuildStatefulSet(HiveCluster 
hiveCluster, LlapSpec llap, I
                 .withEnv(envVars)
                 .withPorts(ports)
                 .withReadinessProbe(readinessProbe)
-                .withResources(buildResources(llap.resources()))
+                .withResources(llap.resources())
                 .withVolumeMounts(volumeMounts)
               .endContainer()
               .withVolumes(volumes)
@@ -618,8 +646,12 @@ private StatefulSet doBuildStatefulSet(HiveCluster 
hiveCluster, LlapSpec llap, I
         .endSpec()
         .build();
 
+    applyAffinityOverride(
+        statefulSet.getSpec().getTemplate().getSpec(), llap.affinity());
     applySpreadAffinityIfAbsent(
         statefulSet.getSpec().getTemplate().getSpec(), selectorLabels);
+    applyTolerations(
+        statefulSet.getSpec().getTemplate().getSpec(), llap.tolerations());
 
     if (autoscaling.isEnabled()) {
       String preStopScript = buildDualMetricDrainScript(
diff --git 
a/packaging/src/kubernetes/src/java/org/apache/hive/kubernetes/operator/dependent/MetastoreDeploymentDependent.java
 
b/packaging/src/kubernetes/src/java/org/apache/hive/kubernetes/operator/dependent/MetastoreDeploymentDependent.java
index 7ee46dc9187..73afedd9dba 100644
--- 
a/packaging/src/kubernetes/src/java/org/apache/hive/kubernetes/operator/dependent/MetastoreDeploymentDependent.java
+++ 
b/packaging/src/kubernetes/src/java/org/apache/hive/kubernetes/operator/dependent/MetastoreDeploymentDependent.java
@@ -84,6 +84,7 @@ protected Deployment desired(HiveCluster hiveCluster,
     if (spec.envVars() != null) {
       envVars.addAll(spec.envVars());
     }
+    envVars.addAll(spec.metastore().envVars());
 
     int thriftPort = ConfigUtils.getInt(
         spec.metastore().configOverrides(),
@@ -172,8 +173,7 @@ protected Deployment desired(HiveCluster hiveCluster,
                 .withPorts(ports)
                 .withReadinessProbe(readinessProbe)
                 .withLivenessProbe(livenessProbe)
-                .withResources(buildResources(
-                    spec.metastore().resources()))
+                .withResources(spec.metastore().resources())
                 .withVolumeMounts(volumeMounts)
               .endContainer()
               .withVolumes(volumes)
@@ -182,8 +182,12 @@ protected Deployment desired(HiveCluster hiveCluster,
         .endSpec()
         .build();
 
+    applyAffinityOverride(
+        deployment.getSpec().getTemplate().getSpec(), 
spec.metastore().affinity());
     applySpreadAffinityIfAbsent(
         deployment.getSpec().getTemplate().getSpec(), selectorLabels);
+    applyTolerations(
+        deployment.getSpec().getTemplate().getSpec(), 
spec.metastore().tolerations());
 
     // HMS uses HTTP transport mode — connections are stateless, so no session
     // drain is needed. The preStop hook simply sends SIGTERM directly to the
diff --git 
a/packaging/src/kubernetes/src/java/org/apache/hive/kubernetes/operator/dependent/ScratchPvcDependent.java
 
b/packaging/src/kubernetes/src/java/org/apache/hive/kubernetes/operator/dependent/ScratchPvcDependent.java
index 0f459105ec1..a034ae2e684 100644
--- 
a/packaging/src/kubernetes/src/java/org/apache/hive/kubernetes/operator/dependent/ScratchPvcDependent.java
+++ 
b/packaging/src/kubernetes/src/java/org/apache/hive/kubernetes/operator/dependent/ScratchPvcDependent.java
@@ -29,11 +29,12 @@
 import 
io.javaoperatorsdk.operator.processing.dependent.kubernetes.KubernetesDependent;
 import org.apache.hive.kubernetes.operator.model.HiveCluster;
 import org.apache.hive.kubernetes.operator.model.spec.TezAmSpec;
+import org.apache.hive.kubernetes.operator.util.ConfigUtils;
 import org.apache.hive.kubernetes.operator.util.Labels;
 
 /**
- * Manages the shared scratch PersistentVolumeClaim mounted by both
- * HiveServer2 and TezAM at /opt/hive/scratch.
+ * Manages the shared scratch PersistentVolumeClaim mounted by HiveServer2,
+ * TezAM and LLAP at {@link ConfigUtils#SCRATCH_MOUNT_PATH}.
  * <p>
  * This mirrors the Docker Compose pattern where a named volume
  * {@code scratch:/opt/hive/scratch} is shared between the hs2 and
@@ -50,6 +51,7 @@
 public class ScratchPvcDependent
     extends HiveDependentResource<PersistentVolumeClaim, HiveCluster> {
 
+  /** Component label value, and the name of the pod volume backed by this 
PVC. */
   public static final String COMPONENT = "scratch";
 
   public ScratchPvcDependent() {
diff --git 
a/packaging/src/kubernetes/src/java/org/apache/hive/kubernetes/operator/model/HiveClusterSpec.java
 
b/packaging/src/kubernetes/src/java/org/apache/hive/kubernetes/operator/model/HiveClusterSpec.java
index 3ff8bd4b4b1..04e83401741 100644
--- 
a/packaging/src/kubernetes/src/java/org/apache/hive/kubernetes/operator/model/HiveClusterSpec.java
+++ 
b/packaging/src/kubernetes/src/java/org/apache/hive/kubernetes/operator/model/HiveClusterSpec.java
@@ -97,12 +97,12 @@ public record HiveClusterSpec(
     Objects.requireNonNull(zookeeper,
         "zookeeper must be provided in the HiveCluster spec");
     metastore = metastore != null ? metastore : new MetastoreSpec(
-        1, null, null, null, null, null, null, true, null, null, null, null);
+        1, null, null, null, null, null, null, null, null, null, true, null, 
null, null, null);
     hiveServer2 = hiveServer2 != null ? hiveServer2 : new HiveServer2Spec(
-        1, null, null, null, null, null, null, null, null, null);
+        1, null, null, null, null, null, null, null, null, null, null, null, 
null);
     llapClusters = llapClusters != null ? llapClusters : List.of();
     tezAm = tezAm != null ? tezAm : new TezAmSpec(
-        1, null, null, null, null, true, null, null, null);
+        1, null, null, null, null, null, null, null, true, null, null, null);
     envVars = envVars != null ? envVars : List.of();
     externalJars = externalJars != null ? externalJars : List.of();
     volumes = volumes != null ? volumes : List.of();
diff --git 
a/packaging/src/kubernetes/src/java/org/apache/hive/kubernetes/operator/model/spec/HiveServer2Spec.java
 
b/packaging/src/kubernetes/src/java/org/apache/hive/kubernetes/operator/model/spec/HiveServer2Spec.java
index b4962d7e6f3..27f54eb17a2 100644
--- 
a/packaging/src/kubernetes/src/java/org/apache/hive/kubernetes/operator/model/spec/HiveServer2Spec.java
+++ 
b/packaging/src/kubernetes/src/java/org/apache/hive/kubernetes/operator/model/spec/HiveServer2Spec.java
@@ -26,6 +26,10 @@
 import io.fabric8.crd.generator.annotation.PreserveUnknownFields;
 import io.fabric8.crd.generator.annotation.SchemaFrom;
 import io.fabric8.generator.annotation.Default;
+import io.fabric8.kubernetes.api.model.Affinity;
+import io.fabric8.kubernetes.api.model.EnvVar;
+import io.fabric8.kubernetes.api.model.ResourceRequirements;
+import io.fabric8.kubernetes.api.model.Toleration;
 import io.fabric8.kubernetes.api.model.Volume;
 import io.fabric8.kubernetes.api.model.VolumeMount;
 
@@ -35,7 +39,9 @@ public record HiveServer2Spec(
     @Default("1")
     Integer replicas,
     @JsonPropertyDescription("Resource requirements for pods")
-    ResourceRequirementsSpec resources,
+    @Default("{\"requests\": {\"cpu\": \"500m\", \"memory\": \"1Gi\"}}")
+    @SchemaFrom(type = Object.class) @PreserveUnknownFields
+    ResourceRequirements resources,
     @JsonPropertyDescription("Additional configuration overrides as key-value 
pairs")
     Map<String, String> configOverrides,
     @JsonPropertyDescription("Additional volumes to attach to the pod (e.g., 
for keytabs or truststores)")
@@ -44,6 +50,15 @@ public record HiveServer2Spec(
     @JsonPropertyDescription("Additional volume mounts for the container")
     @SchemaFrom(type = Object[].class) @PreserveUnknownFields
     List<VolumeMount> extraVolumeMounts,
+    @JsonPropertyDescription("Tolerations for scheduling onto tainted nodes")
+    @SchemaFrom(type = Object[].class) @PreserveUnknownFields
+    List<Toleration> tolerations,
+    @JsonPropertyDescription("Affinity override; replaces the default spread 
anti-affinity when set")
+    @SchemaFrom(type = Object.class) @PreserveUnknownFields
+    Affinity affinity,
+    @JsonPropertyDescription("Component-scoped env vars, appended after the 
cluster-wide envVars")
+    @SchemaFrom(type = Object[].class) @PreserveUnknownFields
+    List<EnvVar> envVars,
     @JsonPropertyDescription("Kubernetes Service type: ClusterIP, 
LoadBalancer, or NodePort")
     @Default("ClusterIP")
     String serviceType,
@@ -61,6 +76,8 @@ public record HiveServer2Spec(
     serviceType = serviceType != null ? serviceType : "ClusterIP";
     extraVolumes = extraVolumes != null ? extraVolumes : List.of();
     extraVolumeMounts = extraVolumeMounts != null ? extraVolumeMounts : 
List.of();
+    tolerations = tolerations != null ? tolerations : List.of();
+    envVars = envVars != null ? envVars : List.of();
     externalJars = externalJars != null ? externalJars : List.of();
     autoscaling = autoscaling != null ? autoscaling : new AutoscalingSpec(
         false, 1, 80, 0, 60, 600, 300, 10, 90, 30, null);
diff --git 
a/packaging/src/kubernetes/src/java/org/apache/hive/kubernetes/operator/model/spec/LlapSpec.java
 
b/packaging/src/kubernetes/src/java/org/apache/hive/kubernetes/operator/model/spec/LlapSpec.java
index eb42d8c8c0e..288e218afec 100644
--- 
a/packaging/src/kubernetes/src/java/org/apache/hive/kubernetes/operator/model/spec/LlapSpec.java
+++ 
b/packaging/src/kubernetes/src/java/org/apache/hive/kubernetes/operator/model/spec/LlapSpec.java
@@ -28,6 +28,10 @@
 import io.fabric8.crd.generator.annotation.SchemaFrom;
 import io.fabric8.generator.annotation.Default;
 import io.fabric8.generator.annotation.Required;
+import io.fabric8.kubernetes.api.model.Affinity;
+import io.fabric8.kubernetes.api.model.EnvVar;
+import io.fabric8.kubernetes.api.model.ResourceRequirements;
+import io.fabric8.kubernetes.api.model.Toleration;
 import io.fabric8.kubernetes.api.model.Volume;
 import io.fabric8.kubernetes.api.model.VolumeMount;
 
@@ -41,7 +45,9 @@ public record LlapSpec(
     @Default("1")
     Integer replicas,
     @JsonPropertyDescription("Resource requirements for pods")
-    ResourceRequirementsSpec resources,
+    @Default("{\"requests\": {\"cpu\": \"500m\", \"memory\": \"1Gi\"}}")
+    @SchemaFrom(type = Object.class) @PreserveUnknownFields
+    ResourceRequirements resources,
     @JsonPropertyDescription("Additional configuration overrides as key-value 
pairs")
     Map<String, String> configOverrides,
     @JsonPropertyDescription("Additional volumes to attach to the pod (e.g., 
for keytabs or truststores)")
@@ -50,6 +56,15 @@ public record LlapSpec(
     @JsonPropertyDescription("Additional volume mounts for the container")
     @SchemaFrom(type = Object[].class) @PreserveUnknownFields
     List<VolumeMount> extraVolumeMounts,
+    @JsonPropertyDescription("Tolerations for scheduling onto tainted nodes")
+    @SchemaFrom(type = Object[].class) @PreserveUnknownFields
+    List<Toleration> tolerations,
+    @JsonPropertyDescription("Affinity override; replaces the default spread 
anti-affinity when set")
+    @SchemaFrom(type = Object.class) @PreserveUnknownFields
+    Affinity affinity,
+    @JsonPropertyDescription("Component-scoped env vars, appended after the 
cluster-wide envVars")
+    @SchemaFrom(type = Object[].class) @PreserveUnknownFields
+    List<EnvVar> envVars,
     @JsonPropertyDescription("Whether LLAP is enabled")
     @Default("true")
     Boolean enabled,
@@ -76,7 +91,16 @@ public record LlapTezAmSpec(
       @Default("1")
       Integer replicas,
       @JsonPropertyDescription("Autoscaling configuration for this LLAP 
cluster's TezAM")
-      AutoscalingSpec autoscaling) {
+      AutoscalingSpec autoscaling,
+      @JsonPropertyDescription("Affinity for this LLAP cluster's TezAM, 
overriding "
+          + "spec.tezAm.affinity. Set it with more than one LLAP cluster.")
+      @SchemaFrom(type = Object.class)
+      @PreserveUnknownFields
+      Affinity affinity,
+      @JsonPropertyDescription("Tolerations for this LLAP cluster's TezAM, 
overriding spec.tezAm.tolerations")
+      @SchemaFrom(type = Object[].class)
+      @PreserveUnknownFields
+      List<Toleration> tolerations) {
 
     public LlapTezAmSpec {
       replicas = replicas != null ? replicas : 1;
@@ -101,9 +125,11 @@ public record LlapTezAmSpec(
     serviceHosts = serviceHosts != null ? serviceHosts : "@" + name;
     extraVolumes = extraVolumes != null ? extraVolumes : List.of();
     extraVolumeMounts = extraVolumeMounts != null ? extraVolumeMounts : 
List.of();
+    tolerations = tolerations != null ? tolerations : List.of();
+    envVars = envVars != null ? envVars : List.of();
     autoscaling = autoscaling != null ? autoscaling : new AutoscalingSpec(
         false, 0, 1, 20, 60, 900, 600, 10, 0, 0, null);
-    tezAm = tezAm != null ? tezAm : new LlapTezAmSpec(null, null);
+    tezAm = tezAm != null ? tezAm : new LlapTezAmSpec(null, null, null, null);
   }
 
   public boolean isEnabled() {
diff --git 
a/packaging/src/kubernetes/src/java/org/apache/hive/kubernetes/operator/model/spec/MetastoreSpec.java
 
b/packaging/src/kubernetes/src/java/org/apache/hive/kubernetes/operator/model/spec/MetastoreSpec.java
index 6548d999918..ba48f3ddf3b 100644
--- 
a/packaging/src/kubernetes/src/java/org/apache/hive/kubernetes/operator/model/spec/MetastoreSpec.java
+++ 
b/packaging/src/kubernetes/src/java/org/apache/hive/kubernetes/operator/model/spec/MetastoreSpec.java
@@ -26,6 +26,10 @@
 import io.fabric8.crd.generator.annotation.PreserveUnknownFields;
 import io.fabric8.crd.generator.annotation.SchemaFrom;
 import io.fabric8.generator.annotation.Default;
+import io.fabric8.kubernetes.api.model.Affinity;
+import io.fabric8.kubernetes.api.model.EnvVar;
+import io.fabric8.kubernetes.api.model.ResourceRequirements;
+import io.fabric8.kubernetes.api.model.Toleration;
 import io.fabric8.kubernetes.api.model.Volume;
 import io.fabric8.kubernetes.api.model.VolumeMount;
 
@@ -35,7 +39,9 @@ public record MetastoreSpec(
     @Default("1")
     Integer replicas,
     @JsonPropertyDescription("Resource requirements for pods")
-    ResourceRequirementsSpec resources,
+    @Default("{\"requests\": {\"cpu\": \"500m\", \"memory\": \"1Gi\"}}")
+    @SchemaFrom(type = Object.class) @PreserveUnknownFields
+    ResourceRequirements resources,
     @JsonPropertyDescription("Additional configuration overrides as key-value 
pairs")
     Map<String, String> configOverrides,
     @JsonPropertyDescription("Additional volumes to attach to the pod (e.g., 
for keytabs or truststores)")
@@ -44,6 +50,15 @@ public record MetastoreSpec(
     @JsonPropertyDescription("Additional volume mounts for the container")
     @SchemaFrom(type = Object[].class) @PreserveUnknownFields
     List<VolumeMount> extraVolumeMounts,
+    @JsonPropertyDescription("Tolerations for scheduling onto tainted nodes")
+    @SchemaFrom(type = Object[].class) @PreserveUnknownFields
+    List<Toleration> tolerations,
+    @JsonPropertyDescription("Affinity override; replaces the default spread 
anti-affinity when set")
+    @SchemaFrom(type = Object.class) @PreserveUnknownFields
+    Affinity affinity,
+    @JsonPropertyDescription("Component-scoped env vars, appended after the 
cluster-wide envVars")
+    @SchemaFrom(type = Object[].class) @PreserveUnknownFields
+    List<EnvVar> envVars,
     @JsonPropertyDescription("Database connection configuration for the 
metastore backend")
     DatabaseConfig database,
     @JsonPropertyDescription("Warehouse directory path")
@@ -69,6 +84,8 @@ public record MetastoreSpec(
     enabled = enabled != null ? enabled : true;
     extraVolumes = extraVolumes != null ? extraVolumes : List.of();
     extraVolumeMounts = extraVolumeMounts != null ? extraVolumeMounts : 
List.of();
+    tolerations = tolerations != null ? tolerations : List.of();
+    envVars = envVars != null ? envVars : List.of();
     autoscaling = autoscaling != null ? autoscaling : new AutoscalingSpec(
         false, 1, 75, 0, 60, 300, 60, 10, 90, 30, null);
   }
diff --git 
a/packaging/src/kubernetes/src/java/org/apache/hive/kubernetes/operator/model/spec/ResourceRequirementsSpec.java
 
b/packaging/src/kubernetes/src/java/org/apache/hive/kubernetes/operator/model/spec/ResourceRequirementsSpec.java
deleted file mode 100644
index 26c1d81776a..00000000000
--- 
a/packaging/src/kubernetes/src/java/org/apache/hive/kubernetes/operator/model/spec/ResourceRequirementsSpec.java
+++ /dev/null
@@ -1,42 +0,0 @@
-/*
- * Licensed to the Apache Software Foundation (ASF) under one
- * or more contributor license agreements.  See the NOTICE file
- * distributed with this work for additional information
- * regarding copyright ownership.  The ASF licenses this file
- * to you under the Apache License, Version 2.0 (the
- * "License"); you may not use this file except in compliance
- * with the License.  You may obtain a copy of the License at
- *
- *     http://www.apache.org/licenses/LICENSE-2.0
- *
- * Unless required by applicable law or agreed to in writing,
- * software distributed under the License is distributed on an
- * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
- * KIND, either express or implied.  See the License for the
- * specific language governing permissions and limitations
- * under the License.
- */
-
-package org.apache.hive.kubernetes.operator.model.spec;
-
-import com.fasterxml.jackson.annotation.JsonPropertyDescription;
-import io.fabric8.generator.annotation.Default;
-
-/** Kubernetes resource requirements specification for CPU and memory. */
-public record ResourceRequirementsSpec(
-    @JsonPropertyDescription("CPU request (e.g. 500m, 1)")
-    @Default("500m")
-    String requestsCpu,
-    @JsonPropertyDescription("Memory request (e.g. 1Gi, 512Mi)")
-    @Default("1Gi")
-    String requestsMemory,
-    @JsonPropertyDescription("CPU limit (e.g. 2, 1000m)")
-    String limitsCpu,
-    @JsonPropertyDescription("Memory limit (e.g. 2Gi, 1024Mi)")
-    String limitsMemory) {
-
-  public ResourceRequirementsSpec {
-    requestsCpu = requestsCpu != null ? requestsCpu : "500m";
-    requestsMemory = requestsMemory != null ? requestsMemory : "1Gi";
-  }
-}
diff --git 
a/packaging/src/kubernetes/src/java/org/apache/hive/kubernetes/operator/model/spec/TezAmSpec.java
 
b/packaging/src/kubernetes/src/java/org/apache/hive/kubernetes/operator/model/spec/TezAmSpec.java
index 8165b9b829a..9caa498e512 100644
--- 
a/packaging/src/kubernetes/src/java/org/apache/hive/kubernetes/operator/model/spec/TezAmSpec.java
+++ 
b/packaging/src/kubernetes/src/java/org/apache/hive/kubernetes/operator/model/spec/TezAmSpec.java
@@ -26,6 +26,10 @@
 import io.fabric8.crd.generator.annotation.PreserveUnknownFields;
 import io.fabric8.crd.generator.annotation.SchemaFrom;
 import io.fabric8.generator.annotation.Default;
+import io.fabric8.kubernetes.api.model.Affinity;
+import io.fabric8.kubernetes.api.model.EnvVar;
+import io.fabric8.kubernetes.api.model.ResourceRequirements;
+import io.fabric8.kubernetes.api.model.Toleration;
 import io.fabric8.kubernetes.api.model.Volume;
 import io.fabric8.kubernetes.api.model.VolumeMount;
 
@@ -35,7 +39,9 @@ public record TezAmSpec(
     @Default("1")
     Integer replicas,
     @JsonPropertyDescription("Resource requirements for pods")
-    ResourceRequirementsSpec resources,
+    @Default("{\"requests\": {\"cpu\": \"500m\", \"memory\": \"1Gi\"}}")
+    @SchemaFrom(type = Object.class) @PreserveUnknownFields
+    ResourceRequirements resources,
     @JsonPropertyDescription("Additional configuration overrides as key-value 
pairs")
     Map<String, String> configOverrides,
     @JsonPropertyDescription("Additional volumes to attach to the pod (e.g., 
for keytabs or truststores)")
@@ -44,11 +50,20 @@ public record TezAmSpec(
     @JsonPropertyDescription("Additional volume mounts for the container")
     @SchemaFrom(type = Object[].class) @PreserveUnknownFields
     List<VolumeMount> extraVolumeMounts,
+    @JsonPropertyDescription("Tolerations for scheduling onto tainted nodes")
+    @SchemaFrom(type = Object[].class) @PreserveUnknownFields
+    List<Toleration> tolerations,
+    @JsonPropertyDescription("Affinity override; replaces the default spread 
anti-affinity when set")
+    @SchemaFrom(type = Object.class) @PreserveUnknownFields
+    Affinity affinity,
+    @JsonPropertyDescription("Component-scoped env vars, appended after the 
cluster-wide envVars")
+    @SchemaFrom(type = Object[].class) @PreserveUnknownFields
+    List<EnvVar> envVars,
     @JsonPropertyDescription("Whether Tez AM is enabled")
     @Default("true")
     Boolean enabled,
     @JsonPropertyDescription("Storage size for the shared scratch PVC "
-        + "(ReadWriteMany) mounted on HS2 and TezAM at /opt/hive/scratch")
+        + "(ReadWriteMany) mounted on HS2, TezAM and LLAP at 
/opt/hive/scratch")
     @Default("1Gi")
     String scratchStorageSize,
     @JsonPropertyDescription("StorageClass for the shared scratch PVC. "
@@ -63,6 +78,8 @@ public record TezAmSpec(
     scratchStorageSize = scratchStorageSize != null ? scratchStorageSize : 
"1Gi";
     extraVolumes = extraVolumes != null ? extraVolumes : List.of();
     extraVolumeMounts = extraVolumeMounts != null ? extraVolumeMounts : 
List.of();
+    tolerations = tolerations != null ? tolerations : List.of();
+    envVars = envVars != null ? envVars : List.of();
     autoscaling = autoscaling != null ? autoscaling : new AutoscalingSpec(
         false, 0, 0, 0, 60, 600, 120, 10, 0, 0, null);
   }
diff --git 
a/packaging/src/kubernetes/src/java/org/apache/hive/kubernetes/operator/reconciler/HiveClusterReconciler.java
 
b/packaging/src/kubernetes/src/java/org/apache/hive/kubernetes/operator/reconciler/HiveClusterReconciler.java
index a7da524a3db..ec37d6820ad 100644
--- 
a/packaging/src/kubernetes/src/java/org/apache/hive/kubernetes/operator/reconciler/HiveClusterReconciler.java
+++ 
b/packaging/src/kubernetes/src/java/org/apache/hive/kubernetes/operator/reconciler/HiveClusterReconciler.java
@@ -160,9 +160,10 @@ public UpdateControl<HiveCluster> reconcile(HiveCluster 
resource, Context<HiveCl
     }
 
     // --- Imperative LLAP cluster management ---
-    if (action != SuspendAction.STAY_SUSPENDED && action != 
SuspendAction.SUSPEND_NOW) {
-      reconcileLlapClusters(resource, client);
-    }
+    // Must also run while suspended: resolve*ReplicaCount() return 0 when
+    // spec.suspend() is set, and skipping the call would leave LLAP/TezAM
+    // at their pre-suspend scale.
+    reconcileLlapClusters(resource, client);
 
     // --- Autoscaling evaluation (only when enabled and not suspended) ---
     if (rescheduleSeconds == 0 && anyAutoscalingEnabled(resource.getSpec())) {
@@ -970,17 +971,24 @@ private void wakeCluster(HiveCluster resource) {
     // the dependent resources (Deployments/StatefulSets) on the next reconcile
     // and use these values for spec.replicas. We don't call patchReplicas()
     // because the workloads may have been garbage-collected while suspended.
-    int hs2Min = Math.max(1, spec.hiveServer2().autoscaling().minReplicas());
-    HiveClusterAutoscaler.setManagedReplicas(ns, name, 
ConfigUtils.COMPONENT_HIVESERVER2, hs2Min);
+    // With autoscaling disabled the wake value is the spec's static replica
+    // count — using minReplicas (0 by default) would pin the component to 0.
+    int hs2Wake = spec.hiveServer2().autoscaling().isEnabled()
+        ? Math.max(1, spec.hiveServer2().autoscaling().minReplicas())
+        : spec.hiveServer2().replicas();
+    HiveClusterAutoscaler.setManagedReplicas(ns, name, 
ConfigUtils.COMPONENT_HIVESERVER2, hs2Wake);
 
     if (spec.metastore().isEnabled() && spec.autoSuspend().includeMetastore()) 
{
-      int hmsMin = Math.max(1, spec.metastore().autoscaling().minReplicas());
-      HiveClusterAutoscaler.setManagedReplicas(ns, name, 
ConfigUtils.COMPONENT_METASTORE, hmsMin);
+      int hmsWake = spec.metastore().autoscaling().isEnabled()
+          ? Math.max(1, spec.metastore().autoscaling().minReplicas())
+          : spec.metastore().replicas();
+      HiveClusterAutoscaler.setManagedReplicas(ns, name, 
ConfigUtils.COMPONENT_METASTORE, hmsWake);
     }
 
     for (var llap : spec.llapClusters()) {
       if (llap.isEnabled()) {
-        int llapWake = llap.autoscaling().minReplicas();
+        int llapWake = llap.autoscaling().isEnabled()
+            ? llap.autoscaling().minReplicas() : llap.replicas();
         HiveClusterAutoscaler.setManagedReplicas(ns, name, 
ConfigUtils.llapComponentKey(llap.name()), llapWake);
       }
     }
@@ -988,14 +996,15 @@ private void wakeCluster(HiveCluster resource) {
     if (spec.tezAm().isEnabled()) {
       for (var llap : spec.llapClusters()) {
         if (llap.isEnabled()) {
-          int tezWake = llap.tezAm().autoscaling().minReplicas();
+          int tezWake = llap.tezAm().autoscaling().isEnabled()
+              ? llap.tezAm().autoscaling().minReplicas() : 
llap.tezAm().replicas();
           HiveClusterAutoscaler.setManagedReplicas(ns, name,
               ConfigUtils.tezAmComponentKey(llap.name()), tezWake);
         }
       }
     }
 
-    LOG.info("Cluster {}/{} woken up — restored to minReplicas", ns, name);
+    LOG.info("Cluster {}/{} woken up", ns, name);
   }
 
   private static boolean allAutoscalingEnabled(HiveClusterSpec spec) {
diff --git 
a/packaging/src/kubernetes/src/java/org/apache/hive/kubernetes/operator/reconciler/HiveWorkflowSpec.java
 
b/packaging/src/kubernetes/src/java/org/apache/hive/kubernetes/operator/reconciler/HiveWorkflowSpec.java
index 8a46332499b..ae84e066376 100644
--- 
a/packaging/src/kubernetes/src/java/org/apache/hive/kubernetes/operator/reconciler/HiveWorkflowSpec.java
+++ 
b/packaging/src/kubernetes/src/java/org/apache/hive/kubernetes/operator/reconciler/HiveWorkflowSpec.java
@@ -186,27 +186,22 @@ private static Condition<?, HiveCluster> metastoreReady() 
{
   }
 
   /**
-   * Reconcile precondition for HiveServer2: if Metastore is managed,
-   * wait for it to be ready before reconciling HS2.
+   * Reconcile precondition for HiveServer2: at least one ready Metastore 
replica, not every
+   * replica. An unmet reconcile precondition deletes the dependent, so 
requiring the full
+   * count took HiveServer2 down whenever one Metastore pod restarted.
    */
   private static Condition<?, HiveCluster> hs2Precondition() {
     return (dependentResource, primary, context) -> {
       if (!primary.getSpec().metastore().isEnabled()) {
         return true;
       }
-      int desiredReplicas;
-      if (primary.getSpec().metastore().autoscaling().isEnabled()) {
-        desiredReplicas = Math.max(1, 
primary.getSpec().metastore().autoscaling().minReplicas());
-      } else {
-        desiredReplicas = primary.getSpec().metastore().replicas();
-      }
       return context.getSecondaryResources(Deployment.class).stream()
           .filter(d -> d.getMetadata().getName().equals(
               primary.getMetadata().getName() + "-metastore"))
           .findFirst()
           .map(deployment -> deployment.getStatus() != null
               && deployment.getStatus().getReadyReplicas() != null
-              && deployment.getStatus().getReadyReplicas() >= desiredReplicas)
+              && deployment.getStatus().getReadyReplicas() >= 1)
           .orElse(false);
     };
   }
diff --git 
a/packaging/src/kubernetes/src/java/org/apache/hive/kubernetes/operator/util/ConfigUtils.java
 
b/packaging/src/kubernetes/src/java/org/apache/hive/kubernetes/operator/util/ConfigUtils.java
index 76dac7a640b..640b7d3abf7 100644
--- 
a/packaging/src/kubernetes/src/java/org/apache/hive/kubernetes/operator/util/ConfigUtils.java
+++ 
b/packaging/src/kubernetes/src/java/org/apache/hive/kubernetes/operator/util/ConfigUtils.java
@@ -74,7 +74,12 @@ public static String tezAmComponentKey(String llapName) {
 
   public static final String HIVE_USER_INSTALL_DIR_KEY = 
"hive.user.install.directory";
 
-  public static final String HIVE_LOCAL_SCRATCH_DIR_KEY = 
"hive.exec.local.scratchdir";
+  public static final String HIVE_SCRATCH_DIR_KEY = "hive.exec.scratchdir";
+
+  public static final String MAPREDUCE_FRAMEWORK_NAME_KEY = 
"mapreduce.framework.name";
+
+  /** Mount path of the shared scratch PVC on HS2, TezAM and LLAP. */
+  public static final String SCRATCH_MOUNT_PATH = "/opt/hive/scratch";
 
   public static final String HIVE_SERVER2_TEZ_USE_EXTERNAL_SESSIONS_KEY = 
"hive.server2.tez.use.external.sessions";
 
diff --git 
a/packaging/src/kubernetes/src/java/org/apache/hive/kubernetes/operator/util/HiveConfigBuilder.java
 
b/packaging/src/kubernetes/src/java/org/apache/hive/kubernetes/operator/util/HiveConfigBuilder.java
index 9c78fa15342..b4957a24d86 100644
--- 
a/packaging/src/kubernetes/src/java/org/apache/hive/kubernetes/operator/util/HiveConfigBuilder.java
+++ 
b/packaging/src/kubernetes/src/java/org/apache/hive/kubernetes/operator/util/HiveConfigBuilder.java
@@ -78,11 +78,11 @@ public static Map<String, String> getHiveServer2HiveSite(
     props.put(ConfigUtils.HIVE_JAR_DIRECTORY_KEY, "/tmp");
     props.put(ConfigUtils.HIVE_USER_INSTALL_DIR_KEY, "/tmp");
     if (tezAmEnabled) {
-      props.put(ConfigUtils.HIVE_LOCAL_SCRATCH_DIR_KEY,
-          "/opt/hive/scratch");
-    }
-
-    if (tezAmEnabled) {
+      // "yarn-tez" is Tez's own framework name 
(YarnTezClientProtocolProvider). The default,
+      // "local", would send staging to the local scratch dir, which the TezAM 
pod cannot
+      // read. file:// because a bare path resolves against fs.defaultFS.
+      props.put(ConfigUtils.MAPREDUCE_FRAMEWORK_NAME_KEY, "yarn-tez");
+      props.put(ConfigUtils.HIVE_SCRATCH_DIR_KEY, "file://" + 
ConfigUtils.SCRATCH_MOUNT_PATH);
       props.put(ConfigUtils.HIVE_SERVER2_TEZ_USE_EXTERNAL_SESSIONS_KEY, 
"true");
       // Default external sessions namespace points to first LLAP cluster's 
TezAM.
       // Client routes to other clusters by overriding both properties in JDBC 
URL:
@@ -114,7 +114,7 @@ public static Map<String, String> getHiveServer2HiveSite(
       props.put(ConfigUtils.HIVE_SERVER2_TEZ_USE_EXTERNAL_SESSIONS_KEY, 
"false");
       props.put(ConfigUtils.TEZ_LOCAL_MODE_KEY, "true");
       props.put(ConfigUtils.TEZ_AM_FRAMEWORK_MODE_KEY, "LOCAL");
-      props.put("mapreduce.framework.name", "local");
+      props.put(ConfigUtils.MAPREDUCE_FRAMEWORK_NAME_KEY, "local");
     }
 
     // Server-side LLAP cluster routing: emit per-cluster definitions and 
routing rules.

Reply via email to