jetson-validate-image について
カスタマイズ済み Jetson BSP イメージを検証するためのプレースホルダー型スキルです。ディスク上の成果物やフラッシュ直後のデバイスを確認するエンジニア向けで、DUT のアクセス仕様と UART ヘルパー以外の手順は未完成です。
主な機能
- 01BSP 成果物の静的チェック
- 02SSH と UART による DUT 接続
- 03起動状態とモジュールの整合性確認
- 04テスト結果とログの集約
活用シーン
- 01フラッシュ前の BSP イメージ確認
- 02フラッシュ直後の Jetson の検証
- 03スモークテストや回帰テストの実行
- 04CI でカスタマイズ成果を判定
インストール
コマンドをコピーしてターミナルで実行します。
npx skills add https:/ / github.com/ nvidia/ skills --skill jetson-validate-imageインストール後、Claude Code で/jetson-validate-imageを入力して読み込まれたか確認します。
同梱ファイル
SKILL.md と一緒にインストールされる参考資料やスクリプト。
BENCHMARK.mdskill-card.mdskill.oms.sigevals/evals.jsonreferences/dut-access.mdscripts/uart_session.py詳細
BSP イメージの検証
ステータス: DUT へのアクセス契約は安定していますが、検証手順の残りの部分は骨組みです。
目的
新たにカスタマイズした BSP が正しく適用されたことを、ディスク上の静的な成果物として、またターゲット上の実行中のシステムとして確認します。再プロモートや再フラッシュは行いません。Setup → Customize → Build → Deploy パイプライン(パイプラインの概要については
../../context/bsp-customization-workflow.md
を参照)の Deploy の検証工程を担い、個別に再実行できます。
前提条件
bsp_image:が解決済みの、アクティブなターゲットプラットフォームプロファイル(最初に/jetson-init-imageを実行してください)。- 静的な検証のみの場合:追加の要件はありません。このスキルは
<bsp_image.root_path>を直接読み取ります。 - ターゲット上で検証する場合:
/jetson-flash-imageによって、ステージング済みの BSP がすでに DUT に書き込まれていること。- アクティブなプロファイルに
dut_access:ブロックが記述されていること(または実行時に対話形式で入力すること。詳細は## DUT accessを参照)。 - トランスポートに応じたホストツール:SSH の場合は
sshとsshpass、UART の場合はpyserialを使用できる Python 3.6 以降。 auth=passwordまたはsudo.method=passwordの場合、必要な環境変数をホスト上で解決できること(password_env/sudo.password_envには環境変数名を指定してください。シークレットを YAML に直接記述しないでください)。
実行するタイミング
jetson-flash-imageで BSP をターゲットに書き込んだ後。- ユーザーから、フラッシュ済みデバイスの検証、テスト、スモークテスト/回帰チェックの実行を明示的に依頼されたとき。
- カスタマイズ一式を出荷可能と判断する前の CI ゲートとして。
手順
以下の手順は骨組みです。
- 前提条件の契約に従って、アクティブなターゲットを読み取ります。
- 検証範囲を選択します — 静的検証(ディスク上の
bsp_imageを対象とし、DUT は不要)および/またはターゲット上での検証(DUT はフラッシュ直後のイメージから起動している必要があります)。 - 静的チェック(範囲に含まれる場合):
- 想定されるパス
<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の状態に対して次の 3 つの不変条件を検証します。 (a)<bsp_image>/Linux_for_Tegra/kernel/Imageと<bsp_image>/Linux_for_Tegra/rootfs/boot/Imageがバイト単位で一致すること。この不一致は、「カーネル Image を rootfs にミラーする」手順が省略され、その後の initramfs の更新が以前のカーネルに対して行われたことを意味します。 (b) 2 つの 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 の不一致は、l4t_update_initrd.shを再実行せずにカーネルImageを更新したことを意味し、モジュールの読み込み時に「disagrees about version of symbol …」というエラーが発生します。3 つの失敗モードはいずれも、/jetson-promote-imageのkernel/Imageまたはrootfs/lib/modules/とカーネル Image のミラーを対象とするゲートで防止されます。ここで不一致を明らかにし、ユーザーにクリーンな昇格を再実行するよう案内してください。詳しくは../jetson-promote-image/SKILL.mdを参照してください。
- 想定されるパス
- ターゲット上のチェック(範囲に含まれる場合):
- 以下の
## 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/以下の領域を抽出してカーネルがロードしたバイナリと md5 を照合するか、振る舞い(printk、sysfs ノード、新バージョンで公開されることが判明している DT プロパティ)で比較してください。 - 実行中のカーネルと rootfs のカーネル
Image。 DUT 上のcat /proc/version(またはuname -v)と、/boot/Imageから抽出したLinux version …文字列(strings /boot/Image | grep -m1 'Linux version')を比較します。不一致は、通常、ビルド時刻またはLOCALVERSIONの違いを示します。これは、ブートローダーが rootfs にあるものより古いカーネルImageを実行していることを意味し、ほぼ確実に、新しい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」を返し、ヒット数が暗黙に 0 になります。dmesgに基づくすべてのチェックはsudoを使用して実行する必要があります(またはsudo sysctl kernel.dmesg_restrict=0で一時的に制限を緩和してください)。この点を検証レイヤーで明示することで、printkに基づくカスタマイズチェックの信頼性を保てます。 - 結果、ログ、アーティファクトを収集します。
- 以下の
- 概要:チェックごとの合否、全体の判定、ログとアーティファクトの保存先。
DUT アクセス
オンターゲット側では、フラッシュ直後の DUT にアクセスする方法が必要です。
完全に対等なトランスポートとして、ssh(優先)と
uart(ネットワークのない DUT 向けのフォールバック)をサポートしています。
契約は確定していますが、この
SKILL.md がエージェントルーティングの予算を超えないよう、
references/dut-access.md に記載されています。このリファレンスでは、以下を扱います。
dut_access:プロファイルのスキーマ(ssh、uart、sudo、workdir)。- 解決順序(プロファイル → 環境変数 → 対話型プロンプト)と、 拒否条件を網羅した表。
- 必須の接続プローブ(
uname -r+cat /etc/nv_tegra_release)とその出力検証ルール。 - トランスポートごとのファイル転送(
scpと base64-over-tty、および100 KB の警告)。
sudo.method× トランスポートごとの sudo 呼び出しマトリックス。scripts/uart_session.pyが遵守する UART 実装契約 (login / exec / push / pull のステートマシン、終了コード、堅牢性に関する注意点)。- セキュリティに関する注意点(パスワードの取り扱い、ホストキーのピン留め)。
利用可能なスクリプト
| スクリプト | 用途 | 引数 |
|---|---|---|
scripts/uart_session.py | オンターゲット側の UART トランスポートのブラックボックス:login、コマンド実行(sudo は任意)、base64-over-tty によるファイル転送。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> [...] |
呼び出し(スキルはサブプロセスとしてスクリプトを呼び出します — エージェントランタイムの用語では
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
DUT にネットワークがない場合の UART 経由のオンターゲット検証:
/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 ファイル転送は 115200 baud で約 10 KB/s のビットバンギングによる base64 転送です — 100 KB を超えるソースには警告を出しますが、転送は続行します。 大容量の転送には SSH トランスポートに切り替えてください。
uart_session.pyはサブコマンドの呼び出しごとに tty を開閉します (呼び出しごとにログインに約 1~2 秒かかります)。10 個を超えるコマンドを実行する検証パスでは UART の効率が大幅に低下するため、SSH を推奨します。- SSH はプロファイルごとの
known_hostsファイルを使用し、StrictHostKeyChecking=accept-newを設定します。フィンガープリントが変更されると拒否されます — 通常、DUT の再フラッシュ(ホストキーの再生成)または IP の再割り当てを意味します。自動的に受け入れるのではなく、プロファイルごとのエントリを手動で削除してください。 - パスワードをプロファイル YAML に直接記述することはありません — 保存されるのは
password_env(環境変数名)のみです。auth=prompt/sudo.method=promptでは会話ログにパスワードが表示されます。管理はユーザーの責任です。 lock_strategy=stealを指定したtransport=uartは 実装されていません (ロック保持者の状態を破損させる可能性がある制御文字を送信する必要があるためです)。
トラブルシューティング
| エラー | 原因 | 解決方法 |
|---|---|---|
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 フィンガープリントが拒否されました | プロファイルごとに固定された known_hosts の設定後に、DUT のホストキーが変更されました(通常は再フラッシュが原因です) | <workspace>/target-platform/<profile-stem>.known_hosts から該当する行を削除して再実行してください。次回の接続時に新しいキーが受け入れられます。 |
login failed (終了コード 128) | UART プローブが、タイムアウトまでにログインプロンプトまたはシェルプロンプトを認識できませんでした | 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 ではなく、新しい BSP で実際に電源再投入されて起動したことを確認してください。 |
sudo prompt detected but no sudo password configured (終了コード 130) | uart_session.py exec に --use-sudo が渡されましたが、--sudo-password-env が設定されておらず、DUT ユーザーにも NOPASSWD がありません | プロファイルで sudo.method=password と sudo.password_env を設定するか、/etc/sudoers.d/ を通じて DUT に NOPASSWD を設定してください。 |
command timed out (終了コード 129) | 実行時間の長い DUT コマンドがスクリプトのタイムアウトを超えました | ssh トランスポートを使ってコマンドを直接実行するか、短い手順に分割してください。 |
参考資料
references/dut-access.md— DUT アクセスの契約全体:プロファイルスキーマ、解決順序、プローブ、ファイル転送、sudo、UART の実装、セキュリティ。../../context/target-platform-contract.md— ターゲットプラットフォームの契約。../../context/bsp-customization-workflow.md— ワークスペースの編集プロトコル(このスキルはデプロイの最後の工程です)。../jetson-build-source/SKILL.md— ビルドビルダー。このスキルが検証する成果物を生成します。