2017/12/16

esxtop のご乱心とその対処法について

vSphere の管理をしていると、vSphere Client などGUIからではらちがあかず、SSH でログオンして様々なコマンドで状況を確認、解消する事もよく出てきます。

特にパフォーマンス問題で力を発揮するのが esxtop コマンドです。Linux, UNIX の top コマンドのように仮想マシンや関連プロセスの稼働状況、IOの状況を表示、定期的に更新してくれる優れものです。
esxtop : とくにパフォーマンス問題で無くてはならない管理者の友です
ただ、様々な端末を使っていると、ときにこの esxtop の表示が乱れたり、vi や less が下記の画像のような表示をして正しくスクロールしてくれなくなる事があります。
esxtop ご乱心!

terminal is not fully functional のメッセージ
リターンを押すと一応表示されるが、若干挙動がおかしくなる

これはどうしてかを簡単に調べてみました。

● 端末画面制御

esxtop や vi, less といったコマンドの特徴は、ただ出力のテキストを垂れ流すのではなく、画面の任意の位置を書き換え、適切なところに表示を行おうとする、事です。こうした端末画面の制御のためのデータベースとして、termcap と terminfo があります。とか言うと何故画面制御にデータベースが関係する? となりますが、これはUNIXと「端末」の歴史にもつながってきます。

60年代やそれ以前、極めて初期のコンピュータでは出力は「紙」でした。プログラムからの出力は紙に印字されて出力されていました。その後にブラウン管への出力に移っていきましたが、ごく初期のブラウン管の出力とキーボードなどの入力の組み合わせた機械、すなわち「端末」(Terminal)では、やはり出力をそのまま、左から右、上から下へだだっと垂れ流すしかできませんでした。これを「ダム端末」と呼ばれてました。dumb=馬鹿とかのろまとかという意味で、まあシリアルケーブルなどを通じて送られてきたデータをただ垂れ流し表示するだけ、なんの能もないからそういう名前になったようです。

少し時代が経つと、少し賢い端末がでてきました。ダム端末に対してこれらは「インテリジェント端末」とも呼ばれました。インテリジェント端末の定義は時代により様々ですが、出始めの場合、文字に色がつけれる、Tektronixと言う会社の端末のように グラフィックの表示機能を備えたものとかがインテリジェント端末と呼ばれました。
(後にはパソコンベースの端末でローカルでのアプリケーションの実行やそれとホストとの連携ができるもの、などがインテリジェント端末と呼ばれるそうですが、私はこの頃はよく知りません。)

インテリジェント端末の時代になってただ出されたテキストを垂れ流しで表示するのではなく、文字の色を変えたり、画面の任意の位置にカーソルを動かして「左から右、上から下」ではない順序での表示が可能になりました。

このような画面の操作を行うのにつかわれたのが「エスケープシーケンス」などと呼ばれる一連のテキストです。これは出力のテキストに混ぜて送られ、送られた文字をただ表示するのではなく、その文字列が指示する動き、例えば次の文字を赤く表示する、カーソルの位置を上から20左から30に移動させる、を実施しました。ちょうどHTMLのタグみたいなものです。この一連のコードはエスケープ(0x1B)を先頭にする場合が多かったこともありエスケープシーケンスと呼ばれました。

エスケープシーケンスは後にISOの共通規格にもなりましたが、問題は、インテリジェント端末の出始めは必ずしも端末のエスケープシーケンスが同じ、ではありませんでした。ホスト上で動くソフトウェア、例えば vi とか esxtop、が次はカーソルを左上に動かして強調文字で「ABC」と書きたい、とか思っても、端末ごとに送るエスケープシーケンスは異なる、端末ごとにアプリ側で対応が必要となりました。ホストに繋ぐ端末機器を変えるたびにアプリ側の設定変更(あるいはコードの修正)が必要になりました。

これは不便だと登場したのが BSD UNIX の「termcap」というデータベースです。/etc/termcap というファイルに、端末ごとのエスケープシーケンス、カーソルを上に動かす時はこう、色を変える時はこう、っという定義を記載、環境変数 TERM によりどの端末の種類かを定義、esxtop のようなアプリケーションはTERMの端末種別を元に termcap から適切なエスケープシーケンスを読み出し、適切な操作ができるようになりました。
環境変数TERM
SystemV では terminfo というほぼ同じ仕組みが作られました。termcap との違いは「termcap はテキストで人が読める」「terminfo はテキストの定義を元にバイナリに変換、アプリからの読み込みが手っ取り早い」と、まあその程度です。

なお、いまどきの Linux, UNIX では terminfo の方を使うのが一般的となってます。

Windows の TeraTerm Pro Putty といったソフトウェアは、SSH や TELNET といったプロトコルで通信する機能を提供する一方、エスケープシーケンスを解釈し適切な表示を行う「端末」の役割も果たしてます。このため端末エミュレータとも呼ばれます。分かりやすいのは macOS の「ターミナル」や Ubuntu Linux などのターミナルアプリで、これらは「端末」としての表示のみを担当、SSH での通信は ssh コマンド、TELNET での通信は telnet コマンド、が担当しております。

