Qiita Teams that are logged in
You are not logged in to any team

Log in to Qiita Team
Community
OrganizationAdvent CalendarQiitadon (β)
Service
Qiita JobsQiita ZineQiita Blog
Help us understand the problem. What is going on with this article?

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

More than 5 years have passed since last update.

作成経緯

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

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

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

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

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

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

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

実行するシェル

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

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

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

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 "第1引数:拠点名(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部分には無いですが、必要に応じて追加します。

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をコピペして貼るだけです。

hostlist
hoge001.hoge.local
hoge002.hoge.local
hoge003.hoge.local

 実行方法

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

./generate_login_shell.sh aaa

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

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

kirksencho
元北の国のエンジニアです 文系大出身ですが子供の頃からコンピュータが好きでエンジニアの道へ 最初はUNIX上でのC言語で、その後のお仕事は、 Linuxサーバの分子動力学計算専門のPCI-Xボードのデバドラ開発 Android端末初号機のバッテリー等のデバイスドライバ開発 Win端末数千台やクラスターサーバのインフラ構築 Objective-CでiPhoneアプリ開発 等々
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away