😥

grepを忘れただけなのに

4 min read 2

今年も『本番環境でやらかしちゃった人のアドベントカレンダー』の季節がやってきましたね。
知見が多く、関心しながら拝見しています。

https://qiita.com/advent-calendar/2020/yarakashi-production

人は必ず何かしらミスを起こすもの。
明日は我が身と思いながら、業務をこなす日々です。

そんな私も業界に入って1年目に、本番環境の洗礼にあったことがございます。
当時は苦々しい思いをしましたが、その経験を供養するためにもここに残そうと思います。

発生当時の状況

事件当時、私はサーバのリプレイス案件にアサインしていました。
その業務の中で上司に日常的に運用されているスクリプトの調査を依頼されました。
私はまだ経験が浅かったため理解が合っているかは怪しいですが、関わっていたシステムは設計の段階で大分やっつけだったらしく、
格納場所が間違っているスクリプトやログが散見されました。
リプレイスを切っ掛けに整理をする予定だったと記憶しています。

入ったばかりのペーペーの私が1人で調査できる訳がないので、ベテランの方(以後Sさんと呼称)と一緒に調査することになりました。
ベテランの方はいわゆる職人という感じで、積極的にコミュケーションをとる方ではなく、私はその雰囲気もあって特に会話もせず、基本Sさんの言うことに疑問を持たず従うという動きをしていました。
それが事件の引き金となることも知らず・・・。

事件経緯

調査のために本番環境にログインし、lsコマンド等で情報を取得しようとしました。
新人である私がおぼついた操作をしようものなら、職人をイライラさせてしまうため、作業確認者(ほぼ置物)となって作業にあたりました。
対象ディレクトは複数ありましたが、その内の一つに下記のようなスクリプト以外のものが紛れ込んでいるディレクトリがありました。

