redis-cli config rewriteでpermissionエラーが発生した際も終了ステータスは0で終了する

環境

  • redis 6.0.10
  • redis-cli 6.0.10

問題

redis-cli config rewrite を実行したところ、redis.confが配置されているディレクトリにredisを実行しているユーザの書き込み権限がないために、(error) ERR Rewriting config file: Permission deniedというエラーが発生した。 この場合のコマンドの実行の終了ステータスは0となっていて、そのため、以下のようなAnsibleのタスクは成功してしまった。

- name: Rewrite config file
  command: "redis-cli -a `password` config rewrite"
  changed_when: yes

エラーの趣旨が出力されていても終了ステータスが0になる。これに関連したIssueとしては以下が存在する。 github.com 終了ステータスが0である背景について、以下のコメントがされている。 github.com

redis serverでエラーが発生してもredis cliがエラーというわけではない、 サーバ側のエラーでありCLIのエラーではないため、exit statusは0ということのようだ。

また、例えば、以下のようにredis clusterで他のノードにデータがある場合のエラーについても、終了ステータスは0である。

$ redis-cli  -a 'password' get aaa
Warning: Using a password with '-a' or '-u' option on the command line interface may not be safe.
(error) MOVED 10439 XX.XX.XX.XX:6379
$ echo $?
0

redis-cli を実行する際、人が実行するときは出力される文章でエラーに気が付けるが、Ansibleやshellなどコードとして機械的に実行する際はエラーを表現する出力があっても終了ステータスは0となることがあるようなので扱いに注意が必要である。

解決方法

今回に限っては、ERR が出力に含まれていたらタスクを失敗させるようにすることで検出できる。 ただ、このケース以外でタスクとしては失敗してほしいがERRがつかない場合がないとは言えないので、その場合はこの方法だと検知できない。

- name: Rewrite config file
  command: "redis-cli -a `password` config rewrite"
  register: result
  failed_when: result.rc != 0 or "ERR" in result.stdout

検知したいエラーに対して失敗するように条件を追加するとか、 エラーが発生すること前提で正しく処理ができたかを別の方法で確認するアサーションを追加するなどで対応することが考えられる。 今回の場合だと、対象のredis.confに対して確かに期待する設定が記述されているかをgrepするとか。

追記(2021/09/21)

Redis 6.2で以下のPRが入り、redis-cli-e オプションを指定することでサーバエラー時に終了ステータスをエラーコードで返すようにできるようなったようだ。

github.com