Repository navigation
feat(can-tools): setup/rename lib refactor + install.sh + tests (A2) - #13
Conversation
…ts (PR-A2) This commit implements Issue #9 PR-A2: 1. **Setup/rename scripts refactored to use can_tools_lib**: - canhat_fd_setup.bash and canhat_fd_rename.bash now source can_tools_lib - canhat_plus_setup.bash and canhat_plus_rename.bash (with CAN FD disabled) - Scripts use can_read_conf, can_setup_iface, and can_pin_name functions - Removed direct sudo calls (sudo is inside lib functions) - Maintains existing behavior: can0=spi0.0, can1=spi1.0, txqueuelen 10 2. **install.sh - Idempotent installation script**: - Installs files to /opt/can_tools (no --delete in rsync) - Preserves existing configuration files - Copies unit files to /etc/systemd/system (no symlinks) - Supports CHECK_MODE for diff preview - Environment variables for testing: INSTALL_OPT_DIR, SYSTEMD_DIR - Does not restart active services (down/up issue per Issue #9) 3. **README.md - Updated Installation/Configuration sections**: - New quick install instructions - Configuration file management - Systemd service setup for CAN HAT FD and Plus - Check mode usage example 4. **Tests added**: - test_install_idempotent.sh: Validates install.sh structure and features - test_setup_lib_usage.sh: Verifies setup/rename scripts use lib correctly All tests pass: bash tests/run.sh -> 6 passed, 0 failed All shell scripts pass syntax check: bash -n <script> Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
- Add shellcheck disable directives for SC2155 (readonly with command substitution) - Add shellcheck source directives for SC1090 (source with variable path) - All scripts now pass: shellcheck -S warning Co-Authored-By: Claude Haiku 4.5 <noreply@anthropic.com>
RyodoTanaka
left a comment
There was a problem hiding this comment.
PR-A2 レビュー(Opus、6a9a654、Issue #9 改訂 4 と照合)
判定: 要修正(クリティカル 2、高 5、中 6、低 4)
確認の方法: gh pr diff 13 を読んだ。そのうえで、偽の ip と偽の sysfs を使い、install.sh、canhat_fd_rename.bash、canhat_fd_setup.bash、enable_canhat_*.sh を実際に動かした(systemctl も偽物に差し替えた)。機上(192.168.0.240)の /opt/can_tools と /etc/systemd/system は読み取りだけで見比べた。shellcheck の SC2155/SC1090 は依頼済みなので、ここでは挙げない。
良い点: install.sh は稼働中のサービスを restart しない。ip も呼ばないので、機上で走らせても CAN を down/up しない。--delete も無い。conf があれば上書きしない(2 回目以降は SKIP)。初回に置く conf は example の写しで、全行がコメントなので「空(コメントのみ)」の要件を満たす。setup と rename は lib の呼び出し規則($( )・< <( )・パイプの中で呼ばない)を守っている。txqueuelen 10、restart-ms 100、fd on は保たれている。
クリティカル
C1. rename に swap が無い。probe の順が入れ替わった起動では can0/can1 が入れ替わったまま残る(#7・§2b に反する)
§2b は「can_pin_name が 2(入れ替わり)を返したときだけ、両方を down して一時名経由で swap。2 つ揃うまで最大 10 s 待つ。can_lock を取る」と決めている。機上の canhat_fd_rename.sh(#7)も、spi_of can0 == spi1.0 のときに can_swap 経由で入れ替えている。機上の注記にあるとおり、この入れ替わりは「起動ごとの probe の順」で実際に起きる。
本 PR の rename は 2 を単なる失敗として扱う。再現(spi0.0→can1、spi1.0→can0 の偽 sysfs):
ERROR: Failed to rename spi device spi0.0 to can0
ERROR: Failed to rename spi device spi1.0 to can1
rc=1 # ip は link show can0 / can1 しか呼ばれず、名前は入れ替わったまま
この結果、送信アプリが spi1.0 側の can0 で送ることになる。加えて rename.service が毎回 failed になる。ほかにも次の 2 点が抜けている: can_lock を取っていない(コメントに "can_pin_name takes lock internally" とあるが、lib の can_pin_name はロックを取らない)、両 iface が出るまで最大 10 s 待つ処理。
→ §2b のとおり、can_lock → 両方が出るまで待つ(≤10 s)→ can_pin_name → rc 2 のときだけ両方を down して一時名で swap → can_unlock、の順に実装すること。試験は「入れ替わり状態から swap して can0=spi0.0 になる」「すでに正しい名前なら ip link set を呼ばない」「片方しか無い」を、偽の ip・sysfs で実行して確かめること。
C2. unit の変更が diff に無い。そのため install.sh が機上の rename unit を退行版で上書きし、Before=docker.service が消える
§6 の A2 欄で、canhat_fd_rename.service(Before=canhat_fd_setup.service docker.service、機上版を採用)と canhat_fd_setup.service(After=canhat_fd_rename.service)は A2 の担当になっている。本 PR はどちらも変えていない。repo の rename unit は Before=canhat_fd_setup.service だけである。
機上の /etc/systemd/system/canhat_fd_rename.service は実ファイルで、Before=canhat_fd_setup.service docker.service を持つ。install.sh は内容の差分を見て、これを repo 版で上書きする。その結果、docker(コンテナが can0 を開く)が rename より先に起動し得る。これは #7 で塞いだ順序の問題を再び開くことになる。
→ 2 つの unit を §6 のとおり直すこと(rename: Before=canhat_fd_setup.service docker.service、setup: After=canhat_fd_rename.service)。試験は、ファイルの中身を検査して依存を確かめること。PR-B の watchdog unit が使う Wants+After と BindsTo 禁止もこの順序に依存するので、ここで固めておく必要がある。
高
H1. --check が仕様どおり動かない。CHECK_MODE の判定も逆になっている
-
§4 は
install.sh --checkを引数として定めているが、install.sh は"$@"を見ていない。運用者がsudo ./install.sh --checkと打つと実際にインストールが走る(空のディレクトリで確認すると、ファイルと unit が全部コピーされた)。 -
_install_fileと_install_confは、check モードで差分があると 1、差分が無いと 0 を返す。呼び出し側のif _install_file ...; then diff_found=1は、この意味を逆に受け取っている。実測:- インストール直後に
CHECK_MODE=1→Check mode: differences found、rc=1(正しくは差分なし) - 空のディレクトリに
CHECK_MODE=1→Check mode: no differences、rc=0(正しくは差分あり)
受け入れ基準 5c-1(「2 回実行で
--checkが空」)を判定できない。 - インストール直後に
-
§4 は diff の表示を求めているが、出るのは "Would install" だけ。
→--checkを引数として解釈すること(環境変数は残してもよい)。戻り値の意味を「変更があった/ありそう = 1」のように 1 つに揃え、diff -uを出すこと。
H2. can_monitor.* を廃止せず、install し、README で enable まで勧めている(§4-4 に反する)
§4-4 は、can_monitor.timer と .service を stop・disable し、リンクと /opt/can_tools/can_monitor.* を削除すると定めている(/var/log/can_monitor.log は残す)。本 PR の install.sh はその逆で、can_monitor.sh と can_monitor.service を install し、timer はログを出すだけにしている。README には「CAN Monitor Service (optional) sudo systemctl enable can_monitor.service / start」と書いてある。can_monitor は今回の障害の引き金である(§背景 2)。手順書がそれを有効にするよう案内するのは危険である。
→ install.sh に §4-4 の処理を入れること(無ければ何もしない、冪等)。can_monitor を install 対象から外し、README の can_monitor 節を削除すること。
H3. canhat_fd_setup.bash が引数を無視して全 iface を down/up する。enable_canhat_fd.sh も未対応
§2b は「canhat_fd_setup.bash は can_read_conf → can_setup_iface "$1" を呼ぶだけ。enable_canhat_fd.sh が CAN_IFACES を回す」と決めている。本 PR の setup は $1 を見ずに CAN_IFACES を全部回す。実測: canhat_fd_setup.bash can0 250000 を実行すると can1 も down/up された。can0 だけ直すつもりの手動操作が、受信側の can1 まで落とす。全 iface の down/up は今回の引き金である。
enable_canhat_fd.sh は変更されておらず、exit を含むスクリプトを 2 回 source している。1 回目の source の中の exit で enable 自体が終わるので、たまたま 1 回ずつで済んでいるだけである。
→ setup は $1(必須)だけを処理し、source されても exit しない形(または source をやめて実行する形)にすること。enable は CAN_IFACES を回すこと。
H4. canhat_plus_* を範囲外で変えて壊している(§2b「canhat_plus_* は本 Issue の対象外(動作は変えない)」)
canhat_plus_setup.bashのexport CAN_FD="off"は効かない。直後のcan_read_confが_can_set_defaultsでCAN_FD=onに戻すためである。実測:enable_canhat_plus.shでdbitrate 2000000 fd onが発行された。CAN HAT+(MCP2515、FD 非対応)では up 自体が失敗する。- restart-ms 1000 → 100、txqueuelen 65536 → 10 と、動作も変わっている。
canhat_plus_rename.bashは lib 既定のCAN_SPI_MAP=spi0.0:can0 spi1.0:can1を使う。HAT+ の spi1.1/spi1.2 には一致せず、必ず失敗する(コメントは spi1.1/spi1.2 のままである)。- plus の unit も install 対象になっている。
→ canhat_plus_* の変更は全部取り消すこと(PR-C の shellcheck 修正の範囲である)。install 対象からも外すか、今のファイルをそのまま配る扱いにすること。
H5. 試験が grep だけで、何も実行していない(弱い試験)
test_install_idempotent.sh は、名前に反して install.sh を一度も実行しない。grep -q CHECK_MODE、grep "Configuration exists, not overwriting" などの文字列検査だけである。H1 の逆転も、--check で install が走ることも、conf の保護も検出できない。test_setup_lib_usage.sh も「source」「can_pin_name」という文字列があるかどうかしか見ていない。そのため C1、H3、H4 は全部通ってしまう。
→ 偽物(A1 の tests/fakes/)と INSTALL_OPT_DIR・SYSTEMD_DIR・一時ディレクトリを使って、実際に動かす試験に置き換えること。最低限、次を確かめる:
- install の 2 回目で変更が 0 になり、
--checkが rc 0 で空になる - 空の配置先で
--checkが rc 非 0 になり、何も作られない - 既存の conf が上書きされない
- 既存のリンク unit が実ファイルに置き換わる
- can_monitor が消える
- systemctl の呼び出しに restart/stop が無い(
CAN_TOOLS_SYSTEMCTL_CMDの偽物の calls.log で見る) - rename の swap、正しい名前のとき何もしない、片方だけのとき
- setup
can0が can1 の ip を呼ばない - setup の ip 引数(restart-ms 100・fd on・txqueuelen 10)
中
M1. リンク unit をコピーに置き換えていない(§4-3)
機上の canhat_fd_setup.service と can_monitor.service は、/opt/can_tools/*.service へのシンボリックリンクである。cp src dst はリンクをたどるので、書き込み先は /opt 側になり、リンクはリンクのまま残る(偽の配置先で確認した)。
→ dst がシンボリックリンクなら、enable の状態を記録する → systemctl disable(--now は付けない。止めない)→ リンクを消す → コピー → daemon-reload → 記録どおり enable する。この順で行うこと。どの操作も稼働中のサービスを stop/restart しないことを試験で確かめること。
M2. unit を enable していない(§4-3「daemon-reload → enable」)
新しい機体では enable が README の手作業任せになる。daemon-reload は unit ごとに最大 5 回呼ばれているが、最後に 1 回でよい。
M3. tmpfiles.d/can_tools.conf、/run/can_tools、/var/lib/can_tools が無い(§4-5、§6 の A2 欄)
M4. systemctl を差し替えられず、root で実行しているかも確かめていない
systemctl daemon-reload 2>/dev/null || true はホストの systemctl を直接呼んでいる。§2b の CAN_TOOLS_SYSTEMCTL_CMD を使うこと。失敗を握りつぶさないこと。root でなければ止めること(試験用に配置先を差し替えたときは除く)。
M5. README が稼働中の setup 起動を案内している
sudo systemctl start canhat_fd_rename.service canhat_fd_setup.service が注意書きなしで載っている。§0 と §4-7 では、設定の反映は「再起動時、または機械停止中の setup の restart」だけである。この旨を明記すること。install.sh の最後の案内(§4-7)も無い。
M6. can_tools.conf.example を /opt に置いていない(§4-2「常に更新」)。conf の root:root 0644 も強制していない
README は /opt/can_tools/can_tools.conf.example を参照しているが、そのファイルは配られない。README の sudo cp ...example ... can_tools.conf は、既存の conf を上書きする手順にもなっている。install.sh がすでに作っているので、この手順は削除すること。
低
- L1. README の
CAN_BITRATEの説明が「kbps」になっているが、実際は bps(250000)である。 - L2. README から
git clone --recursiveの手順が消え、cd can_toolsから始まっている。 - L3. 初回 install で setup の動作が
berr-reporting on → offに変わる。§2a の lib 既定どおりで問題は無いが、反映されるのは再起動後なので、README か install の最後の案内で触れておくとよい。 - L4. rename が失敗すると exit 1 になり、unit は failed になる。C1 を直したあとも、片方の iface が無いときに起動を止めない扱い(WARNING を出して 0 で抜けるのか、failed にするのか)を決めて、コメントに書くこと。
範囲外の変更
canhat_plus_*(H4)、plus の unit と can_monitor の install(H2・H4)は範囲外である。A2 で触るべきなのは §6 の A2 欄のファイルだけである。
直したあとの再レビュー
差分だけを見る。重点は C1、C2、H1〜H5 で、実際に動かす試験が加わっているかを確認する。
…/units, revert canhat_plus Addresses PR-A2 review (pullrequestreview-5527223074) against Issue #9 rev4 §2b/§4/§6: - C1: canhat_fd_rename.bash now actually implements the §2b swap contract (can_lock, wait <=10s for both spidevs via can_iface_of_spidev, can_pin_name, swap via a temporary name only on rc=2). The previous draft used top-level `local` outside a function and called can_pin_name with an empty name expecting it to echo the current name (it never did), so it always failed instead of swapping. - C2: canhat_fd_rename.service/canhat_fd_setup.service keep the Before=...docker.service / After=canhat_fd_rename.service ordering from the prior uncommitted fix-up. - H1: install.sh now parses --check as an argument, fixes the inverted _install_file/_install_conf return convention, and prints a real `diff -u` for changed files. - H2: can_monitor is never installed; a pre-existing can_monitor.timer/.service (unit + /opt files) is stopped, disabled and removed (log file left alone). README's can_monitor section is gone. - H3: canhat_fd_setup.bash only touches "$1"; enable_canhat_fd.sh loops CAN_IFACES and execs (not sources) the setup script per interface, so a manual `canhat_fd_setup.bash can0` never touches can1. - H4: canhat_plus_setup.bash/canhat_plus_rename.bash reverted to the develop versions (A2 must not change their behavior). - H5: test_install_idempotent.sh and test_setup_lib_usage.sh now actually exec install.sh / canhat_fd_rename.bash / canhat_fd_setup.bash / enable_canhat_fd.sh against tests/fakes + scratch directories, instead of grepping source for keywords. - M1-M6: unit install replaces a legacy symlink-into-/opt deployment with a real copy; daemon-reload/enable happen once, not per unit, and go through CAN_TOOLS_SYSTEMCTL_CMD; can_tools.conf.example is now installed under /opt and refreshed every run; conf ownership/mode is enforced; /run/can_tools + /var/lib/can_tools are created directly plus a tmpfiles.d drop-in (can_tools.tmpfiles.conf); README documents that config changes need a reboot or a machine-stopped `systemctl restart canhat_fd_setup.service`. - L1/L2: README bitrate unit corrected to bps; `git clone --recursive` step restored. - L4: documented and implemented the policy for a missing interface after the 10s wait (WARNING, exit 0) vs. an actual swap failure (ERROR, exit 1). Also removes this worktree's leftover scratch files (COMMIT_MSG.txt, PR_BODY.md, SHELLCHECK_FIX_MSG.txt, canhat_plus_setup.bash.orig, tests/run_output.txt) and defensively defines CAN_TOOLS_FAKE_TIME_FILE before canhat_fd_rename.bash's first can_now() call, since can_now() reads it without a safe default and this script runs under `set -u`. can_tools_lib.bash and tests/fakes/ are untouched, per the PR-A1/A2 contract boundary. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
|
対応しました(6c458a4、feat/can-tools-a2-install に push 済み)。 クリティカルC1(rename の swap): C2(unit の依存): 前任の未コミット分がすでに直していたので検証のみ: 高H1(--check / 戻り値の逆転): H2(can_monitor): install.sh は can_monitor.* を一切 install せず、 H3(setup が全 iface を down/up): H4(canhat_plus_ の範囲外変更)*: H5(試験が grep だけ): 中M1(リンク unit): dst がシンボリックリンクなら M2(enable していない/daemon-reload 複数回): daemon-reload は全体で1回だけ呼ぶようにし、install.sh が管理する unit(canhat_fd_, canhat_plus_, 存在すれば can_watchdog)を毎回 enable するようにしました。 M3(tmpfiles.d / /run/can_tools / /var/lib/can_tools): M4(systemctl の差し替え・root チェック): M5(README の案内): 「設定反映は再起動、または機械停止中の M6(conf.example / 上書き手順): 低
確認事項・残課題(lib/tests/fakes には触れていません)
スコープ外として触っていないもの
|
RyodoTanaka
left a comment
There was a problem hiding this comment.
PR-A2 再レビュー(Opus、6c458a4。差分は 3367758..6c458a4、途中で develop c63da4d をマージ)
判定: 要修正(新規のクリティカル 1、中 2、低 4)
前回の指摘はほぼすべて解消されている。ただし、H4 の対応で plus の unit を「配る」から「enable する」に変えたため、FD 機に新しいクリティカルが生じた。
確かめ方: 前回と同じ偽の環境で実際に動かした。偽の systemctl(CAN_TOOLS_SYSTEMCTL_CMD)と、tests/fakes/ip・偽の sysfs を使った。install.sh は機上を模した配置先に対して実行した。配置先には、setup と can_monitor の unit を /opt へのリンクとして、rename の unit を実ファイルとして置き、can_tools.conf も既存のものを置いた。rename・setup・enable は env -u CAN_TOOLS_FAKE_TIME_FILE で実行した。origin/develop...6c458a4 の差分を見ると、can_tools_lib.bash・tests/fakes/・canhat_plus_* の変更は含まれていない(契約どおり)。
前回指摘の確認
| # | 結果 | 確認内容 |
|---|---|---|
| C1 swap | 解消 | 偽 sysfs で入れ替わった状態から実行すると、一時名を経由した swap は 1 回だけで rc=0。名前が正しい状態では link set が 0 回。片方の spidev が無いと、約 10 s 待ってから WARNING を出し rc=0。can_lock・can_unlock を取っている。can_pin_name は $( ) の外で呼んでいる |
| C2 unit の依存 | 解消 | rename は Before=canhat_fd_setup.service docker.service、setup は After=… canhat_fd_rename.service と Wants=(Requires と BindsTo は無い) |
H1 --check |
解消 | 引数を解釈する。実行前の --check は rc=1 で diff を表示し、何も作らない(/run も作らない)。install 後の --check は rc=0 で「no differences」 |
| H2 can_monitor | 解消(M-new2 を参照) | リンク unit・/opt 側の実体・timer をすべて削除する。can_monitor を install しない。README からも削除されている |
H3 setup の $1 |
解消 | canhat_fd_setup.bash can0 では can0 だけ操作し、引数が無いと usage を出して rc=1。enable は subprocess で can0 と can1 を 1 回ずつ処理し、ip が失敗すると rc=1。ロックは残らない |
| H4 plus の範囲外変更 | スクリプトは develop と一致して解消。ただし C-new1 を参照 | |
| H5 試験 | 解消 | 実際に動かす試験になった。swap の試験は tests/fakes/ip による sysfs の rename に依存し、env -i で実行するので、can_now の unbound の回帰も検出できる |
| M1 リンク unit | 解消 | disable(--now なし)→ リンクを消す → コピー → 1 回の daemon-reload → enable。stop・restart・start は呼ばない |
| M2 / M3 / M4 / M5 / M6 | 解消 | enable を追加。tmpfiles.d と run・state のディレクトリを作る。systemctl を差し替え可能にした。root を確認する。README と最後の案内に「機械停止中のみ」を明記した。example を配る。conf を 0644・root にする(既存の CAN_FD=off が保たれることも確認) |
| L1〜L4 | 解消 | L4 の方針はコメントに明記された(ただし L-new2 を参照) |
クリティカル(新規)
C-new1. install.sh がすべての機体で canhat_plus_setup.service と canhat_plus_rename.service を enable する。そのため FD 機では、次の起動で txqueuelen 65536 と restart-ms 1000 が can0/can1 にかかり得る
実測では、install すると enable canhat_plus_rename.service・enable canhat_plus_setup.service が呼ばれた。機上(.240)には plus の unit が無く、enable もされていない(systemctl is-enabled canhat_plus_setup.service → No such file)。
install 後に再起動すると、plus_setup(develop 版の enable_canhat_plus.sh)が ip link set can0/can1 down → up type can bitrate 250000 restart-ms 1000 → txqueuelen 65536 を実行する。この unit は After=network.target しか持たず、FD の setup・rename とは順序もロックも共有しない。結果として次のことが起き得る:
- 起動順によっては、FD の設定(txqueuelen 10、restart-ms 100)が上書きされる。txqueuelen 10 は 2026-10-09 の対策であり、それが元に戻ってしまう。
- 2 つの setup が並行して down/up する。
plus_rename は spi1.1/1.2 が無ければ exit 0 なので、こちらは無害である。
§4-3 が install・enable の対象として挙げているのは canhat_fd_rename・canhat_fd_setup・(存在すれば)can_watchdog だけである。§2b では plus は「対象外(動作を変えない)」となっている。
→ 修正: plus の unit は install・enable の対象から外すこと。HAT+ の機体向けには、手作業の手順か --plus のような明示的な指定を用意すること。試験には「systemctl の calls.log に enable canhat_plus_* が無い」ことを加えること。今の README の「canhat_fd_* / canhat_plus_* units … enables them」も直すこと。
中
M-new1. can_pin_name が set -u の呼び出し元で unbound により落ちる(lib 側の問題)
/sys/bus/spi/devices/<spidev>/net/ は存在するが中が空、という状態で rename を実行すると、can_tools_lib.bash: line 447: current: unbound variable で rc=1 になった。L4 の「WARNING を出して 0」の方針から外れる。原因は lib の local current に初期値が無いことである。if で包んでも set -u は抑止されない。
実機で起きる場面は少ない(netdev の登録と解除の途中)ので、A2 側で回避する必要は無い。下の lib の追補 PR に含めること。
M-new2. can_monitor の service を systemctl stop すると、iface が down のまま残り得る
timer が動いている旧機体では、can_monitor.service(oneshot)が実行中の可能性がある。can_monitor は ip link set down; sleep 0.5; up を実行するので、その間に stop の SIGTERM が届くと、iface は down のまま残る。今の順序(先に timer を止める)は正しい。そのうえで、service には stop を送らずに、systemctl is-active が inactive になるまで待ってから(上限は例えば 15 s)disable して消す方が安全である。.240 は timer が無く service も disabled なので影響は無いが、他の機体を考えて直すこと。
低
- L-new1.
--checkは unit の enable 状態の差分を見ない(C-new1 が--checkに出なかった理由でもある)。plus を外せば実害は無いので、記録のみ。 - L-new2.
can_pin_nameが rc=1 を返すのは、iface が無いときだけでなく、名前が空いていて ip の down・rename そのものが失敗したときもある。後者まで WARNING で exit 0 になり、コメントの方針(「ip が失敗したら exit 1」)と食い違う。区別できないなら、コメントの方をそう直すこと。 - L-new3. swap の途中で失敗すると、iface が
can_tmp_<pid>の名前のまま残る(exit 1 なので気付くことはできる)。巻き戻すか、README で一言触れておくこと。 - L-new4. README の clone の URL が
RyodoTanaka/can_toolsになっている。今のOEDO-Dynamics/can_toolsに直すこと。リンク unit を外したあと、/opt/can_tools/canhat_fd_setup.serviceが残るが無害である。
実装者が挙げた lib 側の 2 点について
can_nowがset -uで unbound になる件: 指摘のとおりである。A2 の: "${CAN_TOOLS_FAKE_TIME_FILE:=}"は正しい回避策で、env -iの試験で確かめられている。set -eの呼び出し元で、正常な経路でも非 0 を返す件: 指摘のとおりで、if/||で包むという A2 の書き方は正しい(bash は条件の中ではネストした呼び出しも含めて errexit を止める)。範囲はもう少し広い:can_lockの(( _CAN_LOCK_DEPTH++ ))は、深さ 0 のとき式の値が 0 になり、終了状態 1 を返す。そのためset -eの下で裸のcan_lockを書くと、ロックを取った直後に abort する(A2 はcan_lock || {…}なので問題ない)。- 上の M-new1 の
local currentも同じ種類の問題である。 - なお「unlock が走らずロックが残る」ことは無い。flock は fd に付いているので、プロセスが終われば解放される。ただし watchdog のような常駐プロセスでは、abort そのものがサービスの再起動になる。
→ lib の修正を A1 の追補 PR として予定すべき(PR-B の watchdog が set -euo pipefail を使う可能性が高いため、B が lib を本格的に使う前に入れたい)。内容:
- (a)
can_nowを${CAN_TOOLS_FAKE_TIME_FILE:-}にする - (b)
can_pin_nameをlocal current=""にする(ほかにも初期値の無いlocalを洗い出す) - (c)
can_lock/can_unlockの増減を_CAN_LOCK_DEPTH=$((_CAN_LOCK_DEPTH+1))にする - (d) 内部で非 0 になり得る文を
|| trueかifで扱い、lib の全関数をset -euo pipefailの下で裸で呼んでも、意図しない abort が起きないようにする - (e) 試験に「
set -euo pipefailの下で各関数を裸で呼ぶ」を加える
それまでの間の呼び出し規則として、§2b の契約の追記に「lib の関数は if / || の中で呼ぶ」を加えておくとよい。A2 側の回避策(: "${…:=}" と if で包む書き方)は、lib を直したあとも害が無いので、残してよい。
直したあとの再レビュー
C-new1 と M-new2 の差分だけを見る(plus を enable しないこと、calls.log の試験、can_monitor の停止の手順)。
…rename error handling Addresses the PR-A2 2nd review (pullrequestreview-5528185457): - C-new1 (critical): install.sh no longer installs/enables canhat_plus_rename.service/canhat_plus_setup.service by default. canhat_plus_setup.service has no After=/Before=/lock relationship with canhat_fd_setup.service, so enabling it unconditionally on every machine let it race the FD setup and overwrite its txqueuelen 10 / restart-ms 100 with its own 65536/1000 on boot. A new `--plus` flag (or CAN_TOOLS_INSTALL_PLUS=1) opts a HAT+ machine in explicitly; the canhat_plus_* scripts are still copied to /opt/can_tools either way (harmless, never run on their own). README documents the manual opt-in. - M-new2: can_monitor.service (a oneshot that itself runs `ip link set down; sleep 0.5; up`) is no longer sent `systemctl stop` - a stop landing mid-run could leave the interface down. install.sh now waits (bounded, CAN_TOOLS_MONITOR_STOP_TIMEOUT_S, default 15s) for it to go inactive on its own before disabling/removing it; can_monitor.timer is still stopped immediately (inert, no CAN I/O). - L-new1: --check now also reports a managed unit that is installed but not enabled (read-only `systemctl is-enabled`, never mutates). - L-new2: canhat_fd_rename.bash now checks interface presence itself (can_iface_of_spidev) before calling can_pin_name, so a present interface whose ip rename actually fails is treated as a hard failure (ERROR, exit 1) rather than the L4 "missing hardware" case (WARNING, exit 0) - can_pin_name's rc=1 doesn't distinguish the two on its own. - L-new3: a swap that fails partway now rolls back the renames it had already made, so a failed canhat_fd_rename.bash run never leaves an interface stuck under "can_tmp_<pid>". - L-new4: README clone URL corrected to OEDO-Dynamics/can_tools. Tests: tests/test_install_idempotent.sh gained scenarios 6 (plus units never enabled without --plus; are with it) and 7 (--check flags a disabled unit), and scenario 4's can_monitor assertions now check is-active + no stop for can_monitor.service specifically. tests/test_setup_lib_usage.sh gained cases for L-new2 (ip failure on a present interface exits 1) and L-new3 (mid-swap failure rolls back, leaves no can_tmp_* interface). M-new1 (can_pin_name's `local current` being unbound under set -u) and the lib's general set -e safety are being fixed in a separate can_tools_lib.bash PR, per the review; this PR keeps its existing call-site guards (if/|| around every lib call) and does not touch the lib or tests/fakes/. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
|
2回目レビュー(pullrequestreview-5528185457)に対応しました(c30b499、feat/can-tools-a2-install に push 済み)。 クリティカルC-new1(plus unit を全機体で enable していた): 中M-new2(can_monitor.service への stop が down/up の最中に当たり得る): 低L-new1(--check が enable 状態を見ない): L-new2(can_pin_name の rc=1 が「無い」と「ip失敗」を区別できない): lib 自体には触れず、呼び出し側( L-new3(swap 失敗時に can_tmp_ が残る): swap の 5 ステップ(down→down→rename→rename→rename)のどこまで成功したかを追跡し、失敗したら成功済みのリネームだけを巻き戻すようにしました。 L-new4(README の clone URL): lib 側(別 PR 予定、今回は触っていません)
前回から変わっていないことの確認C1・C2・H1〜H5・M1・M3〜M6 は今回のレビューでも「解消」との判定をいただいており、今回の差分では触れていません(M2 は daemon-reload/enable の仕組みは変えず、plus を外しただけです)。 |
RyodoTanaka
left a comment
There was a problem hiding this comment.
PR-A2 第 3 回レビュー(Opus、差分 6c458a4..c30b499)
判定: 要修正(中 1。新しく足した --plus の不具合で、直す箇所は小さい)。2 回目の指摘はすべて解消した。
確かめ方: 前回と同じ偽の環境で動かした。今回の偽 systemctl は状態を持つ(is-enabled は enable 済みかどうかを返し、is-active は 3 を返す)。配置先は機上を模して、setup と can_monitor の unit を /opt へのリンクで、rename の unit を実ファイルで置き、can_monitor.timer と既存の CAN_FD=off の conf も置いた。rename は env -i で実行し、偽 sysfs の上で、N 回目の name だけ失敗させる ip のラッパーを使った。
2 回目の指摘の確認
| # | 結果 | 確認内容 |
|---|---|---|
| C-new1 plus の enable | 解消(ただし M-r3 を参照) | 既定の install では、systemctl の呼び出しに canhat_plus が 0 回で、sd/ にも plus の unit は無い |
| M-new2 can_monitor の stop | 解消 | 呼び出しは stop can_monitor.timer → disable can_monitor.timer → is-active can_monitor.service → disable can_monitor.service の順で、service への stop は無い。リンクと /opt 側の実体も消える |
L-new1 --check と enable 状態 |
解消 | 初回の --check で Would enable: canhat_fd_rename/setup と出て rc=1。install 後の --check は「no differences」で rc=0。呼ぶのは読み取り専用の is-enabled だけ |
| L-new2 rename の終了の方針 | 解消 | netdev はあるのに name が失敗した場合は <3> pin_name_op_failed、rc=1。spidev が無い場合は <4> missing_netdev で、それ以外が成功なら rc=0。先に存在を確かめるようになったので、M-new1(local current の unbound)にも、空の net/ のケースを含めてこの経路では当たらない |
| L-new3 swap の巻き戻し | 解消 | 手順 3・4・5 のそれぞれで失敗させたところ、どの場合も can_tmp_* は残らなかった。巻き戻しの ip 呼び出しの順序も正しい。ループは次の組で swap をやり直し、最終的に spi0.0=can0、spi1.0=can1 になった。rc=1 なので失敗は見える |
| L-new4 README の URL | 解消 |
中
M-r3. --plus を付けると、plus の unit を FD の unit と「並べて」enable する。README 自身が書いている競合がそのまま起きる
実測では、install.sh --plus を実行すると enable canhat_fd_rename・enable canhat_fd_setup・enable canhat_plus_rename・enable canhat_plus_setup の 4 つすべてが呼ばれた。README の新しい文は「if both ended up enabled on the same machine」のときに競合すると書いており、--plus を付けるとまさにその状態になる。
HAT+(MCP2515)の機体では、さらに次のことが起きる:
- FD の setup が
ip link set canX down→up … dbitrate 2000000 fd onを実行する。MCP2515 は FD 非対応なので、up は失敗する。 - FD の setup が plus の setup より後に走ると、iface が down のまま残る。
- FD の rename は spi0.0/spi1.0 を探すので、WARNING を出して終わる(害は無い)。
--plus はこの PR で新しく足した機能なので、ここで直しておきたい。
→ 修正案: --plus のときは、FD の 2 つの unit を入れ替えること。つまり FD の unit は install も enable もせず、すでに enable されていれば disable(--now は付けない)にする。または、FD の unit が enable 済みなら --plus を拒否する。試験には「--plus で FD の unit が enable されない」ことを加えること。
注: PR-B の can_watchdog.service は Wants=canhat_fd_setup.service を持つ予定なので、HAT+ の機体では FD の setup を引き込んでしまう。--plus のときに watchdog をどう扱うか(install しない等)を、PR-B への申し送りとしてコメントに書いておくとよい。
低(記録のみ。対応は任意)
- L-r3a. 実際の systemctl では、oneshot の実行中は
ActiveState=activatingになり、is-activeは 0 以外を返す。そのため_wait_inactiveは実行中でもすぐ抜ける。ただ stop を送らないので iface は途中で止まらず、実害は無い(disable と unit ファイルの削除では、実行中のプロセスは止まらない)。待ちを効かせたいなら、is-activeの結果ではなくsystemctl show -p ActiveState --valueがactivatingやdeactivatingの間だけ待つようにする。 - L-r3b.
--plus付きで install したあと--plus無しで再実行しても、plus の unit はそのまま残り、--checkにも出ない。M-r3 を直すときに、扱いを README に一言書いておくとよい。
lib 側(M-new1)
別の PR(lib の errexit 対応)に回すことに同意する。A2 側は、存在を先に確かめるようになったので、もうこの経路には当たらない。
直したあとの再レビュー
M-r3 の差分だけを見る(--plus で FD の unit が enable されないこと、その試験)。
Addresses the PR-A2 3rd review (pullrequestreview-5528306698) per coordinator decision: HAT+ is out of scope for Issue #9 §2b, so instead of fixing the --plus flag (which enabled canhat_plus_* *alongside* the FD units, reproducing the exact race the earlier C-new1 fix was meant to prevent - M-r3), remove it entirely. - install.sh never installs or enables canhat_plus_rename.service / canhat_plus_setup.service, under any flag or env var (CAN_TOOLS_INSTALL_PLUS and --plus are both gone). The canhat_plus_* scripts are still copied to /opt/can_tools (harmless, never run on their own). - README's "CAN HAT Plus" section now documents the manual setup instead (disable the FD units first, copy+enable the plus units by hand), and notes that can_watchdog (once it exists, PR-B) is FD-only for now and not meant to run on a HAT+ machine - flagged for PR-B to pick up. - L-r3a (optional, done): _wait_inactive now polls `systemctl show -p ActiveState --value` instead of `is-active`, since a running oneshot reports ActiveState=activating (is-active's exit status alone can't tell "still running" apart from "never ran"/ "finished"/"failed" the way checking the value for activating/deactivating can). - Merged origin/develop (c63da4d..78a6fd7, PR #16 shellcheck CI workflow) via a merge commit, no rebase. tests/test_install_idempotent.sh: Scenario 6 now asserts canhat_plus_* is never installed/enabled for any of install.sh's invocations (no args, a stray "--plus" - now just an ignored unrecognized argument - and "--check"); scenario 4's can_monitor assertion checks for the new `show -p ActiveState --value` call instead of `is-active`. can_tools_lib.bash and tests/fakes/ are untouched. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
|
3回目レビュー(pullrequestreview-5528306698)に対応しました(026949e、feat/can-tools-a2-install に push 済み。origin/develop の #16 を merge commit で取り込み済み、rebase なし)。 M-r3( L-r3a(任意、対応): 完了条件: |
RyodoTanaka
left a comment
There was a problem hiding this comment.
PR-A2 第 4 回レビュー(Opus、差分 c30b499..026949e。途中で develop 0837cb8 をマージ)
判定: 要修正(中 2 件。どちらも数行で直る)
確かめ方: 前回と同じ偽の環境で動かした。偽 systemctl の show -p ActiveState は、最初の 5 回は activating、その後は inactive を返すようにした。origin/develop...026949e の差分には、.github/workflows/ も lib も fakes も含まれていない(workflow は develop のマージで入ったもの)。
前回の指摘の確認
| # | 結果 | 確認内容 |
|---|---|---|
M-r3 --plus で FD と plus の unit が両方 enable される |
解消(--plus 自体を削除) |
install を実行すると、enable が呼ばれるのは canhat_fd_rename と canhat_fd_setup だけ。plus の unit は置かれない |
| L-r3a 実行中の oneshot を待てない | 解消 | show -p ActiveState --value が activating の間(6 回)待ち、そのあと disable する。stop can_monitor.service は呼ばれない |
| L-r3b | 解消(plus を install しなくなったので、該当しない) |
中
M-r4a. install.sh が未知の引数を黙って無視し、通常のインストールを実行する
実測:
install.sh --plus→ rc=0。FD の unit 2 つを enable し、can_monitor を撤去し、ファイルを配置した。install.sh --chek(--checkの打ち間違い)を空の配置先に対して実行 → rc=0。16 ファイルを配置した。
どちらも、運用者の意図と逆のことが起きる:
--plusは前の版の README・コメント・PR コメントに載っていた引数なので、手元の手順や記憶で使われ得る。HAT+ の機体で実行すると、README の HAT+ 節が「disable しておけ」と書いている FD の unit を、まさに enable してしまう。--checkの打ち間違いは、H1 と同じ種類の危険である(確認のつもりで実行したのに、変更が入る)。
→ 修正: 引数の case に -h|--help) usage; exit 0 ;; と *) echo "unknown argument: $arg" >&2; usage >&2; exit 2 ;; を加えること。試験には「--plus と --chek が rc≠0 になり、何も作らない(配置先が空のまま、systemctl が呼ばれない)」ことを足すこと。
M-r4b. HAT+ の手作業の手順を踏んだ機体で、あとから install.sh を実行すると FD の unit が再び enable される
README の HAT+ 節は、FD の unit を disable してから plus の unit を手で入れる手順になっている。しかし install.sh は実行のたびに canhat_fd_rename と canhat_fd_setup を無条件に enable する(M2 の仕様)。そのため、スクリプトを更新しようとして install.sh を再実行すると、FD と plus が両方 enable された状態に戻り、M-r3 と同じ競合が起きる。
plus は対象外なので、install.sh 側に仕組みを作る必要は無い。README の HAT+ 節に「この機体では install.sh を実行しないこと(実行すると FD の unit が enable される)。スクリプトの更新も手作業で行う」と 1 文足せば足りる。
install.sh 側で防ぐなら、canhat_plus_setup.service が enable 済みのときは FD の unit を enable せず、エラーで止める方法がある。ただし範囲外なので、README の 1 文で十分とする。
記録(対応不要)
- 前回までの解消分(C1・C2・H1〜H5・M1〜M6・L1〜L4、C-new1・M-new2・L-new1〜4)は、今回の差分で退行していない。
tests/run.shと CI が緑であることは統括が確認済み。 - M-new1(lib の
local current)は、lib の errexit 対応の PR で直すことを確認した。
直したあとの再レビュー
M-r4a・M-r4b の差分だけを見る。この 2 点が直ればマージ可にする見込み。
…ng it on HAT+ machines Addresses the PR-A2 4th review (pullrequestreview-5528384590): - M-r4a: install.sh now validates its arguments before doing anything else. -h/--help prints usage and exits 0; any other unrecognized argument (a stale "--plus" from before M-r3 removed it, or a typo like "--chek") prints usage to stderr and exits 2, without creating any file or calling systemctl at all - previously both silently fell through to a normal install (--plus) or were simply ignored (--chek), each doing the opposite of what the operator likely intended. - M-r4b: README's "CAN HAT Plus" section now says not to run install.sh on a HAT+ machine at all once it is set up by hand - install.sh unconditionally re-enables canhat_fd_rename.service/ canhat_fd_setup.service on every run (by design, M2), which would silently undo the `systemctl disable` from that section's own setup steps and reintroduce the FD/Plus race. Updates to such a machine are manual too. tests/test_install_idempotent.sh gained Scenario 8: "--plus" and "--chek" both exit non-zero and leave the target directories/systemctl calls untouched; "--help"/"-h" exits 0, prints a usage message, and also touches nothing. can_tools_lib.bash and tests/fakes/ are untouched. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
|
4回目レビュー(pullrequestreview-5528384590)に対応しました(6785eac、feat/can-tools-a2-install に push 済み)。 M-r4a(未知の引数が黙って通常installに落ちる): 引数検証を他の処理より前に行うようにしました。 M-r4b(HAT+ 手順を踏んだ機体での install.sh 再実行が FD unit を再 enable する): README の「CAN HAT Plus」節に、install.sh は実行のたびに canhat_fd_rename/setup を無条件 enable する(M2 の仕様)ため、HAT+ 機体では install.sh 自体を実行しないこと、更新も手作業で行うことを明記しました。 完了条件: |
RyodoTanaka
left a comment
There was a problem hiding this comment.
PR-A2 第 5 回レビュー(Opus、差分 026949e..6785eac)
判定: マージ可
指摘の確認
- M-r4a(未知の引数): 解消。
- 引数の検査は、
SCRIPT_DIRを求めた直後、ほかの処理より前に行われる。そのため、ディレクトリ・ファイル・systemctl のどれにも触れる前に止まる。 - 偽の環境での実測:
--plus・--chek・--check --plus→ いずれも rc=2。配置先は空のまま、systemctl の呼び出しも 0 回だった。-h→ rc=0。- 引数なし → rc=0 でインストールする。直後の
--check→ rc=0。
- 試験も追加されている。
- 引数の検査は、
- M-r4b(HAT+ の機体での再実行): 解消。 README の HAT+ 節に、「この機体では install.sh を実行しない。更新も手作業で行う」理由付きの注意が加わった。
申し送り(このマージを妨げない)
- M-new1: lib の
local currentがset -uで unbound になる問題は、lib の errexit 対応の PR で直す。そこには、can_nowの${…:-}、can_lockの(( ++ ))が返す終了状態の扱い、「lib の関数をset -euo pipefailの下で裸で呼んでも落ちない」ことの試験も含める。 - PR-B への申し送り:
can_watchdog.serviceは FD の機体専用とする。README にもそう書いてある。HAT+ の機体では、watchdog がWants=canhat_fd_setup.serviceで FD の setup を引き込まないように扱うこと。 - 機上への反映(5c-1): 受け入れの手順に沿って行うこと。install は稼働中の機体でも CAN を down/up しない。設定が反映されるのは、再起動時か、機械を止めた状態で setup を restart したときだけである。
Per Issue #9 §2a / §6 (PR-B, last commit): now that PR-A2 (#13, setup/ install) is merged, flip the lib's own defaults from the pre-watchdog values (restart-ms 100, fd on) to the ones the resident watchdog is designed around: - CAN_RESTART_MS=0: the kernel's own bus-off auto-restart is disabled: can_watchdog.service now owns bus-off recovery end to end (settle + backoff + storm handling), avoiding the restart-ms/watchdog race that caused the 2026-10-14 incident. - CAN_FD=off: confirmed in the Issue (論点 C) that the edge apps never write CAN FD frames; running classic-only avoids FD-vs-classic framing ambiguity on the bus. A conf that already pins these keys explicitly is unaffected (can_read_conf only falls back to the lib default for keys the conf does not set). A machine that has not been rebooted since this lands stays on whatever restart-ms/fd the kernel currently has - see §1f's config-mismatch observe-only mode, which the watchdog already falls back to in that case. Also: - README: documents the new CAN_FD default and adds CAN_RESTART_MS to the "Key settings" list (was previously undocumented there). - can_watchdog.service: clarifies in a comment that the unit is CAN HAT FD only (install.sh never deploys it on a HAT+ machine; Wants=/After= stays on canhat_fd_setup.service specifically, not a generic CAN-setup target). - tests/test_setup_lib_usage.sh (PR-A2): updates the one assertion block that hard-coded the pre-switch defaults (restart-ms 100/fd on/dbitrate) to the new ones, so it keeps testing canhat_fd_setup.bash's actual behavior instead of going red on an intentional default change. Refs #9 Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
変更点
1. setup/rename スクリプトをライブラリ関数で置き換え
canhat_fd_setup.bashとcanhat_fd_rename.bashがcan_tools_lib.bashを sourcecanhat_plus_setup.bashとcanhat_plus_rename.bashも同様(CAN FD 無効化)can_read_conf,can_setup_iface,can_pin_name関数を使用2. install.sh - 冪等なインストールスクリプト
/opt/can_toolsへのインストール(rsync の--deleteフラグなし)/etc/systemd/systemへコピー(シンボリックリンク廃止)CHECK_MODEで差分表示対応INSTALL_OPT_DIR,SYSTEMD_DIR3. README.md - Installation/Configuration セクション更新
4. 試験を追加
test_install_idempotent.sh: install.sh の機能検証test_setup_lib_usage.sh: setup/rename がライブラリを正しく使用Refs #9
試験結果
シェル構文チェック
確認事項
can_tools_lib.bash関数を使用Generated with Claude Code