Skip to content

Commit 24374b4

Browse files
committed
feat(bundler)!: uniform NNN-folder bundle layout via localformat (#662)
Introduce pkg/bundler/deployer/localformat — a deployer-agnostic writer that produces the NNN-<component>/ numbered folder layout. Each folder is one of two kinds: upstream-helm (no Chart.yaml; upstream.env carries {CHART,REPO,VERSION}) or local-helm (Chart.yaml + templates/). Mixed components (Helm + raw manifests) emit two adjacent folders: a primary upstream-helm + an injected -post local-helm wrapper. Each folder carries a rendered install.sh; deploy.sh is now a generic loop with no per-component branching, only name-matched special-case blocks. Rewire --deployer helm to consume localformat. Generator.Generate delegates per-component content (values.yaml, cluster-values.yaml, Chart.yaml, templates/, install.sh) to localformat.Write and owns only top-level orchestration files (README.md, deploy.sh, undeploy.sh, checksums). Deletes ~195 lines of dead code: generateComponentDirectories, buildComponentDataList (full version), writeClusterValuesFile, hasYAMLObjects (relocated to localformat). Deletes ComponentData fields HasChart, HasManifests, IsKustomize. Rewrite deploy.sh.tmpl: generic install loop replaces ~90 lines of {{ if .IsKustomize/.HasChart/.HasManifests }} branching. Delete the ~50-line CRD-race retry block — its trigger (pre-apply raw manifests) is structurally eliminated; mixed components now apply manifests post-install via the injected -post wrapped chart, where Helm owns CRD ordering natively. Rewrite undeploy.sh.tmpl to a generic reverse loop. Preserve name-matched blocks (skyhook taint cleanup, kai-scheduler async timeout/diagnostics, DRA kubelet-plugin restart, orphaned-CRD scan) around the loops; their simplification is deferred. Refactor helm_test.go: introduce assertBundleGolden helper (mirroring localformat's writer_test) + 5 golden-file scenarios under testdata/ exercising upstream-helm-only, manifest-only, mixed gpu-operator, kai-scheduler-present, skyhook-present bundles. Goldens double as reference examples of rendered output. Delete 11 redundant tests covering removed code or duplicating golden coverage; add focused error-path tests. Net: 48 → 37 tests, 3408 → 2130 lines (−37%), coverage 87.6% → 87.9%. Update bundler_test.go, handler_test.go, and 6 chainsaw e2e fixtures to assert on NNN-prefixed paths. Breaking changes for --deployer helm consumers: - Bundle directory layout: <component>/ → NNN-<component>/ - Mixed components emit two folders (primary + -post) - Raw manifests for mixed components apply post-install only - CRD-race retry block removed; pre-apply mechanism gone - No more per-component README.md (top-level README still present) Docs: docs/user/cli-reference.md updated with new layout, folder kinds, mixed-component -post injection, and breaking-change callout. docs/contributor/component.md describes localformat as the shared base format and the load-bearing invariants (localformat never writes deployer-specific files; install.sh never name-customized; Write is deterministic).
1 parent fd15e7c commit 24374b4

43 files changed

Lines changed: 580 additions & 268 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

docs/contributor/component.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ The bundler system converts RecipeInput objects into deployment artifacts. Artif
3232
**Load-bearing invariants** (don't violate without changing the design):
3333

3434
1. **`localformat` never writes deployer-specific files.** `deploy.sh`, `helmfile.yaml`, argocd `Application` CRs, Flux `HelmRelease`s — all produced by the respective deployer after `Write()` returns. This separation is what makes a single layout consumable by every deployer.
35-
2. **`install.sh` is never name-customized.** It is rendered from one of exactly two templates (`install-upstream-helm.sh.tmpl`, `install-local-helm.sh.tmpl`), parameterized only by data (name, namespace, upstream ref). Name-keyed quirks (kai-scheduler async timeout, skyhook taint cleanup, DRA restart, orphan-CRD scan) stay in `deploy.sh` as name-matched blocks — not in `install.sh`. This is the structural barrier that prevents per-folder scripts from accumulating drift.
35+
2. **`install.sh` is never name-customized.** It is rendered from one of exactly two templates (`install-upstream-helm.sh.tmpl`, `install-local-helm.sh.tmpl`), parameterized only by data (name, namespace, upstream ref). Name-keyed quirks (kai-scheduler async timeout, nodewright-operator taint cleanup, DRA restart, orphan-CRD scan) stay in `deploy.sh` as name-matched blocks — not in `install.sh`. This is the structural barrier that prevents per-folder scripts from accumulating drift.
3636
3. **`Write` is deterministic and idempotent.** Same inputs → same on-disk bytes → same `Folder` slice. Map iteration is sorted; no timestamps or random suffixes are embedded.
3737

3838
For the full classification table, base-format invariants, and the helm deployer's call site, see `pkg/bundler/deployer/localformat/doc.go` (godoc) and `pkg/bundler/deployer/helm/helm.go::Generate`. Further design history: ticket [#662](https://github.com/NVIDIA/aicr/issues/662).

docs/user/cli-reference.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1156,7 +1156,7 @@ bundles/
11561156
11571157
Previous releases used a flat `<component>/` layout with `manifests/` siblings and a `--deployer helm` script that branched on component kind. The new format is uniform:
11581158
1159-
- All folders carry a rendered `install.sh`. The top-level `deploy.sh` is a generic loop with no per-component branching — name-matched special-case blocks (skyhook taint cleanup, kai-scheduler async timeout, orphan-CRD scan, DRA kubelet-plugin restart) live around the loop, not inside it.
1159+
- All folders carry a rendered `install.sh`. The top-level `deploy.sh` is a generic loop with no per-component branching — name-matched special-case blocks (nodewright-operator taint cleanup, kai-scheduler async timeout, orphan-CRD scan, DRA kubelet-plugin restart) live around the loop, not inside it.
11601160
- Raw manifests for mixed components now apply **post-install only**, via the injected `-post` wrapped chart. The earlier pre-apply mechanism with a CRD-race retry wrapper is gone — Helm now owns CRD ordering for mixed components natively.
11611161
- Tooling that parsed bundle paths by bare component name must account for the `NNN-` prefix.
11621162

pkg/bundler/bundler_test.go

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -423,11 +423,10 @@ func TestMake_SetEnabledOverridesPrecedence(t *testing.T) {
423423
}
424424

425425
// When included, the component appears as the second numbered folder
426-
// (gpu-operator is 001, aws-ebs-csi-driver is 002). When excluded,
427-
// neither numbering nor flat name should exist.
428-
_, statErr1 := os.Stat(filepath.Join(tmpDir, "002-aws-ebs-csi-driver"))
429-
_, statErr2 := os.Stat(filepath.Join(tmpDir, "aws-ebs-csi-driver"))
430-
included := !os.IsNotExist(statErr1) || !os.IsNotExist(statErr2)
426+
// (gpu-operator is 001, aws-ebs-csi-driver is 002). The flat layout
427+
// is gone in this PR — only assert against the numbered path.
428+
_, statErr := os.Stat(filepath.Join(tmpDir, "002-aws-ebs-csi-driver"))
429+
included := !os.IsNotExist(statErr)
431430

432431
if included != tt.expectIncluded {
433432
t.Errorf("aws-ebs-csi-driver included=%v, want %v", included, tt.expectIncluded)

pkg/bundler/deployer/helm/helm_test.go

Lines changed: 12 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1430,7 +1430,7 @@ func TestUndeployScript_PreflightSkipListCoversManifestDeletedReleases(t *testin
14301430
ComponentRefs: []recipe.ComponentRef{
14311431
{Name: "cert-manager", Namespace: "cert-manager", Chart: "cert-manager", Version: "v1.17.2", Source: "https://charts.jetstack.io"},
14321432
{Name: "kgateway", Namespace: "kgateway-system", Chart: "kgateway", Version: "v0.1.0", Source: "https://example.invalid/charts"},
1433-
{Name: "skyhook-operator", Namespace: "skyhook", Chart: "skyhook-operator", Version: "v0.1.0", Source: "https://example.invalid/charts"},
1433+
{Name: "nodewright-operator", Namespace: "skyhook", Chart: "nodewright-operator", Version: "v0.1.0", Source: "https://example.invalid/charts"},
14341434
},
14351435
DeploymentOrder: []string{"cert-manager", "kgateway", "nodewright-operator"},
14361436
},
@@ -1471,7 +1471,7 @@ func TestUndeployScript_PreflightSkipListCoversManifestDeletedReleases(t *testin
14711471
}
14721472

14731473
out := stdout.String()
1474-
for _, want := range []string{"skip:skyhook-operator", "skip:kgateway", "check:cert-manager"} {
1474+
for _, want := range []string{"skip:nodewright-operator", "skip:kgateway", "check:cert-manager"} {
14751475
if !strings.Contains(out, want) {
14761476
t.Errorf("expected %q in output; stdout=%q stderr=%q", want, out, stderr.String())
14771477
}
@@ -1795,7 +1795,7 @@ func TestUndeployScript_DynamoPlatformOwnsExplicitGroveCRDs(t *testing.T) {
17951795
// The goldens double as reference examples of what a rendered bundle looks
17961796
// like for each common shape: upstream-helm-only, manifest-only, mixed
17971797
// (upstream + raw manifests → primary + -post folder), kai-scheduler (async
1798-
// block), and skyhook-operator (pre-install taint cleanup block).
1798+
// block), and nodewright-operator (pre-install taint cleanup block).
17991799

18001800
func TestBundleGolden_UpstreamHelmOnly(t *testing.T) {
18011801
outDir := t.TempDir()
@@ -1911,19 +1911,24 @@ func TestBundleGolden_KaiSchedulerPresent(t *testing.T) {
19111911
assertBundleGolden(t, outDir, "testdata/kai_scheduler_present")
19121912
}
19131913

1914-
func TestBundleGolden_SkyhookPresent(t *testing.T) {
1914+
func TestBundleGolden_NodewrightPresent(t *testing.T) {
19151915
outDir := t.TempDir()
1916+
// Mirror the production registry: component name "nodewright-operator"
1917+
// but the upstream chart is still named "skyhook-operator". This shape
1918+
// is what real recipes have post-rename — the registry component name
1919+
// drives the name-matched taint cleanup blocks; the chart name drives
1920+
// helm install.
19161921
g := &Generator{
19171922
RecipeResult: singleComponentRecipe(
1918-
"skyhook-operator", "skyhook", "skyhook-operator", "v0.1.0",
1923+
"nodewright-operator", "skyhook", "skyhook-operator", "v0.1.0",
19191924
"https://example.invalid/charts"),
1920-
ComponentValues: map[string]map[string]any{"skyhook-operator": {}},
1925+
ComponentValues: map[string]map[string]any{"nodewright-operator": {}},
19211926
Version: "v1.0.0",
19221927
}
19231928
if _, err := g.Generate(context.Background(), outDir); err != nil {
19241929
t.Fatalf("Generate: %v", err)
19251930
}
1926-
assertBundleGolden(t, outDir, "testdata/skyhook_present")
1931+
assertBundleGolden(t, outDir, "testdata/nodewright_present")
19271932
}
19281933

19291934
// ---------------------------------------------------------------------------

pkg/bundler/deployer/helm/templates/README.md.tmpl

Lines changed: 19 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -24,13 +24,7 @@ via its own `install.sh`:
2424
| Component | Version | Namespace | Source |
2525
|-----------|---------|-----------|--------|
2626
{{ range .Components -}}
27-
{{ if .IsKustomize -}}
28-
| {{ .Name }} | Kustomize | {{ .Tag }} | {{ .Namespace }} | {{ .Repository }} ({{ .Path }}) |
29-
{{ else if .HasChart -}}
30-
| {{ .Name }} | Helm | {{ .Version }} | {{ .Namespace }} | {{ .ChartName }} ({{ .Repository }}) |
31-
{{ else -}}
32-
| {{ .Name }} | Manifests | | {{ .Namespace }} | |
33-
{{ end -}}
27+
| {{ .Name }} | {{ if .Version }}{{ .Version }}{{ else }}N/A{{ end }} | {{ .Namespace }} | {{ if .Repository }}{{ .ChartName }} ({{ .Repository }}){{ else }}local{{ end }} |
3428
{{ end }}
3529

3630
{{ if .Constraints }}
@@ -60,7 +54,7 @@ Use `--no-wait` to skip Helm chart-level waiting where AICR uses `--wait` (keeps
6054
./deploy.sh --no-wait
6155
```
6256

63-
> **Note:** The deploy script's final status reflects install/apply results. If `--best-effort` was used, one or more components may still have failed; check warning lines and logs. This does **not** mean the cluster is ready for GPU workloads. On fresh GPU nodes, cluster convergence (Nodewright node tuning, GPU operator operand rollout, DRA kubelet plugin registration) continues asynchronously after the script exits. See the [AICR CLI Reference](https://github.com/NVIDIA/aicr/blob/main/docs/user/cli-reference.md#deploy-script-behavior-deploysh) for details.
57+
> **Note:** The deploy script's final status reflects install/apply results. If `--best-effort` was used, one or more components may still have failed; check warning lines and logs. This does **not** guarantee the cluster is ready to schedule workloads — operator-driven cluster convergence (CRD reconciliation, node tuning, plugin registration, etc.) continues asynchronously after the script exits, in operator-specific ways. See the [AICR CLI Reference](https://github.com/NVIDIA/aicr/blob/main/docs/user/cli-reference.md#deploy-script-behavior-deploysh) for details.
6458

6559
## Manual Installation
6660

@@ -71,56 +65,24 @@ with the right arguments baked in. To install a single component manually:
7165
cd NNN-<component-name>
7266
bash install.sh
7367
```
74-
{{ else if .HasChart -}}
75-
```bash
76-
{{ if .IsOCI -}}
77-
helm upgrade --install {{ .Name }} {{ .Repository }}/{{ .ChartName }} \
78-
--version {{ .Version }} \
79-
-n {{ .Namespace }} --create-namespace \
80-
-f {{ .Name }}/values.yaml \
81-
-f {{ .Name }}/cluster-values.yaml \
82-
--wait --timeout 10m
83-
{{ else -}}
84-
helm upgrade --install {{ .Name }} {{ .ChartName }} \
85-
--repo {{ .Repository }} \
86-
--version {{ .Version }} \
87-
-n {{ .Namespace }} --create-namespace \
88-
-f {{ .Name }}/values.yaml \
89-
-f {{ .Name }}/cluster-values.yaml \
90-
--wait --timeout 10m
91-
{{ end -}}
92-
```
93-
{{ end -}}
94-
{{ if .HasManifests }}
95-
```bash
96-
kubectl apply -f {{ .Name }}/manifests/
97-
```
98-
{{ end }}
99-
{{ end }}
10068

10169
## Customization
10270

103-
Each Helm component has two values files in its directory:
104-
105-
- `values.yaml` — resolved configuration from the recipe. Edit to override defaults:
71+
Each component folder has its own `values.yaml` (static) and `cluster-values.yaml`
72+
(dynamic, per-cluster). Edit either before deploying:
10673

107-
```bash
108-
vim gpu-operator/values.yaml
109-
```
110-
111-
- `cluster-values.yaml` — install-time parameters. Any paths declared with
112-
`aicr bundle --dynamic <component>:<path>` are pulled out of `values.yaml`
113-
and placed here for you to fill in. The file is always created (empty if
114-
no dynamic paths were declared) and passed to `helm upgrade --install`
115-
alongside `values.yaml` by both `deploy.sh` and the per-component commands
116-
in the "Manual Installation" section above.
74+
```bash
75+
vim NNN-<component-name>/values.yaml
76+
vim NNN-<component-name>/cluster-values.yaml
77+
```
11778

11879
## Upgrade
11980

12081
Re-run the per-component install.sh to upgrade an already-installed release:
12182

12283
```bash
123-
helm upgrade <component> <chart> --version <version> -n <namespace> -f <component>/values.yaml -f <component>/cluster-values.yaml --wait --timeout 10m
84+
cd NNN-<component-name>
85+
bash install.sh
12486
```
12587

12688
## Uninstall
@@ -144,20 +106,27 @@ helm uninstall {{ .Name }} -n {{ .Namespace }}
144106
### Check deployment status
145107

146108
```bash
147-
kubectl get pods -A | grep -E 'gpu-operator|network-operator|cert-manager'
109+
kubectl get pods -A | grep -E '{{ range $i, $c := .Components }}{{ if $i }}|{{ end }}{{ $c.Name }}{{ end }}'
148110
```
149111

150112
### View component logs
151113

114+
Inspect a single component's pods (replace `<component>` and `<namespace>`
115+
with one of the entries from the table above):
116+
152117
```bash
153-
kubectl logs -n gpu-operator -l app=gpu-operator
118+
kubectl logs -n <namespace> -l app.kubernetes.io/instance=<component>
154119
```
155120

121+
{{- $hasGPU := false -}}
122+
{{- range .Components -}}{{- if eq .Name "gpu-operator" -}}{{- $hasGPU = true -}}{{- end -}}{{- end -}}
123+
{{- if $hasGPU }}
156124
### Verify GPU access
157125

158126
```bash
159127
kubectl get nodes -o jsonpath='{.items[*].status.allocatable}' | jq '.["nvidia.com/gpu"]'
160128
```
129+
{{- end }}
161130

162131
## References
163132

pkg/bundler/deployer/helm/templates/deploy.sh.tmpl

Lines changed: 17 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ set -euo pipefail
3131
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
3232

3333
# Run helm commands from a temp directory to prevent local chart directories
34-
# (e.g., bundle/001-skyhook-operator/) from shadowing remote chart references.
34+
# (e.g., bundle/001-nodewright-operator/) from shadowing remote chart references.
3535
HELM_WORKDIR="$(mktemp -d)"
3636
trap 'rm -rf "${HELM_WORKDIR}"; exit 130' INT TERM
3737
trap 'rm -rf "${HELM_WORKDIR}"' EXIT
@@ -263,17 +263,17 @@ if [[ "${nodewright_available}" == "0" || -z "${nodewright_available}" ]]; then
263263
# Extract the taint key from bundle values. The YAML value is a taint string
264264
# like "custom.io/gate=true:NoSchedule" — extract the key before the first "=".
265265
# If runtimeRequiredTaint is not set, use the default skyhook.nvidia.com.
266-
SKYHOOK_TAINT_KEY="skyhook.nvidia.com"
267-
# Locate skyhook-operator's NNN-prefixed directory at runtime.
268-
skyhook_dir="$(ls -d "${SCRIPT_DIR}"/[0-9][0-9][0-9]-skyhook-operator 2>/dev/null | head -1)"
269-
if [[ -n "${skyhook_dir}" && -f "${skyhook_dir}/values.yaml" ]]; then
270-
custom_taint_line=$(grep 'runtimeRequiredTaint:' "${skyhook_dir}/values.yaml" 2>/dev/null || true)
266+
NODEWRIGHT_TAINT_KEY="skyhook.nvidia.com"
267+
# Locate nodewright-operator's NNN-prefixed directory at runtime.
268+
nodewright_dir="$(ls -d "${SCRIPT_DIR}"/[0-9][0-9][0-9]-nodewright-operator 2>/dev/null | head -1)"
269+
if [[ -n "${nodewright_dir}" && -f "${nodewright_dir}/values.yaml" ]]; then
270+
custom_taint_line=$(grep 'runtimeRequiredTaint:' "${nodewright_dir}/values.yaml" 2>/dev/null || true)
271271
if [[ -n "${custom_taint_line}" ]]; then
272272
taint_value=$(echo "${custom_taint_line}" | sed 's/.*runtimeRequiredTaint:[[:space:]]*//' | tr -d '"' | tr -d "'")
273273
if [[ -n "${taint_value}" ]]; then
274274
# Handle both key=value:effect and key:effect formats
275-
SKYHOOK_TAINT_KEY="${taint_value%%=*}"
276-
SKYHOOK_TAINT_KEY="${SKYHOOK_TAINT_KEY%%:*}"
275+
NODEWRIGHT_TAINT_KEY="${taint_value%%=*}"
276+
NODEWRIGHT_TAINT_KEY="${NODEWRIGHT_TAINT_KEY%%:*}"
277277
fi
278278
fi
279279
fi
@@ -312,7 +312,13 @@ for dir in "${SCRIPT_DIR}"/[0-9][0-9][0-9]-*/; do
312312
dir="${dir%/}"
313313
base="${dir##*/}"
314314
name="${base#[0-9][0-9][0-9]-}"
315-
echo "Installing ${name} (${base})..."
315+
# Source the namespace from the folder's install.sh — not the folder
316+
# basename — because the helm release name and its target namespace can
317+
# differ (e.g. nodewright-operator → namespace skyhook; gpu-operator-post →
318+
# namespace gpu-operator). cleanup_helm_hooks and the kai diagnostics
319+
# both operate on the namespace.
320+
namespace=$(awk '{ for (i=1;i<NF;i++) if ($i=="--namespace") { print $(i+1); exit } }' "${dir}/install.sh")
321+
echo "Installing ${name} (${base}) into namespace ${namespace}..."
316322

317323
# Derive wait args: global --wait/--no-wait behavior + per-component timeout.
318324
COMPONENT_HELM_TIMEOUT="${HELM_TIMEOUT}"
@@ -343,13 +349,13 @@ for dir in "${SCRIPT_DIR}"/[0-9][0-9][0-9]-*/; do
343349
break
344350
fi
345351
attempt=$((attempt + 1))
346-
dump_kai_scheduler_helm_diagnostics "${name}"
352+
dump_kai_scheduler_helm_diagnostics "${namespace}"
347353
if [[ ${attempt} -gt ${COMPONENT_MAX_RETRIES} ]]; then
348354
echo "ERROR: ${name} install failed after ${attempt} attempts"
349355
helm_failed "${name}"
350356
break
351357
fi
352-
cleanup_helm_hooks "${name}"
358+
cleanup_helm_hooks "${namespace}"
353359
wait_secs=$(backoff_seconds "${attempt}")
354360
echo "RETRY: ${name} install failed (attempt ${attempt}/${COMPONENT_MAX_RETRIES}), retrying in ${wait_secs}s..."
355361
sleep "${wait_secs}"

pkg/bundler/deployer/helm/templates/undeploy.sh.tmpl

Lines changed: 23 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -469,28 +469,41 @@ for dir in $(ls -1d "${SCRIPT_DIR}"/[0-9][0-9][0-9]-*/ 2>/dev/null | sort -r); d
469469
continue
470470
fi
471471
echo "Uninstalling ${name} (${ns})..."
472+
# For local-helm folders (Chart.yaml + templates/), kubectl-delete the
473+
# rendered templates BEFORE helm uninstall. The templates may carry
474+
# helm.sh/hook annotations (post-install/post-upgrade) which helm does
475+
# not track or clean up on uninstall — so without this pre-delete, the
476+
# operator gets removed but its hook-created CRs (and their finalizers)
477+
# linger. Doing the delete while the controller is still running lets
478+
# finalizers clear naturally.
479+
if [[ -d "${dir}/templates" ]]; then
480+
for tpl in "${dir}/templates/"*.yaml; do
481+
[[ -f "${tpl}" ]] || continue
482+
kubectl delete -n "${ns}" -f "${tpl}" --ignore-not-found --timeout="${HELM_TIMEOUT}s" || true
483+
done
484+
fi
472485
helm_force_uninstall "${name}" "${ns}"
473486
delete_release_cluster_resources "${name}" "${ns}"
474487
delete_orphaned_webhooks_for_ns "${ns}"
475488
done
476489

477-
# Remove skyhook node taints that persist after operator removal.
478-
# Skyhook taints nodes during kernel tuning. The taint key is configurable
490+
# Remove nodewright node taints that persist after operator removal.
491+
# Nodewright taints nodes during kernel tuning. The taint key is configurable
479492
# via runtimeRequiredTaint (defaults to skyhook.nvidia.com).
480493
{{- range .ComponentsReversed }}
481-
{{- if eq .Name "skyhook-operator" }}
482-
SKYHOOK_TAINT_KEY="skyhook.nvidia.com"
483-
# Locate skyhook-operator's NNN-prefixed directory at runtime.
484-
skyhook_dir="$(ls -d "${SCRIPT_DIR}"/[0-9][0-9][0-9]-skyhook-operator 2>/dev/null | head -1)"
485-
if [[ -n "${skyhook_dir}" && -f "${skyhook_dir}/values.yaml" ]]; then
486-
custom_taint_line=$(grep 'runtimeRequiredTaint:' "${skyhook_dir}/values.yaml" 2>/dev/null || true)
494+
{{- if eq .Name "nodewright-operator" }}
495+
NODEWRIGHT_TAINT_KEY="skyhook.nvidia.com"
496+
# Locate nodewright-operator's NNN-prefixed directory at runtime.
497+
nodewright_dir="$(ls -d "${SCRIPT_DIR}"/[0-9][0-9][0-9]-nodewright-operator 2>/dev/null | head -1)"
498+
if [[ -n "${nodewright_dir}" && -f "${nodewright_dir}/values.yaml" ]]; then
499+
custom_taint_line=$(grep 'runtimeRequiredTaint:' "${nodewright_dir}/values.yaml" 2>/dev/null || true)
487500
if [[ -n "${custom_taint_line}" ]]; then
488501
# Extract value after "runtimeRequiredTaint:", then extract taint key before "="
489502
taint_value=$(echo "${custom_taint_line}" | sed 's/.*runtimeRequiredTaint:[[:space:]]*//' | tr -d '"' | tr -d "'")
490503
if [[ -n "${taint_value}" ]]; then
491504
# Handle both key=value:effect and key:effect formats
492-
SKYHOOK_TAINT_KEY="${taint_value%%=*}"
493-
SKYHOOK_TAINT_KEY="${SKYHOOK_TAINT_KEY%%:*}"
505+
NODEWRIGHT_TAINT_KEY="${taint_value%%=*}"
506+
NODEWRIGHT_TAINT_KEY="${NODEWRIGHT_TAINT_KEY%%:*}"
494507
fi
495508
fi
496509
fi

0 commit comments

Comments
 (0)