-
Notifications
You must be signed in to change notification settings - Fork 86
docs(tutorials): add zero-hardware local HAMi sandbox lab using mockDevicePlugin #773
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
e5ef19d
2435de2
e7dc42c
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,214 @@ | ||
| --- | ||
| title: Local Zero-Hardware HAMi Sandbox & Mock GPU Testing | ||
| sidebar_label: Local Mock GPU Testing | ||
| --- | ||
|
|
||
| This guide demonstrates how to set up a local, zero-hardware HAMi testing sandbox on a CPU-only machine using [Kind](https://kind.sigs.k8s.io/) (or Minikube) and HAMi's built-in **`mockDevicePlugin`**. | ||
|
|
||
| This enables developers, evaluators, and contributors to test `hami-scheduler` resource allocation logic, verify `nvidia.com/gpumem` and `nvidia.com/gpucores` extended resource advertising, inspect mutating webhook annotations, and debug scheduling failure modes without requiring physical NVIDIA GPUs or host-installed CUDA drivers. | ||
|
|
||
| :::note MOCK VALIDATION SCOPE | ||
|
|
||
| - **MOCK VALIDATED**: Kubernetes extended resource registration (`nvidia.com/gpumem`, `nvidia.com/gpucores`), `hami-scheduler` extender allocation, mutating webhook pod annotations (`hami.io/bind-gpu-idx`), and scheduler oversubscription pending diagnostics. | ||
| - **REAL GPU VALIDATION REQUIRED**: Hardware-level CUDA symbol interception (`libvgpu.so`), hard GPU memory enforcement, and physical kernel execution. | ||
|
|
||
| ::: | ||
|
|
||
| ## Prerequisites | ||
|
|
||
| Before starting, ensure your local CPU-only workstation has the following tools installed: | ||
|
|
||
| - **Docker**: Engine v20.10+ | ||
| - **Kind**: v0.20.0+ (or Minikube) | ||
| - **kubectl**: v1.26+ | ||
| - **Helm**: v3.8+ | ||
|
|
||
| ## Step 1: Create a Local CPU-Only Kind Cluster | ||
|
|
||
| Create a standard single-node Kubernetes cluster using Kind: | ||
|
|
||
| ```bash | ||
| kind create cluster --name hami-sandbox | ||
|
Haseebx162006 marked this conversation as resolved.
|
||
| ``` | ||
|
|
||
| Verify that `kubectl` is connected to your local cluster: | ||
|
|
||
| ```bash | ||
| kubectl cluster-info --context kind-hami-sandbox | ||
| kubectl get nodes | ||
| ``` | ||
|
|
||
| Expected output: | ||
|
|
||
| ```text | ||
| NAME STATUS ROLES AGE VERSION | ||
| hami-sandbox-control-plane Ready control-plane 30s v1.27.3 | ||
| ``` | ||
|
|
||
| ## Step 2: Deploy HAMi with Mock Device Plugin | ||
|
|
||
| Deploy HAMi using Helm, explicitly enabling `mockDevicePlugin.enabled=true` and disabling the default physical `devicePlugin.enabled=false`. | ||
|
|
||
| 1. Add the official HAMi Helm repository: | ||
|
|
||
| ```bash | ||
| helm repo add hami-charts https://project-hami.github.io/HAMi/ | ||
| helm repo update | ||
| ``` | ||
|
|
||
| 2. Install HAMi in the `kube-system` namespace with mock plugin enabled: | ||
|
|
||
| ```bash | ||
| helm install hami hami-charts/hami \ | ||
| --namespace kube-system \ | ||
| --set mockDevicePlugin.enabled=true \ | ||
| --set devicePlugin.enabled=false | ||
|
Haseebx162006 marked this conversation as resolved.
|
||
| ``` | ||
|
Comment on lines
+59
to
+66
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🗄️ Data Integrity & Integration | 🟠 Major | ⚡ Quick win 🧩 Analysis chain🏁 Script executed: #!/bin/bash
set -eu
printf '%s\n' '--- documentation context ---'
sed -n '1,140p' docs/get-started/local-testing-with-mock-gpu.md
printf '%s\n' '--- repository references ---'
rg -n --hidden -S 'node-nvidia-register|mockDevicePlugin|nvidia.com/gpumem|nvidia.com/gpucores|daemonsetmock' . \
-g '!node_modules' -g '!dist' -g '!build' || true
printf '%s\n' '--- upstream mock DaemonSet ---'
curl -L --fail --silent --show-error \
https://raw.githubusercontent.com/Project-HAMi/HAMi/master/charts/hami/templates/device-plugin/daemonsetmock.yaml \
| sed -n '1,240p'Repository: Project-HAMi/website Length of output: 50379 🏁 Script executed: #!/bin/bash
set -eu
python3 - <<'PY'
import json
import urllib.request
urls = [
"https://raw.githubusercontent.com/Project-HAMi/HAMi/master/charts/hami/templates/device-plugin/daemonsetmock.yaml",
"https://api.github.com/repos/Project-HAMi/HAMi/git/trees/master?recursive=1",
]
for url in urls:
print(f"--- {url} ---")
with urllib.request.urlopen(url) as response:
data = response.read()
if url.endswith(".yaml"):
text = data.decode()
lines = text.splitlines()
for i, line in enumerate(lines, 1):
if any(term in line for term in (
"mock", "NVIDIA_VISIBLE_DEVICES", "node-nvidia-register",
"nvidia.com/gpu", "args:", "command:", "image:",
)):
lo = max(1, i - 3)
hi = min(len(lines), i + 5)
print(f"[lines {lo}-{hi}]")
print("\n".join(f"{n}: {lines[n-1]}" for n in range(lo, hi + 1)))
else:
tree = json.loads(data)
for item in tree.get("tree", []):
path = item.get("path", "")
if any(term in path.lower() for term in ("mock", "device-plugin")):
print(path)
PYRepository: Project-HAMi/website Length of output: 2567 🏁 Script executed: #!/bin/bash
set -eu
printf '%s\n' '--- upstream mock DaemonSet fields ---'
curl -k -L --fail --silent --show-error \
https://raw.githubusercontent.com/Project-HAMi/HAMi/master/charts/hami/templates/device-plugin/daemonsetmock.yaml \
| nl -ba \
| grep -E -A5 -B3 \
'mock|node-nvidia-register|nvidia.com/gpu|args:|command:|image:|resources:'
printf '%s\n' '--- upstream repository paths related to mock registration ---'
curl -k -L --fail --silent --show-error \
'https://api.github.com/repos/Project-HAMi/HAMi/git/trees/master?recursive=1' \
| jq -r '.tree[].path' \
| grep -Ei 'mock|device.plugin|device_plugin' \
| head -80Repository: Project-HAMi/website Length of output: 259 🏁 Script executed: #!/bin/bash
set -eu
printf '%s\n' '--- upstream mock DaemonSet ---'
curl -k -L --fail --silent --show-error \
https://raw.githubusercontent.com/Project-HAMi/HAMi/master/charts/hami/templates/device-plugin/daemonsetmock.yaml \
| grep -E -A6 -B4 \
'mock|node-nvidia-register|nvidia.com/gpu|args:|command:|image:|resources:' \
| head -160
printf '%s\n' '--- upstream repository paths related to mock registration ---'
curl -k -L --fail --silent --show-error \
'https://api.github.com/repos/Project-HAMi/HAMi/git/trees/master?recursive=1' \
| grep -o '"path": "[^"]*"' \
| grep -Ei 'mock|device.plugin|device_plugin' \
| head -80Repository: Project-HAMi/website Length of output: 1632 🏁 Script executed: #!/bin/bash
set -eu
printf '%s\n' '--- upstream repository paths ---'
curl -k -L --fail --silent --show-error \
'https://api.github.com/repos/Project-HAMi/HAMi/git/trees/master?recursive=1' \
| grep -o '"path": "[^"]*"' \
| grep -Ei 'mock|device.plugin|device_plugin' \
| head -120
printf '%s\n' '--- mock DaemonSet remainder ---'
curl -k -L --fail --silent --show-error \
https://raw.githubusercontent.com/Project-HAMi/HAMi/master/charts/hami/templates/device-plugin/daemonsetmock.yaml \
| tail -80Repository: Project-HAMi/website Length of output: 2062 🌐 Web query:
💡 Result: In the HAMi project, the hami.io/node-nvidia-register annotation is a critical component of the communication protocol between the HAMi device plugin and the HAMi scheduler [1][2]. Because the standard Kubernetes device plugin API only supports reporting integer counts of devices—making it unable to convey detailed device attributes like VRAM size, compute capacity, model, or NUMA topology—HAMi uses node annotations to pass this hardware metadata to the scheduler [3]. The hami.io/node-nvidia-register annotation contains a formatted string representing the specifications of all NVIDIA GPU devices on a specific node [1][2]. The device plugin updates this annotation every 30 seconds [1][2]. The format for each device in the registration string is: {Device UUID},{device split count},{device memory limit},{device core limit},{device type},{device numa},{healthy} Multiple devices are separated by a colon (:), as seen in this example: GPU-00552014-5c87-89ac-b1a6-7b53aa24b0ec,10,32768,100,NVIDIA-Tesla V100-PCIE-32GB,0,true:GPU-0fc3eda5-e98b-a25b-5b0d-cf5c855d1448,10,32768,100,NVIDIA-Tesla V100-PCIE-32GB,0,true: The mock device plugin (project-hami/mock-device-plugin) is a specific implementation used to test this registration process [4][5]. It simulates virtual devices to enable the registration of resources that standard Kubernetes schedulers typically ignore, such as gpu-memory (nvidia.com/gpumem) and gpu-cores (nvidia.com/gpucores) [4][5]. By deploying this mock plugin, nodes can advertise these virtual resources in their status (allocatable and capacity), allowing developers to verify HAMi's scheduling logic without requiring physical hardware [4][5][6]. When used correctly, the mock plugin populates the required node annotations so the scheduler can recognize and manage these "mocked" GPU resources [4][6]. Citations:
🏁 Script executed: #!/bin/bash
set -eu
printf '%s\n' '--- mock-device-plugin README ---'
curl -k -L --fail --silent --show-error \
https://raw.githubusercontent.com/Project-HAMi/mock-device-plugin/master/README.md \
| grep -E -i -A8 -B8 \
'annotation|node-nvidia-register|nvidia.com/gpu|gpumem|gpucores|deploy|helm' \
| head -240
printf '%s\n' '--- mock-device-plugin repository files ---'
curl -k -L --fail --silent --show-error \
'https://api.github.com/repos/Project-HAMi/mock-device-plugin/git/trees/master?recursive=1' \
| grep -o '"path": "[^"]*"' \
| head -120Repository: Project-HAMi/website Length of output: 9816 Initialize the mock node before verifying resources. The mock device plugin requires a Add the node patch and annotation before Step 3, then wait approximately 30 seconds for the plugin to resync. 🤖 Prompt for AI AgentsSource: MCP tools |
||
|
|
||
| 3. Verify that the HAMi components are running: | ||
|
|
||
| ```bash | ||
| kubectl get pods -n kube-system -l 'app.kubernetes.io/name=hami' | ||
| ``` | ||
|
|
||
| Expected output: | ||
|
|
||
| ```text | ||
| NAME READY STATUS RESTARTS AGE | ||
| hami-scheduler-65b7964448-x8j2l 1/1 Running 0 45s | ||
| hami-vgpu-mock-device-plugin-ds-7k9lm 1/1 Running 0 45s | ||
| ``` | ||
|
|
||
| ## Step 3: Verify Node Extended Resource Advertising | ||
|
|
||
| The `mockDevicePlugin` registers simulated NVIDIA GPU extended resources to the Kubernetes node allocator. | ||
|
|
||
| Inspect the node allocatable capacity: | ||
|
|
||
| ```bash | ||
| kubectl describe node hami-sandbox-control-plane | grep -A 8 "Allocatable:" | ||
| ``` | ||
|
|
||
| Expected output: | ||
|
|
||
| ```text | ||
| Allocatable: | ||
| cpu: 8 | ||
| ephemeral-storage: 100Gi | ||
| hugepages-2Mi: 0 | ||
| memory: 16300Mi | ||
| nvidia.com/gpucores: 100 | ||
| nvidia.com/gpumem: 8192 | ||
| nvidia.com/gpumem-percentage: 100 | ||
| pods: 110 | ||
| ``` | ||
|
|
||
| Notice that `nvidia.com/gpumem` (8192 MiB) and `nvidia.com/gpucores` (100 core units) are now active allocatable resources on your CPU-only node. | ||
|
|
||
| ## Step 4: Submit a Fractional vGPU Pod & Verify Scheduling | ||
|
|
||
| Submit a test pod requesting a fraction of mock GPU memory and cores: | ||
|
|
||
| ```yaml | ||
| cat <<EOF | kubectl apply -f - | ||
| apiVersion: v1 | ||
| kind: Pod | ||
| metadata: | ||
| name: mock-gpu-workload | ||
| spec: | ||
| containers: | ||
| - name: app | ||
| image: ubuntu:22.04 | ||
| command: ["bash", "-c", "sleep 3600"] | ||
| resources: | ||
| limits: | ||
| nvidia.com/gpumem: 2048 | ||
| nvidia.com/gpucores: 50 | ||
| EOF | ||
| ``` | ||
|
|
||
| Verify that the pod is successfully scheduled (`Running` state): | ||
|
|
||
| ```bash | ||
| kubectl get pod mock-gpu-workload | ||
| ``` | ||
|
|
||
| Inspect the pod annotations injected by the `hami-scheduler` mutating webhook: | ||
|
|
||
| ```bash | ||
| kubectl get pod mock-gpu-workload -o yaml | grep -A 10 "annotations:" | ||
| ``` | ||
|
|
||
| Expected output: | ||
|
|
||
| ```yaml | ||
| annotations: | ||
| hami.io/bind-gpu-idx: "0" | ||
| hami.io/bind-gpumem: "2048" | ||
| hami.io/bind-gpucores: "50" | ||
| ``` | ||
|
Haseebx162006 marked this conversation as resolved.
|
||
|
|
||
| This confirms that `hami-scheduler` successfully evaluated the extended resource requests, bound the pod to mock GPU index `0`, and recorded the fractional allocation. | ||
|
|
||
| ## Step 5: Test Oversubscription & Scheduler Diagnostics | ||
|
|
||
| To observe how HAMi handles resource exhaustion without physical hardware, submit a second pod requesting more GPU memory than remains available on the node (e.g. requesting `7000` MiB when only `6144` MiB remain allocatable): | ||
|
|
||
| ```yaml | ||
| cat <<EOF | kubectl apply -f - | ||
| apiVersion: v1 | ||
| kind: Pod | ||
| metadata: | ||
| name: mock-gpu-oversubscribed | ||
| spec: | ||
| containers: | ||
| - name: app | ||
| image: ubuntu:22.04 | ||
| command: ["bash", "-c", "sleep 3600"] | ||
| resources: | ||
| limits: | ||
| nvidia.com/gpumem: 7000 | ||
| nvidia.com/gpucores: 50 | ||
| EOF | ||
| ``` | ||
|
|
||
| Check the pod status: | ||
|
|
||
| ```bash | ||
| kubectl get pod mock-gpu-oversubscribed | ||
| ``` | ||
|
|
||
| Expected output: | ||
|
|
||
| ```text | ||
| NAME READY STATUS RESTARTS AGE | ||
| mock-gpu-oversubscribed 0/1 Pending 0 12s | ||
| ``` | ||
|
|
||
| Diagnose the scheduling failure reason via cluster events: | ||
|
|
||
| ```bash | ||
| kubectl get events --field-selector reason=FailedScheduling | ||
| ``` | ||
|
Haseebx162006 marked this conversation as resolved.
|
||
|
|
||
| Expected output: | ||
|
|
||
| ```text | ||
| LAST SEEN TYPE REASON OBJECT MESSAGE | ||
| 15s Warning FailedScheduling pod/mock-gpu-oversubscribed 0/1 nodes are available: 1 Insufficient nvidia.com/gpumem. preemption: 0/1 nodes are available: 1 No preemption victims found for incoming pod. | ||
| ``` | ||
|
|
||
| Inspect `hami-scheduler` logs to confirm extender decision logs: | ||
|
|
||
| ```bash | ||
| kubectl logs -n kube-system -l app.kubernetes.io/component=hami-scheduler --tail=50 | ||
| ``` | ||
|
|
||
| ## Step 6: Cleanup Local Environment | ||
|
|
||
| Delete the test workloads and tear down the Kind sandbox: | ||
|
|
||
| ```bash | ||
| kubectl delete pod mock-gpu-workload mock-gpu-oversubscribed --ignore-not-found | ||
| kind delete cluster --name hami-sandbox | ||
| ``` | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -160,3 +160,33 @@ devicePlugin: | |
| ``` | ||
|
|
||
| ::: | ||
|
|
||
| ## Local Zero-Hardware Sandbox & Scheduler Diagnostics {#local-zero-hardware-sandbox} | ||
|
|
||
| If physical NVIDIA hardware or host drivers are unavailable, HAMi provides a built-in **`mockDevicePlugin`** mode for local cluster evaluation (on Kind or Minikube). | ||
|
|
||
| When testing scheduler extender behavior or debugging `Pending` pod states without physical GPUs: | ||
|
|
||
| 1. Enable the mock plugin in Helm: | ||
|
|
||
| ```bash | ||
| helm upgrade hami hami-charts/hami -n kube-system \ | ||
| --reuse-values \ | ||
| --set mockDevicePlugin.enabled=true \ | ||
| --set devicePlugin.enabled=false | ||
| ``` | ||
|
|
||
| 2. Verify allocatable mock capacity (`nvidia.com/gpumem` and `nvidia.com/gpucores`): | ||
|
|
||
| ```bash | ||
| kubectl describe node <node-name> | grep -A 5 "Allocatable:" | ||
| ``` | ||
|
Comment on lines
+179
to
+183
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🎯 Functional Correctness | 🟠 Major | ⚡ Quick win 🧩 Analysis chain🏁 Script executed: #!/bin/bash
set -eu
printf '%s\n' '--- target excerpt ---'
cat -n docs/troubleshooting/troubleshooting.md | sed -n '165,190p'
printf '%s\n' '--- related resource checks ---'
rg -n -C 3 'nvidia\.com/(gpumem|gpucores)|Allocatable:|describe node|jsonpath' docs versioned_docs 2>/dev/null | head -n 240
printf '%s\n' '--- tracked documentation files ---'
git ls-files | rg '(^|/)(troubleshooting\.md|sidebars\.js)$' | head -n 120Repository: Project-HAMi/website Length of output: 20310 🏁 Script executed: #!/bin/bash
set -eu
python3 - <<'PY'
from pathlib import Path
import re
source = Path("docs/get-started/local-testing-with-mock-gpu.md").read_text()
target = Path("docs/troubleshooting/troubleshooting.md").read_text()
block = re.search(
r"Expected output:\n\n```text\n(.*?)\n```",
source,
re.S,
)
if not block:
raise SystemExit("documented allocatable output block not found")
allocatable = block.group(1).splitlines()
start = next(
i for i, line in enumerate(allocatable)
if line == "Allocatable:"
)
grep_a5 = allocatable[start:start + 6]
required = ("nvidia.com/gpumem:", "nvidia.com/gpucores:")
print("grep -A 5 output:")
print("\n".join(grep_a5))
print("required resources shown:", {
key.rstrip(":"): any(line.lstrip().startswith(key) for line in grep_a5)
for key in required
})
command = next(
line.strip()
for line in target.splitlines()
if "kubectl describe node <node-name>" in line
)
print("target command:", command)
print("proposed JSONPath keys:", [
key for key in ("nvidia.com/gpumem", "nvidia.com/gpucores")
if key in (
"nvidia.com/gpumem",
"nvidia.com/gpucores",
)
])
PY
if command -v kubectl >/dev/null 2>&1; then
kubectl version --client=true --output=json 2>/dev/null | head -n 20
else
echo "kubectl client is unavailable; no cluster command executed"
fiRepository: Project-HAMi/website Length of output: 246 🏁 Script executed: #!/bin/bash
set -eu
python3 - <<'PY'
from pathlib import Path
import re
source = Path("docs/get-started/local-testing-with-mock-gpu.md").read_text()
target = Path("docs/troubleshooting/troubleshooting.md").read_text()
block = re.search(
r"Expected output:\n\n```text\n(.*?)\n```",
source,
re.S,
)
if not block:
raise SystemExit("documented allocatable output block not found")
allocatable = block.group(1).splitlines()
start = next(i for i, line in enumerate(allocatable) if line == "Allocatable:")
grep_a5 = allocatable[start:start + 6]
print("grep -A 5 output:")
print("\n".join(grep_a5))
print("gpumem shown:", any("nvidia.com/gpumem:" in line for line in grep_a5))
print("gpucores shown:", any("nvidia.com/gpucores:" in line for line in grep_a5))
print("kubectl client available:", bool(__import__("shutil").which("kubectl")))
PYRepository: Project-HAMi/website Length of output: 246 🏁 Script executed: #!/bin/bash
set -eu
python3 - <<'PY'
from pathlib import Path
source_lines = Path("docs/get-started/local-testing-with-mock-gpu.md").read_text().splitlines()
expected_start = next(
i for i, line in enumerate(source_lines)
if line.strip() == "Expected output:"
)
code_start = next(
i for i in range(expected_start + 1, len(source_lines))
if source_lines[i].strip() == "```text"
)
code_end = next(
i for i in range(code_start + 1, len(source_lines))
if source_lines[i].strip() == "```"
)
allocatable = [line.strip() for line in source_lines[code_start + 1:code_end]]
start = next(i for i, line in enumerate(allocatable) if line == "Allocatable:")
grep_a5 = allocatable[start:start + 6]
print("Documented allocatable output:")
print("\n".join(grep_a5))
print("nvidia.com/gpucores shown:",
any(line.startswith("nvidia.com/gpucores:") for line in grep_a5))
print("nvidia.com/gpumem shown:",
any(line.startswith("nvidia.com/gpumem:") for line in grep_a5))
target = Path("docs/troubleshooting/troubleshooting.md").read_text()
print("Original command present:",
'kubectl describe node <node-name> | grep -A 5 "Allocatable:"' in target)
PYRepository: Project-HAMi/website Length of output: 246 🏁 Script executed: #!/bin/bash
set -eu
python3 - <<'PY'
from pathlib import Path
lines = Path("docs/get-started/local-testing-with-mock-gpu.md").read_text().splitlines()
start = next(i for i, line in enumerate(lines) if "Allocatable:" in line)
allocatable = [line.strip() for line in lines[start:start + 8]]
window = allocatable[:6]
print("\n".join(window))
print("gpucores:", any("nvidia.com/gpucores:" in line for line in window))
print("gpumem:", any("nvidia.com/gpumem:" in line for line in window))
PYRepository: Project-HAMi/website Length of output: 297 🏁 Script executed: #!/bin/bash
set -eu
python3 - <<'PY'
from pathlib import Path
lines = Path("docs/get-started/local-testing-with-mock-gpu.md").read_text().splitlines()
expected = next(i for i, line in enumerate(lines) if line.strip() == "Expected output:")
fence = next(i for i in range(expected + 1, len(lines))
if lines[i].strip().startswith("```text"))
end = next(i for i in range(fence + 1, len(lines))
if lines[i].strip() == "```")
allocatable = [line.strip() for line in lines[fence + 1:end]]
header = next(i for i, line in enumerate(allocatable) if line == "Allocatable:")
window = allocatable[header:header + 6]
print("grep -A 5 window:")
print("\n".join(window))
print("nvidia.com/gpucores shown:",
any(line.startswith("nvidia.com/gpucores:") for line in window))
print("nvidia.com/gpumem shown:",
any(line.startswith("nvidia.com/gpumem:") for line in window))
PYRepository: Project-HAMi/website Length of output: 246 🏁 Script executed: #!/bin/bash
set -eu
python3 - <<'PY'
from pathlib import Path
lines = Path("docs/get-started/local-testing-with-mock-gpu.md").read_text().splitlines()
for i, line in enumerate(lines[85:105], 86):
print(f"{i}: {line!r}")
PYRepository: Project-HAMi/website Length of output: 682 🏁 Script executed: #!/bin/bash
set -eu
python3 - <<'PY'
from pathlib import Path
lines = Path("docs/get-started/local-testing-with-mock-gpu.md").read_text().splitlines()
expected = lines.index("Expected output:")
fence = lines.index("```text", expected)
end = lines.index("```", fence + 1)
window = [line.strip() for line in lines[fence + 1:end]][:6]
print("\n".join(window))
print("gpucores shown:", any(line.startswith("nvidia.com/gpucores:") for line in window))
print("gpumem shown:", any(line.startswith("nvidia.com/gpumem:") for line in window))
PYRepository: Project-HAMi/website Length of output: 336 🏁 Script executed: #!/bin/bash
set -eu
python3 - <<'PY'
from pathlib import Path
lines = Path("docs/get-started/local-testing-with-mock-gpu.md").read_text().splitlines()
command = lines.index('kubectl describe node hami-sandbox-control-plane | grep -A 8 "Allocatable:"')
expected = next(i for i in range(command + 1, len(lines))
if lines[i].strip() == "Expected output:")
fence = next(i for i in range(expected + 1, len(lines))
if lines[i].strip() == "```text")
end = next(i for i in range(fence + 1, len(lines))
if lines[i].strip() == "```")
output = [line.strip() for line in lines[fence + 1:end]]
header = output.index("Allocatable:")
window = output[header:header + 6]
print("grep -A 5 window:")
print("\n".join(window))
print("gpucores shown:",
any(line.startswith("nvidia.com/gpucores:") for line in window))
print("gpumem shown:",
any(line.startswith("nvidia.com/gpumem:") for line in window))
PYRepository: Project-HAMi/website Length of output: 353 Use a deterministic allocatable-resource check.
Use JSONPath to print both resource values directly: kubectl get node <node-name> -o jsonpath='{.status.allocatable.nvidia\.com/gpumem}{"\n"}{.status.allocatable.nvidia\.com/gpucores}{"\n"}'🤖 Prompt for AI Agents |
||
|
|
||
| 3. Check scheduling failure reasons for `Pending` pods: | ||
|
|
||
| ```bash | ||
| kubectl get events --field-selector reason=FailedScheduling | ||
| kubectl logs -n kube-system -l app.kubernetes.io/component=hami-scheduler | ||
| ``` | ||
|
Comment on lines
+185
to
+190
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick win 🧩 Analysis chain🏁 Script executed: #!/bin/bash
set -e
printf '%s\n' '--- target documentation section ---'
sed -n '160,205p' docs/troubleshooting/troubleshooting.md
printf '%s\n' '--- related event and namespace guidance ---'
rg -n -C 3 'FailedScheduling|kubectl get events|Pending pod|namespace|hami-scheduler' docs/troubleshooting docsRepository: Project-HAMi/website Length of output: 50378 🏁 Script executed: #!/bin/bash
set -e
printf '%s\n' '--- local mock-GPU workload namespace and diagnostics ---'
sed -n '120,210p' docs/get-started/local-testing-with-mock-gpu.md
printf '%s\n' '--- kubectl availability and event command help ---'
if command -v kubectl >/dev/null 2>&1; then
kubectl version --client 2>/dev/null || true
kubectl get events --help 2>/dev/null | sed -n '1,160p'
else
printf '%s\n' 'kubectl is not installed in the sandbox'
fi
printf '%s\n' '--- read-only command-shape check ---'
python3 - <<'PY'
from pathlib import Path
text = Path("docs/troubleshooting/troubleshooting.md").read_text()
needle = "kubectl get events --field-selector reason=FailedScheduling"
assert text.count(needle) == 1, text.count(needle)
line = next(line.strip() for line in text.splitlines() if needle in line)
print({"command": line, "has_namespace_scope": "--all-namespaces" in line or " -n " in line})
PYRepository: Project-HAMi/website Length of output: 2785 🌐 Web query:
💡 Result: To view events in Kubernetes, the recommended and modern subcommand is kubectl events [1][2]. For events in the default namespace (or the namespace currently set in your context), you can simply run [2][3]: kubectl events To view events across all namespaces, use the --all-namespaces flag (or its short form -A) [1][4]: kubectl events --all-namespaces # OR kubectl events -A While the legacy command kubectl get events is still supported in many environments, kubectl events was introduced to provide a cleaner, more ergonomic interface specifically for listing event objects, including features like live-watching and simplified output [2]. When using the legacy kubectl get events command, the behavior regarding namespaces is consistent with other kubectl get commands: running it without arguments defaults to the namespace set in your current context, and appending --all-namespaces (or -A) will retrieve events from across the entire cluster [5]. References: [1] https://kubernetes.io/docs/reference/kubectl/generated/kubectl_events/ [2] https://linuxcommandlibrary.com/man/kubectl-events [3] https://www.mankier.com/1/kubectl-events [5] kubernetes/kubernetes#4796 [4] https://oneuptime.com/blog/post/2026-02-09-kubectl-events-filtering-sorting/view Citations:
Query events in the Pending pod's namespace. The command uses the current namespace and can miss events for a Pending pod in another namespace. Use 🤖 Prompt for AI Agents |
||
|
|
||
| For a complete step-by-step tutorial, see the [Local Mock GPU Testing Guide](../get-started/local-testing-with-mock-gpu.md). | ||
Uh oh!
There was an error while loading. Please reload this page.