-- script
    |-- 190106.log
    ~~~~~~~~  略 ~~~~~~~~~~
    |-- 201206.log
    |-- app01.sh
    |-- app02.sh
    |-- app03.sh
    |-- app04.sh
    |-- app05.sh
    |-- app06.sh
    |-- app07.sh
    |-- app08.sh
    ~~~~~~~~  略 ~~~~~~~~~~
    |-- app40.sh
    |-- common01.sh
    |-- common02.sh
    |-- common03.sh
    |-- common04.sh
    |-- common05.sh
    ~~~~~~~~  略 ~~~~~~~~~~
    |-- common30.sh
    |-- day
    `-- month

皆さんはこの中から、スクリプトだけ表示させるならどのようなコマンドを使用するでしょうか?
findでしょうか?grepでしょうか?
はたまたlsで全部取得して、コンソールのログから抽出しますか?

どちらにしろ、やり方はSさん次第です。
私に意見はございません。ベテランに任せれば全て上手くいくのですから。

Sさんは手癖のようにコマンドを入力します。(実際に手癖なのかもしれません)
コンソール画面に高速にコマンドが表示されます。

[root@foo script]# ls -l |

私が「あ、grepで表示するのか」と思う間もなく、コマンドは放たれました。
そのコマンドとは下記の形でした。

[root@foo script]# ls -l | sh

grepを打ち忘れてますね。
猿も木から落ちる。弘法も筆の誤り。
結果、画面に表示されたのは

sh: line 1: total: command not found
sh: line 2: -rw-rw-r--.: command not found
sh: line 3: -rw-rw-r--.: command not found
sh: line 4: -rwxr-xr-x.: command not found
sh: line 5: -rwxr-xr-x.: command not found
sh: line 6: -rwxr-xr-x.: command not found
~~~~~~~~~~~ 略  ~~~~~~~~~

ずらっとcommand not foundが続いていました。
これは・・・どうなったんだ?もしかしてやってしまったのか?本番環境で?どうする?どうする?
危うくテンパる間際の私に、Sさんはこう言いました。

「打ち間違えた。lsの標準出力をshコマンドに繋げてしまったが、パーミッションの表示に該当するコマンドは存在しないので問題はない。」

へ〜そうなんだ〜。さすがSさん。冷静だぜ!
一瞬ヒヤってしたしたが、ベテランが大丈夫って言ってるのでヨシ!

その後も調査を続け、上記の打ち間違い以外は特に何事もなく終えました。

事件発生

本番環境のバッチが動かない

そんな連絡を受けたのは、作業した次の日でした。
のんきな顔して出社してきた私に対し、複数の人が詰め寄ってきます。
本番運用を任されている人達です。

「バッチで使用しているスクリプトの中身が消えている。昨日、本番作業をした時にスクリプトを編集しなかったか?」

え?スクリプトの編集?
そんな覚えはない。

いや・・・。もしかしてあのコマンドの打ち間違いか?

ともかく私では、どのコマンドがスクリプトに影響を及ぼしたか判断がつかなかったため、作業当時のログを提出し、
打ち間違いをした箇所を報告しました。

結果、私たちの作業でスクリプトの中身を消していることが判明しました。

原因

やはり、下記のコマンドが原因でした。

[root@foo script]# ls -l | sh

『いやいや。そもそもcommand not foundが出てたし、何も起きるわけないでしょ。』
そんなふうに考えていた時期が私にもありました。

なぜ上記のコマンドでスクリプトのクリア処理が起こったのか?
それは対象ディレクトリにあるファイルに鍵がありました。
では当時を再現した状態を見てみましょう。

[root@foo script]# ls -l
total [n]
-rw-rw-r--. 1 root    other    0 Dec  6 07:48 190106.log
~~~~~~~~~~~~~ 略 ~~~~~~~~~~~~~~
-rw-rw-r--. 1 root    other    0 Dec  6 07:13 201206.log
-rwxr-xr-x. 1 root    other   39 Dec  6 07:10 app01.sh
-rwxr-xr-x. 1 root    other    0 Dec  6 07:46 app02.sh
-rwxr-xr-x. 1 root    other    0 Dec  6 07:46 app03.sh
-rwxr-xr-x. 1 root    other    0 Dec  6 07:46 app04.sh
-rwxr-xr-x. 1 root    other    0 Dec  6 07:46 app05.sh
~~~~~~~~~~~~~ 略 ~~~~~~~~~~~~~~
-rwxr-xr-x. 1 root    other    0 Dec  6 07:46 app40.sh
lrwxrwxrwx. 1 root    other   32 Dec  5 14:00 common01.sh -> /db/script/common/common01.sh
-rwxr-xr-x. 1 root    other    0 Dec  6 07:47 common02.sh
-rwxr-xr-x. 1 root    other    0 Dec  6 07:47 common03.sh
-rwxr-xr-x. 1 root    other    0 Dec  6 07:47 common04.sh
-rwxr-xr-x. 1 root    other    0 Dec  6 07:47 common05.sh
~~~~~~~~~~~~~ 略 ~~~~~~~~~~~~~~
-rwxr-xr-x. 1 root    other    0 Dec  6 07:47 common30.sh
drwxrwxr-x. 2 root    other    6 Dec  6 07:12 day
drwxrwxr-x. 2 root    other    6 Dec  6 07:11 month

そう。シンボリックリンクがあったのです。

つまり下記のようなコマンドが走っていたことになります。

sh lrwxrwxrwx. 1 root    other   32 Dec  5 14:00 common01.sh -> /db/script/common/common01.sh

ここで問題なのはシンボリックリンクの> /db/script/common/common01.shの部分。
このリダイレクトだけが発動して、シンボリックリンク先のファイルをクリアしてしまっていたのです。

リダイレクトの部分だけなぜ有効に機能するのかはシステムコールを全く読めなかったので、究明できませんでした。
知ってる方は教えて下さい・・・。

どうすればよかったのか?

  • 本番作業をコマンド手打ちとかありえない

  • findコマンドでやれよ

  • そもそもrootでやること?

とか色々あるとは思いますが、私が出来た範囲で防げたことがあります。

私が作業確認者として、しっかりコマンド実行前に確認すること。

これだけでコマンドの打ち間違いに気づけました。
(私が気づかなくても実行前に一拍おくだけで、Sさんが気づいた可能性があります)

本番作業を甘く見て、ベテラン作業者1人だけに任せてしまいました。

以後反省し、どんなに話辛い人とペアになっても作業前は必ず認識を合わせるようにしてます。
本番環境の前では人は皆平等になるのだから・・・。