踏み台から多段ログインしてconfファイルの編集を行うTeratermマクロ

# 概要
Zabbixサーバの移行に伴い、これまで監視していた数十台のサーバでzabbix_agentd.confの書き換えが必要になりました。
サーバ1台1台にログインし、ファイルを編集するのはあまりにも面倒なため、一括で設定変更を行ってくれるTeraTermマクロを作成しました。
本記事ではZabbix_agentd.confの編集を行っていますが、色々と応用が利く内容のため備忘として残します。

# 環境
マクロ実行PC(Windows10)
踏み台サーバ(CentOS7)
ZabbixAgentサーバ(RHEL7)
TeraTerm v4.106

# 事前準備
マクロの中身については後述しますが、軽く説明するとテキストファイルの中に接続先のIPアドレスまたはホスト名を列挙しておき、その一覧をwhile文で読み取って順次接続、confファイルを編集していく流れになります。

本記事ではデスクトップにmacroフォルダを作成し、その中にTXTファイルとTTLファイルを格納しています。
また実行ログ取得用にlogフォルダをサブフォルダとして作成しています。
Desktop
　└macro
　　　├log
　　　├ServerList.txt
　　　└ZabbixConfWrite.ttl

ServerList.txtの記載内容は以下になります。

```ServerList.txt
#本番環境
172.20.100.10
172.20.100.11
172.20.100.12

#開発環境
172.21.200.10
172.21.200.11
172.21.200.12
```


# マクロの記載内容
マクロの記載内容について以下に記します。
やることは「Server=」と「ServerActive=」のIPを移行後のサーバIPに書き換えます。
また、Zabbixを構築した前任者は逐一「Hostname」を記載していましたが、コメントアウトしておけばOS上のホスト名でZabbixサーバと通信するため、「Hostname」パラメータは無効にします。
丁寧にやるのであればエラーハンドリングをすべきなのでしょうが、面倒なのでひとつ操作をする度に1秒待機させるかプロンプトが入力可能な状態になるのを待っています。

```bash:ZabbixConfRewrite.ttl
;======================================================================
; 踏み台情報
BASTION = 'XXX.XXX.XXX.XXX'
USERNAME1 = 'BastionUser'
PASSWORD1 = 'XXXXXXXXXXXX'
; ログファイル保存先
LOGPATH = 'C:\Users\USER\Desktop\macro\log\'
; 接続先サーバ一覧ファイル
HOSTFILE = 'C:\Users\USER\Desktop\macro\ServerList.txt'
; 接続先ユーザパスワード
USERNAME2 = 'ServerUser'
PASSWORD2 = 'XXXXXXXXXXXX'
; Zabbix情報
CONFFILE = '/etc/zabbix/zabbix_agentd.conf'
SEARCHSTR1 = 'Server=XXX.XXX.XXX.XXX(移行前ZabbixサーバIP)'
SEARCHSTR2 = 'ServerActive=XXX.XXX.XXX.XXX(移行前ZabbixサーバIP)'
SEARCHSTR3 = 'Hostname=XXX(命名規則の先頭文字列)'
APPENDSTR = 'XXX.XXX.XXX.XXX(移行後ZabbixサーバIP)'
;======================================================================

; サーバ一覧ファイルオープン
fileopen HOSTLIST HOSTFILE 0

; 1行目読み込み
filereadln HOSTLIST HOSTNAME

; サーバ一覧の繰り返し処理
while result = 0
; 空行スキップ
strlen HOSTNAME
if result = 0 goto END
; コメントアウトを判別
strmatch HOSTNAME '^#'
; サブルーチンREWITEを実行
if result <> 1 CALL REWRITE

:END
; サーバ一覧から次のサーバを読み込み
filereadln HOSTLIST HOSTNAME
endwhile

; サーバ一覧ファイルクローズ
fileclose HOSTLIST

; マクロ終了
end
;============================================================

; サブルーチンREWRITE開始
:REWRITE

; 3秒待機
timeout = 3

; 日時の取得
gettime timestr '_%Y%m%d_%H%M%S.log'

; ログファイル名結合
logfilename = HOSTNAME
strconcat logfilename timestr
FULLPATH = LOGPATH
strconcat FULLPATH logfilename

; 踏み台接続
COMMAND = BASTION
strconcat COMMAND ':22 /ssh /2 /auth=password /user='
strconcat COMMAND USERNAME1
strconcat COMMAND ' /passwd='
strconcat COMMAND PASSWORD1

; 接続
connect COMMAND

; プロンプト表示まで待機
wait ']$'

; ログ取得開始
logopen FULLPATH 0 0

; 作業サーバへ接続
SERVERIP = HOSTNAME

COMMAND = 'ssh -o StrictHostKeyChecking=no -o UserKnownHostsFile=/dev/null '
strconcat COMMAND USERNAME2
strconcat COMMAND '@'
strconcat COMMAND SERVERIP

; 作業サーバへ接続
sendln COMMAND

; パスワード入力
wait 'password:'
sendln PASSWORD2

; プロンプト表示まで待機
wait ']$'

; confファイル編集
COMMAND = 'sudo vi '
strconcat COMMAND CONFFILE
sendln COMMAND


; Server=の編集
; /を送る
send '/'
pause 1
; 検索文字へ移動
sendln SEARCHSTR1
pause 1
strlen SEARCHSTR1
; カーソル位置を=まで移動
sendkcode 333 7
pause 1

; DでIPアドレスを削除
send 'D'
pause 1

; aで編集モード
send 'a'
pause 1

; IP入力
send APPENDSTR
pause 1

; エスケープ
send #$1B
pause 1


; ServerActive=の編集
; /を送る
send '/'
pause 1
; 検索文字へ移動
sendln SEARCHSTR2
pause 1
strlen SEARCHSTR2
; カーソル位置を=まで移動
sendkcode 333 13
pause 1

; Dで上書き
send 'D'
pause 1

; aで編集モード
send 'a'
pause 1

; IP入力
send APPENDSTR
pause 1

; エスケープ
send #$1B
pause 1

; Hostname=の編集
; /を送る
send '/'
pause 1
; 検索文字へ移動
sendln SEARCHSTR3
pause 1
strlen SEARCHSTR3
pause 1

; iで編集モード
send 'i'
pause 1

; 先頭に#を記載
send '#'
pause 1

; エスケープ
send #$1B
pause 1

; ファイルを保存して終了
send ':'
pause 1
sendln 'wq!'

; プロンプト表示まで待機
wait ']$'

; Zabbix再起動
sendln 'sudo systemctl restart zabbix-agent'

; プロンプト表示まで待機
wait ']$'

; サービスステータス確認
sendln 'sudo systemctl status zabbix-agent'

; プロンプト表示まで待機
wait ']$'

; サブルーチンREWRITE終了
closett
return
```

# 参考サイト
[TeraTermマクロ－機器情報を自動収集してくれるMACRO](https://www.j-oosk.com/teraterm/macro/256/)
[TeraTermマクロでvi編集 | ESORO system design](https://esoro.jp/?p=750) (本記事投稿時には404 Not Foundになっています)