余談ですが Windows 8 から 10 にかけて、ウィンドウズのコマンドプロンプトウィンドウもかなり機能強化されましたが、その一つとして端末エミュレータとしての機能強化もあります。マイクロソフト自身が OpenSSH を移植、Windows10 への標準搭載化を進めていますので、端末エミュレータとしての機能の受け皿が必要になった、というのもあります。

閑話休題、ともあれ termcap ないしは terminfo というデータベースを通じて端末の形式から正しいエスケープシーケンスを調べだし、適切な画面の制御ができるようになっている、というのが Linux, UNIX の端末画面制御になります。

なお、terminfo の情報は通常、/usr/share/terminfo 以下にあります。コンピュータの処理能力が非力だった時代からあるため、負荷軽減と検索の高速化のため、terminfo フォルダの下にサブフォルダを作成、1ファイル1端末種別 でファイルが格納されています。
macOS 10.12.6 Sierra での terminfo の設定ファイル数
1ファイル=1端末種別のため、約2600の端末機器に対応...ほとんどは使われないと思うけど。
macOS の場合、terminfo 以下には 2563ファイル存在、つまり 2563種類の端末に対応しています。

また、「ターミナル」アプリケーションでは、以下画面の10種類の端末形式に対応しております。
Mac の場合、ターミナルアプリのプロファイルにて、
プロファイルごとにどの端末の種別かを設定できる

vt100 はハードウェアだった端末でのデファクトスタンダードで、vt100互換、つまりvt100と同じエスケープシーケンスを受け付ける端末ハードウェアが多かったと伺っております。また、xterm は X Window System に付属のターミナルソフトで、rxvt は xterm を元に軽量化させたもので、一時期 流行ってたのを記憶しております。
( なお、私は NeXT(標準ターミナルアプリケーション) -> UX/OS(kterm) という流れで以降は Mac か Windows を端末に Solaris や Linux にリモートアクセスなので、xterm を少々使った事があるぐらいです。)

大まかに有名どころの端末のエスケープシーケンスに対応していると言えます。
この「ターミナルの宣言方法」を切り替えてから新規ターミナルウィンドウを開くと、環境変数TERMはその値に設定され、そして若干挙動がかわります。例えば、vt100 と xterm でそれぞれ less を実行、終了すると分かりやすいと思います。


● ESXi の端末情報データベース

さて、ようやく本題です。
ESXi Shell の環境も概ね Linux, UNIXの仕組みを継承しています。画面制御については実は terminfo を使っています。ではどれだけの端末の種類に対応してるでしょうか...。

ESXi Shell 環境での端末の種別。5行、すなわち5ファイルで、5端末種別、だけ...。
はい。たった5種類の端末にしか対応していません。内訳を見ると、screen, xterm, ansi, linux, vt102 です。screen は端末切り替えソフトの screen を使用の際に使われるもの、linux は Linux 起動時のコンソールで利用される端末の種別で、実際、コンソールでの ESXi Shell では環境変数TERM は linux に定義されています。
ローカルコンソールでの ESXi Shell
環境変数が linux になってるのが分かる
つまり、ssh接続などで一般的に使われる端末エミュレータとしては、xterm か vt102 しか対応していない、といえます。
Mac のターミナルアプリケーションのデフォルトの端末種別は「xterm-256color」です。ssh コマンドはデフォルトでローカルの環境変数TERMをリモートにも伝えてくれます。つまり ESXi にログインした場合、環境変数 TERM は xterm-256color が設定されますが、これは ESXi 側の terminfo に存在しない端末種別のため、esxtop のように画面制御ができずダム端末のようにテキストを流し込んでくるか、冒頭の less のように「制御できないけど、いい?」って聞いてくるようになります。

● どう対処すべきか

このような問題が生じている場合、簡単なのは送付する環境変数TERM を変えてしまうと言う事です。
例えば、以下のように env コマンドで環境変数TERMを xterm に変更後 ssh コマンドを実行すると、ESXi 側では xterm-256color ではなく xterm として扱ってくれます。

env コマンドで環境変数TERMを再設定してから ssh
結果、再設定したTERMの値が伝えられる
xterm-256color と xterm は、色に関するエスケープシーケンスが違うだけで互換性がありますので、このような無茶も通ります。

あとは、そもそも端末エミュレータ側の端末種別を xterm か  vt102 に設定してしまう、というのもあります。

この手の問題をググると、「だったら terminfo に設定追加すれば良いじゃん」的な答えが散見されますが、残念ながら ESXi Shell の環境には tic コマンド(terminfo でテキストの設定からバイナリの設定にコンパイルするコマンド)が存在しないので、やるとすると少々面倒です。また、ESXi Shell 環境というかあのファイルシステムにあまり独自のファイルを置くのはあまり推奨されません。やるなら tardisk とか ramdisk の仕組みをよく調べて、ESXi の動き、何処のファイルが温存されどれが消えうるかを確認、これらの意味をよく分かった上で実施すると良いでしょう。

ともあれ、vSphere の管理者にとって esxtop が使えない環境は最悪です。環境変数TERMをうまく扱う事でそんな環境はなくしていきましょう。


最後に、個人的な感想ですが、「いや、vt100互換が実際には vt102互換である事ぐらいは知ってるけどさ、何も馬鹿正直に vt102 だけを置いて vt100 を置かないってのもないんじゃねえの?」とか思いましたよ、ええ。