mcpField
J
jetson-validate-image

jetson-validate-image

github.com/nvidia测试与质量3.8k1.1k 次安装今天更新
代码仓库

关于 jetson-validate-image

用于验证定制 Jetson BSP 镜像的占位 Skill,面向检查磁盘产物和已刷写设备的工程师。DUT 访问约定与 UART 辅助脚本已定义,大部分验证流程仍是框架。

主要功能

  1. 01静态 BSP 产物检查
  2. 02通过 SSH 和 UART 访问 DUT
  3. 03启动与模块一致性检查
  4. 04汇总测试结果和日志

适用场景

  1. 01刷写前检查 BSP 镜像
  2. 02验证刚刷写的 Jetson
  3. 03运行冒烟或回归检查
  4. 04在 CI 中设置定制批次门禁

安装

复制下面的命令,在终端中运行。

$npx skills add https://github.com/nvidia/skills --skill jetson-validate-image

安装后在 Claude Code 中输入/jetson-validate-image确认已加载。

包含的文件

除 SKILL.md 外,安装时一起下载的参考资料和脚本。

BENCHMARK.md
skill-card.md
skill.oms.sig
evals/
evals.json
references/
dut-access.md
scripts/
uart_session.py

详细介绍

验证 BSP 镜像

状态: DUT 访问约定已稳定;其余验证流程仍为骨架。

目的

确认刚完成定制的 BSP 已正确落地——既作为静态产物存在于磁盘上,也已在目标设备上作为运行系统启动——无需重新推广或重新刷写。本流程构成 Setup → Customize → Build → Deploy 流水线中的 Deploy 验证阶段(流水线视图请参见 ../../context/bsp-customization-workflow.md),并且可以独立重复运行。

