You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@impala.apache.org by ja...@apache.org on 2026/08/12 22:17:35 UTC
(impala) 01/02: IMPALA-15028: Add Helm chart render assertions
This is an automated email from the ASF dual-hosted git repository.
asf-gitbox-commits pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/impala.git
commit 49c867d40f291bcf88757d9a410d0b7aa29f98e3
Author: Anubhav Jindal <an...@gmail.com>
AuthorDate: Mon Aug 10 15:43:33 2026 -0700
IMPALA-15028: Add Helm chart render assertions
Add a lightweight CI-friendly chart test harness that runs helm lint,
renders default and override manifests, and asserts key Impala Helm
chart behaviors to prevent regressions.
Wire chart checks into bin/run-all-tests.sh as an opt-in stage
(HELM_CHART_TEST=false by default) and keep Jenkins all-tests behavior
unchanged unless explicitly enabled.
Cover both core defaults and optional chart functionality, including
LDAP, Ranger, Kudu, OAuth, and secure-cluster Kerberos/TLS/Istio paths.
Also validate required-value failures for secure secret inputs.
Align assert script execution with repository conventions by using an
executable shebang (#!/usr/bin/env impala-python3), invoking the script
directly, and documenting required local dependencies.
Testing:
- bash -n bin/jenkins/all-tests.sh
- bash -n bin/run-all-tests.sh
- bash -n helm/impala/tests/run-chart-tests.sh
- python3 bin/jenkins/critique-gerrit-review.py --dryrun
Change-Id: I313be431e81a4b98370e51d298b7b2d35e0aded8
Assisted-by: GPT-5.3 (Cursor)
Reviewed-on: http://gerrit.cloudera.org:8080/24368
Reviewed-by: Jason Fehr <jf...@cloudera.com>
Tested-by: Jason Fehr <jf...@cloudera.com>
---
bin/run-all-tests.sh | 8 +
helm/impala/README.md | 22 ++
helm/impala/tests/assert_chart.py | 578 +++++++++++++++++++++++++++++++++++
helm/impala/tests/run-chart-tests.sh | 176 +++++++++++
4 files changed, 784 insertions(+)
diff --git a/bin/run-all-tests.sh b/bin/run-all-tests.sh
index 601485ec8..9a740c3d6 100755
--- a/bin/run-all-tests.sh
+++ b/bin/run-all-tests.sh
@@ -68,6 +68,8 @@ fi
# Run Cluster Tests
: ${CLUSTER_TEST:=true}
: ${CLUSTER_TEST_FILES:=}
+# Run Helm chart render assertions on demand.
+: ${HELM_CHART_TEST:=false}
# Run JS tests
: ${JS_TEST:=false}
# Verifiers to run after all tests. Skipped if true.
@@ -412,6 +414,12 @@ do
export IMPALA_MAX_LOG_FILES="${IMPALA_MAX_LOG_FILES_SAVE}"
fi
+ if [[ "$HELM_CHART_TEST" == true ]]; then
+ if ! "${IMPALA_HOME}/helm/impala/tests/run-chart-tests.sh"; then
+ TEST_RET_CODE=1
+ fi
+ fi
+
if [ ! -z "${TEST_SUITE_VERIFIERS}" ]; then
mkdir -p "${TEST_SUITE_VERIFIERS_LOG_DIR}"
pushd "${IMPALA_HOME}/tests"
diff --git a/helm/impala/README.md b/helm/impala/README.md
index 88f2eb0ce..4c1b885c1 100644
--- a/helm/impala/README.md
+++ b/helm/impala/README.md
@@ -390,6 +390,28 @@ helm upgrade impala ./helm/impala -n impala \
--set catalogd.hmsEventPollingIntervalS=0
```
+## Automated chart checks
+
+From the repository root, run:
+
+```bash
+./helm/impala/tests/run-chart-tests.sh
+```
+
+This script runs `helm lint`, renders default and override manifests with
+`helm template`, and validates key chart behavior with assertions.
+Coverage includes default core settings plus optional LDAP, Ranger, Kudu,
+OAuth, and secure-cluster (Kerberos/TLS/Istio) rendering paths.
+
+Required dependencies to run this harness:
+
+- `helm` 3.x on `PATH`
+- `impala-python3` on `PATH` (or Impala dev environment sourced)
+- shell utilities used by the script (`bash`, `mktemp`)
+
+This is a render-time validation suite; it does not require a running
+Kubernetes cluster or Docker runtime.
+
## Control-plane guidance
Use one control path per release/namespace:
diff --git a/helm/impala/tests/assert_chart.py b/helm/impala/tests/assert_chart.py
new file mode 100755
index 000000000..983a0a565
--- /dev/null
+++ b/helm/impala/tests/assert_chart.py
@@ -0,0 +1,578 @@
+#!/usr/bin/env impala-python3
+# 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.
+
+import argparse
+import sys
+from pathlib import Path
+
+
+def _read_text(path: str) -> str:
+ return Path(path).read_text(encoding="utf-8")
+
+
+def _require(
+ failures: list[str],
+ condition: bool,
+ success_message: str,
+ failure_message: str,
+) -> None:
+ if condition:
+ print(f"[PASS] {success_message}")
+ else:
+ failures.append(failure_message)
+ print(f"[FAIL] {failure_message}")
+
+
+def _verify_default_images(default_render: str, failures: list[str]) -> None:
+ expected_suffixes = [
+ "catalogd",
+ "impala_quickstart_hms",
+ "impalad_coord_exec",
+ "statestored",
+ ]
+ for suffix in expected_suffixes:
+ image = f"image: apache/impala:4.5.0-{suffix}"
+ _require(
+ failures,
+ image in default_render,
+ f"default image renders {image}",
+ f"default image missing {image}",
+ )
+
+
+def _verify_beeswax_absence(default_render: str, failures: list[str]) -> None:
+ _require(
+ failures,
+ "beeswax" not in default_render.lower(),
+ "beeswax name is absent from rendered manifests",
+ "beeswax references found in rendered manifests",
+ )
+ _require(
+ failures,
+ "containerPort: 21000" not in default_render,
+ "deprecated beeswax container port 21000 is absent",
+ "deprecated beeswax container port 21000 was rendered",
+ )
+ _require(
+ failures,
+ "\n - port: 21000\n" not in default_render,
+ "deprecated beeswax service port 21000 is absent",
+ "deprecated beeswax service port 21000 was rendered",
+ )
+
+
+def _verify_debug_levels(
+ default_render: str,
+ debug_render: str,
+ failures: list[str],
+) -> None:
+ _require(
+ failures,
+ default_render.count("- -v=1") >= 3,
+ "default debug levels render as -v=1 for daemons",
+ "default debug levels did not render expected -v=1 args",
+ )
+ _require(
+ failures,
+ "- -v=3" in debug_render,
+ "impalad.v override renders -v=3",
+ "impalad.v override did not render -v=3",
+ )
+ _require(
+ failures,
+ "- -v=4" in debug_render,
+ "catalogd.v override renders -v=4",
+ "catalogd.v override did not render -v=4",
+ )
+ _require(
+ failures,
+ "- -v=5" in debug_render,
+ "statestored.v override renders -v=5",
+ "statestored.v override did not render -v=5",
+ )
+
+
+def _verify_hms_polling(
+ default_render: str,
+ polling_render: str,
+ failures: list[str],
+) -> None:
+ _require(
+ failures,
+ "- -hms_event_polling_interval_s=1" in default_render,
+ "default catalogd.hmsEventPollingIntervalS renders as 1",
+ "default catalogd.hmsEventPollingIntervalS did not render as 1",
+ )
+ _require(
+ failures,
+ "- -hms_event_polling_interval_s=0" in polling_render,
+ "catalogd.hmsEventPollingIntervalS override renders as 0",
+ "catalogd.hmsEventPollingIntervalS override did not render as 0",
+ )
+
+
+def _verify_shared_warehouse_access_mode(
+ default_render: str,
+ failures: list[str],
+) -> None:
+ _require(
+ failures,
+ "- ReadWriteMany" in default_render,
+ "default render uses ReadWriteMany for shared warehouse PVC",
+ "default render did not use ReadWriteMany for shared warehouse PVC",
+ )
+
+
+def _verify_hms_security_context(hms_security_render: str, failures: list[str]) -> None:
+ _require(
+ failures,
+ "runAsUser: 0" in hms_security_render,
+ "hms.securityContext.runAsUser renders when set",
+ "hms.securityContext.runAsUser did not render",
+ )
+ _require(
+ failures,
+ "runAsGroup: 0" in hms_security_render,
+ "hms.securityContext.runAsGroup renders when set",
+ "hms.securityContext.runAsGroup did not render",
+ )
+
+
+def _verify_ldap_render(ldap_render: str, failures: list[str]) -> None:
+ _require(
+ failures,
+ "- -enable_ldap_auth" in ldap_render,
+ "LDAP enable flag renders",
+ "LDAP enable flag did not render",
+ )
+ _require(
+ failures,
+ "- -ldap_uri=ldap://ldap.example.org:389" in ldap_render,
+ "LDAP URI flag renders",
+ "LDAP URI flag did not render",
+ )
+ _require(
+ failures,
+ "- -ldap_bind_pattern=cn=#UID,dc=example,dc=org" in ldap_render,
+ "LDAP bind pattern renders",
+ "LDAP bind pattern did not render",
+ )
+ _require(
+ failures,
+ "- -ldap_passwords_in_clear_ok" in ldap_render,
+ "LDAP cleartext-password opt-in flag renders",
+ "LDAP cleartext-password opt-in flag did not render",
+ )
+
+
+def _verify_ranger_render(ranger_render: str, failures: list[str]) -> None:
+ _require(
+ failures,
+ "# Source: impala/templates/ranger-deployment.yaml" in ranger_render,
+ "Ranger deployment template renders when enabled",
+ "Ranger deployment template did not render",
+ )
+ _require(
+ failures,
+ "# Source: impala/templates/ranger-service.yaml" in ranger_render,
+ "Ranger service template renders when enabled",
+ "Ranger service template did not render",
+ )
+ _require(
+ failures,
+ "- -authorization_provider=ranger" in ranger_render,
+ "Impala daemons render Ranger authorization provider flag",
+ "Ranger authorization provider flag did not render",
+ )
+ _require(
+ failures,
+ "- -server_name=server1" in ranger_render,
+ "Ranger server_name flag renders with expected key format",
+ "Ranger server_name flag did not render with expected key format",
+ )
+ _require(
+ failures,
+ "ranger-hive-security.xml" in ranger_render,
+ "Ranger security configuration file is rendered and mounted",
+ "Ranger security configuration file did not render",
+ )
+ _require(
+ failures,
+ "ranger-hive-audit.xml" in ranger_render,
+ "Ranger audit configuration file is rendered and mounted",
+ "Ranger audit configuration file did not render",
+ )
+
+
+def _verify_kudu_render(kudu_render: str, failures: list[str]) -> None:
+ _require(
+ failures,
+ "# Source: impala/templates/kudu-master-deployment.yaml" in kudu_render,
+ "Kudu master StatefulSet template renders when enabled",
+ "Kudu master StatefulSet template did not render",
+ )
+ _require(
+ failures,
+ "# Source: impala/templates/kudu-tserver-deployment.yaml" in kudu_render,
+ "Kudu tserver StatefulSet template renders when enabled",
+ "Kudu tserver StatefulSet template did not render",
+ )
+ _require(
+ failures,
+ "# Source: impala/templates/kudu-master-service.yaml" in kudu_render,
+ "Kudu master service template renders when enabled",
+ "Kudu master service template did not render",
+ )
+ _require(
+ failures,
+ "# Source: impala/templates/kudu-tserver-service.yaml" in kudu_render,
+ "Kudu tserver service template renders when enabled",
+ "Kudu tserver service template did not render",
+ )
+ _require(
+ failures,
+ "- -kudu_master_hosts=impala-kudu-impala-kudu-master:7051" in kudu_render,
+ "Impala daemons render Kudu master hosts when Kudu is enabled",
+ "Kudu master hosts flag did not render in Impala daemons",
+ )
+ _require(
+ failures,
+ "name: kudu-master-data\n emptyDir: {}" in kudu_render,
+ "Kudu master data volume uses emptyDir when persistence is disabled",
+ "Kudu master data volume did not render emptyDir for disabled persistence",
+ )
+ _require(
+ failures,
+ "name: kudu-tserver-data\n emptyDir: {}" in kudu_render,
+ "Kudu tserver data volume uses emptyDir when persistence is disabled",
+ "Kudu tserver data volume did not render emptyDir for disabled persistence",
+ )
+ _require(
+ failures,
+ "volumeClaimTemplates:" not in kudu_render,
+ "Kudu StatefulSets skip volumeClaimTemplates when persistence is disabled",
+ "Kudu StatefulSets still render volumeClaimTemplates with disabled persistence",
+ )
+ _require(
+ failures,
+ "claimName:" not in kudu_render,
+ "No PVC claimName mounts are rendered for disabled Kudu persistence",
+ "PVC claimName mounts were rendered despite disabled Kudu persistence",
+ )
+ _require(
+ failures,
+ "# Source: impala/templates/kudu-pvc.yaml" not in kudu_render,
+ "Kudu PVC template is skipped when Kudu persistence is disabled",
+ "Kudu PVC template rendered despite disabled Kudu persistence",
+ )
+
+
+def _verify_oauth_render(oauth_render: str, failures: list[str]) -> None:
+ _require(
+ failures,
+ "- -oauth_token_auth=true" in oauth_render,
+ "OAuth token auth flag renders when enabled",
+ "OAuth token auth flag did not render",
+ )
+ _require(
+ failures,
+ "- -oauth_jwt_custom_claim_username=sub" in oauth_render,
+ "OAuth custom username claim flag renders",
+ "OAuth custom username claim flag did not render",
+ )
+ _require(
+ failures,
+ "- -oauth_jwt_validate_signature=true" in oauth_render,
+ "OAuth signature validation flag renders",
+ "OAuth signature validation flag did not render",
+ )
+ _require(
+ failures,
+ "- -oauth_jwks_url=https://idp.example.org/jwks" in oauth_render,
+ "OAuth JWKS URL flag renders",
+ "OAuth JWKS URL flag did not render",
+ )
+ _require(
+ failures,
+ "- -oauth_allow_without_tls=true" in oauth_render,
+ "OAuth no-TLS development override flag renders when set",
+ "OAuth no-TLS development override flag did not render",
+ )
+
+
+def _verify_secure_render(secure_render: str, failures: list[str]) -> None:
+ _require(
+ failures,
+ secure_render.count('sidecar.istio.io/inject: "true"') >= 4,
+ "Istio sidecar annotation renders across core workloads",
+ "Istio sidecar annotation did not render across core workloads",
+ )
+ _require(
+ failures,
+ "- -principal=impala/_HOST@EXAMPLE.COM" in secure_render,
+ "Kerberos principal flag renders",
+ "Kerberos principal flag did not render",
+ )
+ _require(
+ failures,
+ "- -be_principal=impala/_HOST@EXAMPLE.COM" in secure_render,
+ "Kerberos backend principal flag renders",
+ "Kerberos backend principal flag did not render",
+ )
+ _require(
+ failures,
+ "- -keytab_file=/etc/impala/security/impala.keytab" in secure_render,
+ "Kerberos keytab path flag renders",
+ "Kerberos keytab path flag did not render",
+ )
+ _require(
+ failures,
+ "- -krb5_conf=/etc/krb5/krb5.conf" in secure_render,
+ "Kerberos krb5.conf path flag renders when config map is set",
+ "Kerberos krb5.conf path flag did not render",
+ )
+ _require(
+ failures,
+ "- -ssl_server_certificate=/etc/impala/tls/tls.crt" in secure_render,
+ "TLS certificate flag renders",
+ "TLS certificate flag did not render",
+ )
+ _require(
+ failures,
+ "- -ssl_private_key=/etc/impala/tls/tls.key" in secure_render,
+ "TLS private key flag renders",
+ "TLS private key flag did not render",
+ )
+ _require(
+ failures,
+ "- -ssl_client_ca_certificate=/etc/impala/tls/ca.crt" in secure_render,
+ "TLS client CA flag renders",
+ "TLS client CA flag did not render",
+ )
+ _require(
+ failures,
+ "secretName: impala-kerberos-keytab" in secure_render,
+ "Kerberos keytab secret mount renders",
+ "Kerberos keytab secret mount did not render",
+ )
+ _require(
+ failures,
+ "secretName: impala-tls" in secure_render,
+ "TLS secret mount renders",
+ "TLS secret mount did not render",
+ )
+ _require(
+ failures,
+ "name: impala-krb5-conf" in secure_render,
+ "krb5 config map mount renders when set",
+ "krb5 config map mount did not render",
+ )
+
+
+def _verify_secure_validation_errors(
+ missing_kerberos_principal_render: str,
+ missing_kerberos_render: str,
+ missing_tls_render: str,
+ failures: list[str],
+) -> None:
+ _require(
+ failures,
+ "security.kerberos.principal is required" in missing_kerberos_principal_render,
+ "Kerberos missing-principal validation error is raised",
+ "Kerberos missing-principal validation error was not raised",
+ )
+ _require(
+ failures,
+ "security.kerberos.keytabSecretName is required" in missing_kerberos_render,
+ "Kerberos missing-secret validation error is raised",
+ "Kerberos missing-secret validation error was not raised",
+ )
+ _require(
+ failures,
+ "security.tls.secretName is required" in missing_tls_render,
+ "TLS missing-secret validation error is raised",
+ "TLS missing-secret validation error was not raised",
+ )
+
+
+def _verify_oauth_validation_errors(
+ missing_oauth_jwks_render: str,
+ ambiguous_oauth_jwks_render: str,
+ failures: list[str],
+) -> None:
+ expected_error = (
+ "Set exactly one of auth.oauth.jwksFilePath or auth.oauth.jwksUrl "
+ "when auth.oauth.jwtValidateSignature=true"
+ )
+ _require(
+ failures,
+ expected_error in missing_oauth_jwks_render,
+ "OAuth validation error is raised when JWKS source is missing",
+ "OAuth validation error was not raised for missing JWKS source",
+ )
+ _require(
+ failures,
+ expected_error in ambiguous_oauth_jwks_render,
+ "OAuth validation error is raised when both JWKS sources are set",
+ "OAuth validation error was not raised for ambiguous JWKS source",
+ )
+
+
+def _verify_ranger_validation_error(
+ missing_ranger_admin: str,
+ failures: list[str],
+) -> None:
+ _require(
+ failures,
+ "auth.ranger.adminUrl is required when auth.ranger.enabled=true and "
+ "ranger.enabled=false" in missing_ranger_admin,
+ "Ranger external-mode validation error is raised without adminUrl",
+ "Ranger external-mode validation error was not raised without adminUrl",
+ )
+
+
+def _verify_values_example_render(example_render: str, failures: list[str]) -> None:
+ _require(
+ failures,
+ "- ReadWriteMany" in example_render,
+ "values-example renders shared warehouse PVC with ReadWriteMany",
+ "values-example did not render shared warehouse PVC with ReadWriteMany",
+ )
+
+
+def main() -> int:
+ parser = argparse.ArgumentParser(
+ description="Assert key behavior for Impala Helm chart renders."
+ )
+ parser.add_argument(
+ "--default",
+ required=True,
+ help="Path to default render output",
+ )
+ parser.add_argument(
+ "--debug",
+ required=True,
+ help="Path to debug-level override render",
+ )
+ parser.add_argument(
+ "--polling",
+ required=True,
+ help="Path to hmsEventPollingIntervalS override render",
+ )
+ parser.add_argument(
+ "--hms-security",
+ required=True,
+ help="Path to HMS securityContext override render",
+ )
+ parser.add_argument("--ldap", required=True, help="Path to LDAP render output")
+ parser.add_argument("--ranger", required=True, help="Path to Ranger render output")
+ parser.add_argument("--kudu", required=True, help="Path to Kudu render output")
+ parser.add_argument("--oauth", required=True, help="Path to OAuth render output")
+ parser.add_argument("--secure", required=True, help="Path to secure render output")
+ parser.add_argument(
+ "--missing-kerberos-principal",
+ required=True,
+ help="Path to secure render error output with missing kerberos principal",
+ )
+ parser.add_argument(
+ "--missing-kerberos",
+ required=True,
+ help="Path to secure render error output with missing keytab secret",
+ )
+ parser.add_argument(
+ "--missing-tls",
+ required=True,
+ help="Path to secure render error output with missing TLS secret",
+ )
+ parser.add_argument(
+ "--missing-oauth-jwks",
+ required=True,
+ help="Path to OAuth render error output with no JWKS source configured",
+ )
+ parser.add_argument(
+ "--ambiguous-oauth-jwks",
+ required=True,
+ help="Path to OAuth render error output with both JWKS sources configured",
+ )
+ parser.add_argument(
+ "--missing-ranger-admin",
+ required=True,
+ help="Path to Ranger render error output with missing external admin URL",
+ )
+ parser.add_argument(
+ "--example",
+ required=True,
+ help="Path to render output generated with values-example.yaml",
+ )
+ args = parser.parse_args()
+
+ default_render = _read_text(args.default)
+ debug_render = _read_text(args.debug)
+ polling_render = _read_text(args.polling)
+ hms_security_render = _read_text(args.hms_security)
+ ldap_render = _read_text(args.ldap)
+ ranger_render = _read_text(args.ranger)
+ kudu_render = _read_text(args.kudu)
+ oauth_render = _read_text(args.oauth)
+ secure_render = _read_text(args.secure)
+ missing_kerberos_principal_render = _read_text(args.missing_kerberos_principal)
+ missing_kerberos_render = _read_text(args.missing_kerberos)
+ missing_tls_render = _read_text(args.missing_tls)
+ missing_oauth_jwks_render = _read_text(args.missing_oauth_jwks)
+ ambiguous_oauth_jwks_render = _read_text(args.ambiguous_oauth_jwks)
+ missing_ranger_admin = _read_text(args.missing_ranger_admin)
+ example_render = _read_text(args.example)
+
+ failures: list[str] = []
+
+ _verify_default_images(default_render, failures)
+ _verify_beeswax_absence(default_render, failures)
+ _verify_debug_levels(default_render, debug_render, failures)
+ _verify_hms_polling(default_render, polling_render, failures)
+ _verify_shared_warehouse_access_mode(default_render, failures)
+ _verify_hms_security_context(hms_security_render, failures)
+ _verify_ldap_render(ldap_render, failures)
+ _verify_ranger_render(ranger_render, failures)
+ _verify_kudu_render(kudu_render, failures)
+ _verify_oauth_render(oauth_render, failures)
+ _verify_secure_render(secure_render, failures)
+ _verify_secure_validation_errors(
+ missing_kerberos_principal_render,
+ missing_kerberos_render,
+ missing_tls_render,
+ failures,
+ )
+ _verify_oauth_validation_errors(
+ missing_oauth_jwks_render,
+ ambiguous_oauth_jwks_render,
+ failures,
+ )
+ _verify_ranger_validation_error(missing_ranger_admin, failures)
+ _verify_values_example_render(example_render, failures)
+
+ if failures:
+ print("\nChart assertions failed:")
+ for failure in failures:
+ print(f"- {failure}")
+ return 1
+ print("\nAll chart assertions passed.")
+ return 0
+
+
+if __name__ == "__main__":
+ sys.exit(main())
diff --git a/helm/impala/tests/run-chart-tests.sh b/helm/impala/tests/run-chart-tests.sh
new file mode 100755
index 000000000..4a56aa981
--- /dev/null
+++ b/helm/impala/tests/run-chart-tests.sh
@@ -0,0 +1,176 @@
+#!/usr/bin/env bash
+# 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.
+
+set -euo pipefail
+
+SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
+CHART_DIR="$(cd "${SCRIPT_DIR}/.." && pwd)"
+if [[ -z "${IMPALA_HOME:-}" ]]; then
+ IMPALA_HOME="$(cd "${SCRIPT_DIR}/../../.." && pwd)"
+fi
+export IMPALA_HOME
+export PATH="${IMPALA_HOME}/bin:${PATH}"
+TMP_DIR="$(mktemp -d)"
+
+cleanup() {
+ rm -rf "${TMP_DIR}"
+}
+trap cleanup EXIT
+
+echo "Running helm lint..."
+helm lint "${CHART_DIR}"
+
+echo "Rendering default manifests..."
+helm template impala-default "${CHART_DIR}" \
+ > "${TMP_DIR}/default.yaml"
+
+echo "Rendering debug level override manifests..."
+helm template impala-debug "${CHART_DIR}" \
+ --set impalad.v=3 \
+ --set catalogd.v=4 \
+ --set statestored.v=5 \
+ > "${TMP_DIR}/debug.yaml"
+
+echo "Rendering HMS polling compatibility manifests..."
+helm template impala-polling "${CHART_DIR}" \
+ --set catalogd.hmsEventPollingIntervalS=0 \
+ > "${TMP_DIR}/polling.yaml"
+
+echo "Rendering HMS securityContext manifests..."
+helm template impala-hms-security "${CHART_DIR}" \
+ --set hms.securityContext.runAsUser=0 \
+ --set hms.securityContext.runAsGroup=0 \
+ > "${TMP_DIR}/hms-security.yaml"
+
+echo "Rendering LDAP auth manifests..."
+helm template impala-ldap "${CHART_DIR}" \
+ --set auth.ldap.enabled=true \
+ --set auth.ldap.uri="ldap://ldap.example.org:389" \
+ --set-string auth.ldap.bindPattern='cn=#UID\,dc=example\,dc=org' \
+ --set auth.ldap.passwordsInClearOk=true \
+ > "${TMP_DIR}/ldap.yaml"
+
+echo "Rendering Ranger manifests..."
+helm template impala-ranger "${CHART_DIR}" \
+ --set ranger.enabled=true \
+ --set auth.ranger.enabled=true \
+ > "${TMP_DIR}/ranger.yaml"
+
+echo "Rendering Kudu manifests with persistence disabled..."
+helm template impala-kudu "${CHART_DIR}" \
+ --set persistence.enabled=false \
+ --set kudu.enabled=true \
+ --set kudu.master.persistence.enabled=false \
+ --set kudu.tserver.persistence.enabled=false \
+ > "${TMP_DIR}/kudu.yaml"
+
+echo "Rendering OAuth manifests..."
+helm template impala-oauth "${CHART_DIR}" \
+ --set auth.oauth.enabled=true \
+ --set auth.oauth.jwksUrl="https://idp.example.org/jwks" \
+ --set auth.oauth.jwtCustomClaimUsername="sub" \
+ --set auth.oauth.allowWithoutTls=true \
+ > "${TMP_DIR}/oauth.yaml"
+
+echo "Rendering secure-cluster manifests..."
+helm template impala-secure "${CHART_DIR}" \
+ --set security.istio.enabled=true \
+ --set security.kerberos.enabled=true \
+ --set security.kerberos.principal="impala/_HOST@EXAMPLE.COM" \
+ --set security.kerberos.bePrincipal="impala/_HOST@EXAMPLE.COM" \
+ --set security.kerberos.keytabSecretName="impala-kerberos-keytab" \
+ --set security.kerberos.krb5ConfigMapName="impala-krb5-conf" \
+ --set security.tls.enabled=true \
+ --set security.tls.secretName="impala-tls" \
+ > "${TMP_DIR}/secure.yaml"
+
+echo "Rendering values-example manifests..."
+helm template impala-example "${CHART_DIR}" \
+ -f "${CHART_DIR}/values-example.yaml" \
+ > "${TMP_DIR}/example.yaml"
+
+echo "Checking secure-cluster required-value validation..."
+if helm template impala-secure-no-principal "${CHART_DIR}" \
+ --set security.kerberos.enabled=true \
+ --set security.kerberos.keytabSecretName="impala-kerberos-keytab" \
+ > "${TMP_DIR}/missing-kerberos-principal.out" 2>&1; then
+ echo "Expected helm template to fail without kerberos principal."
+ exit 1
+fi
+
+if helm template impala-secure-no-keytab "${CHART_DIR}" \
+ --set security.kerberos.enabled=true \
+ --set security.kerberos.principal="impala/_HOST@EXAMPLE.COM" \
+ > "${TMP_DIR}/missing-kerberos.out" 2>&1; then
+ echo "Expected helm template to fail without kerberos keytab secret."
+ exit 1
+fi
+
+if helm template impala-secure-no-tls-secret "${CHART_DIR}" \
+ --set security.tls.enabled=true \
+ > "${TMP_DIR}/missing-tls.out" 2>&1; then
+ echo "Expected helm template to fail without TLS secret."
+ exit 1
+fi
+
+if helm template impala-oauth-no-jwks "${CHART_DIR}" \
+ --set auth.oauth.enabled=true \
+ --set auth.oauth.jwtValidateSignature=true \
+ > "${TMP_DIR}/missing-oauth-jwks.out" 2>&1; then
+ echo "Expected helm template to fail without OAuth JWKS source."
+ exit 1
+fi
+
+if helm template impala-oauth-ambiguous-jwks "${CHART_DIR}" \
+ --set auth.oauth.enabled=true \
+ --set auth.oauth.jwtValidateSignature=true \
+ --set auth.oauth.jwksUrl="https://idp.example.org/jwks" \
+ --set auth.oauth.jwksFilePath="/etc/impala/jwks.json" \
+ > "${TMP_DIR}/ambiguous-oauth-jwks.out" 2>&1; then
+ echo "Expected helm template to fail when both OAuth JWKS sources are set."
+ exit 1
+fi
+
+if helm template impala-ranger-missing-admin "${CHART_DIR}" \
+ --set auth.ranger.enabled=true \
+ --set ranger.enabled=false \
+ > "${TMP_DIR}/missing-ranger-admin.out" 2>&1; then
+ echo "Expected helm template to fail without external Ranger admin URL."
+ exit 1
+fi
+
+echo "Running chart assertions..."
+"${SCRIPT_DIR}/assert_chart.py" \
+ --default "${TMP_DIR}/default.yaml" \
+ --debug "${TMP_DIR}/debug.yaml" \
+ --polling "${TMP_DIR}/polling.yaml" \
+ --hms-security "${TMP_DIR}/hms-security.yaml" \
+ --ldap "${TMP_DIR}/ldap.yaml" \
+ --ranger "${TMP_DIR}/ranger.yaml" \
+ --kudu "${TMP_DIR}/kudu.yaml" \
+ --oauth "${TMP_DIR}/oauth.yaml" \
+ --secure "${TMP_DIR}/secure.yaml" \
+ --missing-kerberos-principal "${TMP_DIR}/missing-kerberos-principal.out" \
+ --missing-kerberos "${TMP_DIR}/missing-kerberos.out" \
+ --missing-tls "${TMP_DIR}/missing-tls.out" \
+ --missing-oauth-jwks "${TMP_DIR}/missing-oauth-jwks.out" \
+ --ambiguous-oauth-jwks "${TMP_DIR}/ambiguous-oauth-jwks.out" \
+ --missing-ranger-admin "${TMP_DIR}/missing-ranger-admin.out" \
+ --example "${TMP_DIR}/example.yaml"
+
+echo "Impala Helm chart tests completed successfully."