systemctl の start, stop, restart, try-restart, reload, reload-or-restart, reload-or-try-restart の違いまとめ

`systemctl` のサブコマンドってサービスの起動停止リロード周りだけで、妙に沢山用意されてるくせに肝心なサブコマンドが足りなかったり命名や挙動が微妙だったりで納得行かない点が多くて腹立つので纏めた。

# やりたいこと→対応コマンド まとめ表


|やりたいこと| COMMAND                 | active   | inactive           |
|:--|:------------------------|:--|:--|:-:|
|起動状態にしたい| systemctl start xxx                  | なにもしない (exit 0) | start (Starting,Started) |
|停止状態にしたい| systemctl stop xxx                    | stop (Stopping,Stoped) | なにもしない (exit 0) |
|稼働中なら再起動、停止中なら起動| systemctl restart xxx                 | restart (Stopping,Starting,Started) | start (Starting,Started) |
|稼働中なら再起動、停止中なら何もしない| systemctl try-restart xxx             | restart (Stopping,Starting,Started) | 何もしない (exit 0) |
|稼働中ならリロード(UnitのReload対応必要)、停止中ならエラー| systemctl reload xxx                  | reload (Reloaded) | エラー (echo "Job for xxx.service invalid." >&2; exit 1) | 
|稼働中ならリロード(UnitがReload非対応ならrestart)、停止中なら起動| systemctl reload-or-restart xxx      | reload (Reloaded) | start (Starting,Started) |
|稼働中ならリロード(UnitがReload非対応ならrestart)、停止中ならエラー| systemctl reload-or-try-restart xxx  | reload (Reloaded) | エラー (echo "Job for xxx.service invalid." >&2; exit 1)  |
|稼働中ならリロード(UnitがReload非対応ならrestart)、停止中なら何もしない|if systemctl -q is-active xxx; then systemctl reload-or-restart xxx; fi| reload (Reloaded) | 何もしない (exit 0) |


- 褒めたいとこ
    - `start` と `stop` が稼働中か停止中かのステータスを見て不要なら何もしない挙動になってて SysVinit 時代よりちょっと賢い。
    - `restart` って SysVinit 時代は事前状態無視して雑に stop and start を実行するイメージだったけど、systemctl だと停止状態なら無駄な stop はしないで start だけ実行するって挙動になっててちょっと賢い。これ内部的には多分stop/start呼んでるだけでstop/startが賢くなったことの恩恵がそのままrestartにも現れてるだけか。
    - `reload-or-restart` が出来るのは嬉しい。SysVinit の頃とかは status チェックして reload と restart を使い分けるワンライナーとか書くこともよくあったし。ん？でもこの挙動って名前とちょっと違うよな…？
- 文句言いたいとこ
    - `try-restart` って言葉の印象と動作が何か違くね？ try restart て言われると「事前ステータス無視してとりあえず再起動stop,start)実行してみる」ぽい印象なんだけど、実際は事前ステータスに応じて「稼働中なら再起動(stop,start)して、既に停止中ならstopすらせず何もしないで正常終了」とかむしろ微妙にインテリジェンスな挙動してるのがもにゃる。いや挙動自体はむしろこういう動作が欲しいことが多いからいいんだけど名前だけが気になる…。英語ネイティブな人の感覚だと問題ないのかな？これ。自分の try に対する理解が間違ってるん？
    - `reload-or-restart` って非論理的で分かりにくくね？ ~~やってることは reload-or-start じゃん？~~ あー！この restart って非稼働中の場合にstartするって意味じゃなくて、UnitがReload対応してなかったらreloadの代わりにrestart実行するって意味だったのか！ でも、だったら非稼働中のときは reload のときと同様にエラーになれよ！ 何勝手に起動してんだよ！？ 全体で見た時にやっぱり非論理的で混乱するじゃねーかよ! 多分、`reload-or-restart` は非稼働時はエラーになる挙動にしといて、別途 _`reload-or-restart-or-start`_ とかって名前のサブコマンド作ってそっちを今の `reload-or-restart` の挙動にしとくべきだったと思うぞ、こんなサブコマンド無いけどもさ。それに今更挙動変えたら互換性保てなくなって問題出るし、後の祭りだからもういいけどさ…。
    - 「稼働中ならリロード(UnitがReload非対応ならrestart)、停止中なら何もしない」が何で存在しないんだよ！？ すげー使うシーンあるだろうが。これだけいつもワンライナー書いてるわ。
    - ていうか改めて `try-restart` の言葉の意味がわかんねー…。何で `try-restart` のときは停止中は何もせず正常終了だったのに、`reload-or-try-restart` は停止中だとエラーになるの？ 全体的にサブコマンドの名前と挙動がちぐはぐ過ぎんだろ？ SysVinit とか Upstart とかを踏み台にして、現状、最後発で出てきたリソース管理の仕組みだろう？何なのこのとっちらかって洗練されてない感じは…。


# bash-completion に出てくるサブコマンドの `legacy alias` は補完候補から消え去って欲しい。
以下のサブコマンドはいくつかのディストリビューションの慣習で存在してたものだが、systemctl にまとめる際に `legacy alias` として内部では以下のような対応のエイリアス定義されてて一応受け入れて使えるけど、基本使わない奴だ。

- condstop -> stop
- condrestart -> try-restart
- condreload -> reload-or-try-restart
- force-reload -> reload-or-try-restart
- check -> is-active

これらのサブコマンドは `systemctl --help` の一覧には表示されないが man には乗ってる程度の扱い。基本いらないんだが、これが `bash-completion` などの補完ではサブコマンドとして普通に一覧に出てきてしまう。このせいでタダでさえサービス系のサブコマンドが多くて分かりにくいのに、「condreloadとreloadって何が違うの？helpにねーし…ぐぐったりman見たら分かったぞタダのエイリアスかよ！確認する時間無駄にしたじゃねーか」って感じで世界中の技術者のリソースが無駄に消費させてると思うと、無駄に混乱させられて腹立つし補完リストからも消え去って欲しい。あえてこれを補完して使いたいケースなんてないでしょ？


# ぐち
いや、過去のいろいろに比べて仕組み的には良いところもいっぱいあるのは知ってるんだけどさ、一番良く使うサービス操作系のサブコマンド郡がなんか微妙なのがイラッと来るんだよね。多分普通に利用するだけなら status/start/stop/restart/reload くらいしか使わないから気にならないんだけど。
ansibleの構成ファイル作ってるときとか、ちょっと事前状態確認しつつreloadやstartとか使い分けたかったり、あるべき状態を終了ステータスで適切な判定したいとかやりはじめると、サブコマンド名が論理的に整理して覚えられないし挙動もチグハグだから不安になって結局毎回ドキュメントや実際の挙動とかを確認しながら書く羽目になるんだよな。