前提条件

  • 已激活目标平台配置文件,并解析出 bsp_image:(先运行 /jetson-init-image)。
  • 对于仅静态验证范围:无需其他条件;此技能会直接读取 <bsp_image.root_path>。
  • 对于目标设备验证范围:
    • /jetson-flash-image 已将暂存的 BSP 推送到 DUT。
    • 已在激活的配置文件中编写 dut_access: 块(或在运行时交互式填写——参见 ## DUT access)。
    • 根据传输方式准备好主机工具:SSH 需要 ssh + sshpass;UART 需要 Python 3.6+ 和 pyserial。
    • 当 auth=password 或 sudo.method=password 时,主机上必须能够解析所需的环境变量(password_env / sudo.password_env 用于指定环境变量名称;切勿在 YAML 中内联机密)。

调用时机

  • 在 jetson-flash-image 已将 BSP 写入目标设备后。
  • 用户明确要求在已刷写的设备上进行验证、测试或运行冒烟/回归检查时。
  • 在宣布一批定制成果可交付前,将其用作 CI 门禁。

说明

以下流程为骨架。

  1. 读取活动目标,遵循前置条件约定。
  2. 选择验证范围——静态验证(针对磁盘上的 bsp_image,无需 DUT)和/或目标设备验证(DUT 必须从刚刷写的映像启动)。
  3. 静态检查(若在范围内):
    • 必需的工件是否存在于 <bsp_image.root_path>/Linux_for_Tegra/ 下的预期路径。
    • DTB/模块校验和或签名验证。
    • 根据每块板的 .conf 中的 XML 检查分区布局是否合理。
    • 对照 bsp_image 检查覆盖层暂存的输出(提升后两者应完全一致)。
    • Initramfs ↔ 内核 + rootfs 模块一致性。 提取 <bsp_image>/Linux_for_Tegra/bootloader/l4t_initrd.img 和 <bsp_image>/Linux_for_Tegra/rootfs/boot/initrd;根据已提升的 bsp_image 状态验证以下三项不变量: (a) <bsp_image>/Linux_for_Tegra/kernel/Image 与 <bsp_image>/Linux_for_Tegra/rootfs/boot/Image 必须逐字节一致——此处出现偏差意味着跳过了“将内核 Image 镜像到 rootfs”步骤,后续任何 initramfs 刷新都是基于先前的内核构建的。 (b) 对两个 initrd 映像中包含的每个模块路径,其字节内容/md5 必须与 <bsp_image>/Linux_for_Tegra/rootfs/lib/modules/<ver>/ 下的文件匹配——任何偏差都意味着这些模块会在早期启动时被覆盖。 (c) 每个 initramfs *.ko 上标记的 vermagic 必须与从 <bsp_image>/Linux_for_Tegra/kernel/Image 获取的 UTS_RELEASE 匹配(例如,使用 strings 解析 Linux version … 字符串)——vermagic 不匹配意味着内核 Image 已刷新,但未重新运行 l4t_update_initrd.sh,模块将无法加载,并报错“disagrees about version of symbol …”。/jetson-promote-image 对 kernel/Image 或 rootfs/lib/modules/ 以及内核 Image 镜像步骤设置的门控会排除所有这三种故障模式;若此处发现偏差,请告知用户并引导其重新执行干净的提升流程。参见 ../jetson-promote-image/SKILL.md。
  4. 目标设备检查(若在范围内):
    • 按照下方的 ## DUT access 部分连接到 DUT——根据活动配置文件的 dut_access: 块确定传输方式(ssh/uart)、凭据和 sudo 方法(若字段缺失/标记为 prompt,则交互式询问),然后运行连接探测;若失败则停止。
    • 确认已启动并进入用户空间。
    • 运行选定的测试套件(冒烟测试、回归测试、针对每项自定义配置的专项测试、临时测试)。
    • 已加载模块的 srcversion 偏差。 对于已知经自定义配置重新构建的模块,将 DUT 上的 cat /sys/module/<name>/srcversion 与 modinfo /lib/modules/$(uname -r)/.../<name>.ko | awk '/srcversion/ {print $2}' 的读取结果进行比较。不匹配意味着内核运行的是较旧副本,而 rootfs 中的是较新副本——这几乎总是因为 initramfs 过时(引导加载程序侧的 initrd 携带了自定义配置前的模块,该模块先被加载,而 rootfs 中的副本无法替换已运行的模块)。建议重新运行 /jetson-promote-image 并重新刷写。注意:有些模块不会提供 srcversion;可改为将校验值与通过提取 /sys/module/<name>/sections/ 下的区域而获得的内核已加载二进制进行核对,或通过行为进行比较(例如,新版本已知会提供的 printk、sysfs 节点或 DT 属性)。
    • 运行中的内核与 rootfs 内核 Image。 将 DUT 上的 cat /proc/version(或 uname -v)与从 /boot/Image 提取的 Linux version … 字符串(strings /boot/Image | grep -m1 'Linux version')进行比较。不匹配——通常是构建时间戳/LOCALVERSION 不同——意味着引导加载程序运行的内核 Image 比 rootfs 中的旧,这几乎可以确定是因为新 Image 已提升,但 initramfs/extlinux.conf/QSPI 启动分区未刷新。此时 rootfs 中的模块会具有不同的 vermagic,之后任何针对新内核构建的 .ko 执行 modprobe 都会失败。建议运行 /jetson-promote-image 并重新刷写。
    • 用户空间中的 dmesg 可读性。 Ubuntu 22.04 将 kernel.dmesg_restrict=1 设为默认值;非 root 用户读取 dmesg 会返回“Operation not permitted”,且命中数会被静默置零。所有基于 dmesg 的检查都必须使用 sudo 运行(或通过 sudo sysctl kernel.dmesg_restrict=0 临时降低限制)。在验证层指出这一点,可确保基于 printk 的自定义配置检查结果准确。
    • 收集结果、日志和工件。
  5. 摘要:逐项检查的通过/失败情况、总体结论,以及日志和工件的存放位置。

DUT 访问

目标设备端需要一种方式来访问刚刷写好的 DUT。 目前支持两种地位相同的传输方式:ssh(首选)和 uart(适用于没有网络的 DUT)。

相关约定已确定,但为使 SKILL.md 保持在 Agent 路由预算内, 内容存放于 references/dut-access.md。该参考文档涵盖:

  • dut_access: 配置文件架构(ssh、uart、sudo、workdir)。
  • 解析顺序(配置文件 → 环境变量 → 交互式提示),以及 完整的拒绝触发条件表。
  • 强制连接探测(uname -r + cat /etc/nv_tegra_release)及其输出验证规则。
  • 各传输方式的文件传输(scp 与通过 tty 传输 base64,并对

    100 KB 的文件发出警告)。

  • 按 sudo.method × 传输方式划分的 sudo 调用矩阵。
  • scripts/uart_session.py 遵循的 UART 实现约定(登录 / exec / push / pull 状态机、退出码、健壮性说明)。
  • 安全说明(密码处理、主机密钥固定)。

可用脚本

脚本用途参数
scripts/uart_session.py目标设备端的 UART 传输黑盒:登录、命令执行(可选 sudo)以及通过 tty 传输 base64 文件。在 DUT 没有网络或 ssh 不可用时替代 ssh。--tty <dev> [--baud <n>] --user <name> --password-env <ENVVAR> [--sudo-password-env <ENVVAR>] [--shell-prompt <regex>] [--lock-strategy refuse|wait] <probe|exec|push|pull> [...]

调用方式(该技能将脚本作为子进程调用——在 Agent 运行时术语中为 run_script()):

# run_script: probe the DUT over UART
DUT_UART_PASSWORD_ENV=DUT_UART_PWD \
DUT_UART_PWD="$(read -rs -p 'UART login pw: '; echo "$REPLY")" \
  scripts/uart_session.py \
    --tty /dev/ttyACM0 --baud 115200 \
    --user ubuntu --password-env DUT_UART_PASSWORD_ENV \
    probe

# run_script: exec a sudo command and capture exit code
scripts/uart_session.py --tty /dev/ttyACM0 --user ubuntu \
  --password-env DUT_UART_PASSWORD_ENV \
  --sudo-password-env DUT_SUDO_PWD \
  exec --use-sudo 'dmesg | tail -200'

脚本的退出码即为约定内容——请参阅 UART implementation contract 中的退出码表。

示例

仅静态验证(无需 DUT):

/jetson-validate-image
> static checks only against the staged BSP

刚刷写完 DUT 后通过 SSH 进行目标设备端验证:

/jetson-flash-image
   ↓
/jetson-validate-image
> on-target checks via dut_access.ssh

通过 UART 进行目标设备端验证(DUT 无网络):

/jetson-validate-image
> use the uart transport at /dev/ttyACM0; the dut_access.uart block
  in the profile already has the tty and login_password_env wired up

限制

  • 占位技能——目前仅确定了 DUT 访问约定和 uart_session.py 辅助脚本。静态检查列表、 测试套件选择、结果接收端布局和通过 / 失败策略 均在 ## Open items 下跟踪,且可能变更。
  • UART 文件传输通过逐字节发送 base64 实现,波特率为 115200 时速率约为 10 KB/s——源文件大于 100 KB 时会发出警告,但仍会继续传输。对于 大批量传输,请切换到 SSH 传输方式。
  • uart_session.py 在每次子命令调用时都会打开并关闭 tty (每次登录约需 1–2 s)。验证过程若通过 UART 运行超过 10 条 命令,则耗时较长;建议使用 SSH。
  • SSH 使用 StrictHostKeyChecking=accept-new,并为每个配置文件使用单独的 known_hosts 文件。指纹变更时会拒绝连接——通常表示 DUT 已重新刷写(主机密钥已重新生成)或 IP 已重新分配。请手动移除对应配置文件中的条目, 不要自动接受。
  • 密码不会直接写入配置文件 YAML——只会持久化 password_env(环境变量名)。auth=prompt / sudo.method=prompt 会让密码出现在对话日志中, 用户需自行负责管理。
  • transport=uart 搭配 lock_strategy=steal 尚未实现 (需要发送控制字符,可能会破坏占用者的状态)。

故障排除

错误原因解决方案
no DUT transport configured(拒绝)请求了目标设备范围,但在配置文件/环境变量/交互式提示中均未解析出 dut_access.transport在活动配置文件中编写 dut_access:,或重新运行并仅指定静态范围。
$PASSWORD_ENV is unset(拒绝)auth=password(或 sudo.method=password)指定的环境变量未在主机上导出调用此技能前运行 export <ENVVAR>=...;切勿将密码直接写入 YAML。
tty held by another process(拒绝,退出码 3)lock_strategy=refuse,且 fuser 检测到另一个占用进程(minicom、picocom、getty)关闭占用进程(只有在确认进程内容后才运行 sudo fuser -k <tty>),或使用 lock_strategy=wait 重新运行。
pyserial import failed(退出码 4)已选择 UART 传输,但此技能的 Python 环境未安装 pyserial运行 apt install python3-serial 或 pip install pyserial。
SSH 指纹被拒绝DUT 的主机密钥自按配置文件固定 known_hosts 后发生了变化(通常是重新刷写所致)从 <workspace>/target-platform/<profile-stem>.known_hosts 中删除匹配行并重新运行;首次连接时将接受新密钥。
login failed(退出码 128)UART 探测在超时时间内未能匹配登录提示符或 shell 提示符确认 DUT 已通电并启动至用户空间;如果 DUT 使用了不同寻常的 PS1,检查 --shell-prompt 覆盖项;确认 --user 对应真实账户。
DUT not booted from the just-flashed BSP(警告/拒绝)DUT 上的 /etc/nv_tegra_release 与 bsp_image.version 不匹配重新运行 /jetson-flash-image,并确认 DUT 确实已断电重启并进入新的 BSP,而不是之前的版本。
sudo prompt detected but no sudo password configured(退出码 130)将 --use-sudo 传给 uart_session.py exec,但未设置 --sudo-password-env,且 DUT 用户没有 NOPASSWD 权限在配置文件中设置 sudo.method=password 和 sudo.password_env,或通过 DUT 上的 /etc/sudoers.d/ 授予 NOPASSWD 权限。
command timed out(退出码 129)长时间运行的 DUT 命令超出了脚本的超时时间直接通过 ssh 传输方式运行命令,或将命令拆分为较短步骤。

参考资料

评论

支持 Markdown