FQDNを羅列したテキストを元に踏み台経由のログインシェルを自動で大量生成するシェル

# 作成経緯

同時に30台以上のサーバの構築依頼等が来た場合、ansible等を導入できない環境では、コンソールでコツコツとコマンド打って設定する訳ですが、一台づつやってたらエライ目に遭います。

なのでMacのiTerm2の機能で全コンソール同時入力モードにして共通設定部分は、30台以上を一回のコマンド入力で設定するとします。
（※ホスト名やIPアドレス等の個別の設定部分は自動で設定するVMware用ツールが既にあるのですが、そのツールが設定できない部分が対象）

それにしても、30台以上にログインする時にいちいち踏み台にログインしてサーバにログインしてなんて手打ちでやってたら、これまたエライ目に遭います。（設定修正が発生してまたログインし直しになった時とか）

なのでそれを全自動でやるログインシェルを作る訳ですが、そのシェルもいちいち手で編集してたら、これまたエライ目に遭います。（もし50台以上あったりしたら、それはもう具合悪くなります）

なので全自動ログインシェルを、これまた全自動で作ってくれるシェルを作りました。

どこまでも自動化して楽したい訳です（笑）

# コードとホストリストのフォーマットなど

## 実行するシェル

ベースとなるシェルに踏み台とサーバのIPアドレスを追記するだけです。
以下は拠点が５つある想定です。

定義部分の、AAA_FUMIにその拠点の踏み台アドレスを記載
AAA_PATHに保存したフォルダ名を記載します。
フォルダはカレントフォルダ直下に予め掘ってある前提です。
BBB以降も同様です。

case文の条件だけベタ書きしちゃってますが、PATHと同じ変数でもいいかもしれません。

```bash:generate_login_shell.sh
#!/bin/sh

# DEFINITION
HOSTLIST="./hostlist"
BASESHELL="./login_base.sh"

AAA_FUMI="xxx.xxx.xxx.xxx"
AAA_PATH="aaa"

BBB_FUMI="xxx.xxx.xxx.xxx"
BBB_PATH="bbb"

CCC_FUMI="xxx.xxx.xxx.xxx"
CCC_PATH="ccc"

DDD_FUMI="xxx.xxx.xxx.xxx"
DDD_PATH="ddd"

EEE_FUMI="xxx.xxx.xxx.xxx"
EEE_PATH="eee"

# ARG CHECK
if [ $# -ne 1 ]; then
    echo "引数の数：$#"
    echo "第１引数：拠点名（aaa,bbb,ccc,ddd,eee）"
    exit 1
fi

echo LOCATION : ${1}

while read line; do
    case "${1}" in
      "aaa" ) cp ${BASESHELL} ./${AAA_PATH}/${line}.sh && \
              sed -i.bak -e '1a\'$'\n'"FUMI=${AAA_FUMI}" ./${AAA_PATH}/${line}.sh && \
              sed -i.bak -e '2a\'$'\n'"SERVER=${line}"$'\n' ./${AAA_PATH}/${line}.sh && \
              rm -f ./${AAA_PATH}/${line}.sh.bak ;;
      "bbb" ) cp ${BASESHELL} ./${BBB_PATH}/${line}.sh && \
              sed -i.bak -e '1a\'$'\n'"FUMI=${BBB_FUMI}" ./${BBB_PATH}/${line}.sh && \
              sed -i.bak -e '2a\'$'\n'"SERVER=${line}"$'\n' ./${BBB_PATH}/${line}.sh && \
              rm -f ./${BBB_PATH}/${line}.sh.bak ;;
      "ccc" )  cp ${BASESHELL} ./${CCC_PATH}/${line}.sh && \
              sed -i.bak -e '1a\'$'\n'"FUMI=${CCC_FUMI}" ./${CCC_PATH}/${line}.sh && \
              sed -i.bak -e '2a\'$'\n'"SERVER=${line}"$'\n' ./${CCC_PATH}/${line}.sh && \
              rm -f ./${CCC_PATH}/${line}.sh.bak ;;
      "ddd" )  cp ${BASESHELL} ./${DDD_PATH}/${line}.sh && \
              sed -i.bak -e '1a\'$'\n'"FUMI=${DDD_FUMI}" ./${DDD_PATH}/${line}.sh && \
              sed -i.bak -e '2a\'$'\n'"SERVER=${line}"$'\n' ./${DDD_PATH}/${line}.sh && \
              rm -f ./${DDD_PATH}/${line}.sh.bak ;;
      "eee" )  cp ${BASESHELL} ./${EEE_PATH}/${line}.sh && \
              sed -i.bak -e '1a\'$'\n'"FUMI=${EEE_FUMI}" ./${EEE_PATH}/${line}.sh && \
              sed -i.bak -e '2a\'$'\n'"SERVER=${line}"$'\n' ./${EEE_PATH}/${line}.sh && \
              rm -f ./${EEE_PATH}/${line}.sh.bak ;;
    esac
done < ${HOSTLIST}
exit
```

## ベースとなるシェル

例によって、expect必須です。
USERとPASSWDにログインアカウントの情報を記載します。

KEYには秘密鍵のパスを記載しますが、私はマックを使用しているので、各踏み台をキーチェーンで覚えさせてしまっています。
なので、-iの鍵指定がspawn部分には無いですが、必要に応じて追加します。

```bash:login_base.sh
#!/bin/sh


USER="hogeinfra"
PASSWD="hogepass"
KEY="/Users/hogehoge/.ssh/id_rsa"

echo "Login to ${SERVER}"

expect -c "
  set timeout -1
  spawn ssh -l ${USER} ${FUMI}

  expect \"Are you sure you want to continue connecting (yes/no)?\" {
      send \"yes\n\"
      expect \"password\"
      send \"${PASSWD}\n\"
  } \"password\" {
      send \"${PASSWD}\n\"
  } \"$ \" {
      send \"date\n\"
  }

  expect \"$ \"
  send \"ssh -l ${USER} ${SERVER}\n\"

  expect \"Are you sure you want to continue connecting (yes/no)?\" {
      send \"yes\n\"
      expect \"Enter passphrase for key\" {
        send \"${PASSWD}\n\"
        expect \"password\" {
          send \"${PASSWD}\n\"
        } \"$ \" {
          send \"date\n\"
        }
      } \"password\" {
        send \"${PASSWD}\n\"
        expect \"$ \"
        send \"date\n\"
      }
  } \"Enter passphrase for key\" {
      send \"${PASSWD}\n\"
      expect \"password\" {
        send \"${PASSWD}\n\"
        send \"date\n\"
      } \"$ \" {
        send \"date\n\"
      }
  } \"password\" {
      send \"${PASSWD}\n\"
      expect \"$ \"
      send \"date\n\"
  } \"$ \" {
      send \"date\n\"
  }

interact
"
```

## ホストリスト

構築依頼が来たら、大概ホスト名一覧みたいなものも貰えるでしょうから、そこからFQDNをコピペして貼るだけです。

```bash:hostlist
hoge001.hoge.local
hoge002.hoge.local
hoge003.hoge.local
```

#　実行方法

aaa拠点に属するサーバのログインシェルを作りたい場合は以下です。

`./generate_login_shell.sh aaa`

引数は一個だけで、拠点名です。
あとは勝手に同じフォルダにあるベースシェルの先頭に追記して指定フォルダにどんどん量産していきます。

私はこのシェルを作ったおかげで、ログインシェル編集地獄から解放されました。