【自動化】Pythonで複数機器に連続リモートSSH接続【pexpect】

2022-03-13

トパーズ
トパーズ

全国各地の大量のルーターを設定変更したい…

トパーズ
トパーズ

何百台ものサーバーを1人で管理するのがしんどい…

Pythonで全部自動化できるよ。

サファイア
サファイア

メンテナンス作業の際に、ルーターやサーバーの数が多過ぎてお困りだった経験はないでしょうか?

もし数台程度なら、Tera Term等での手動作業でも出来るかもしれません。しかしサービス規模によっては、その管理対象が数百台~数千台ということもあるでしょう。

そうなると人力での作業は現実的に不可能。なぜなら、複数の作業要員と膨大な工数を要するからです。

そこで、各種ツールで作業を自動化するのがトレンド。中でもPythonを用いた自動化ツールの人気が上昇しています。

しかし、Pythonでの「複数機器の作業自動化」はまだあまり情報がないので、自分で作成してみました。

結果、Pythonの「pexpect」ライブラリを使うことで、大量の機器に連続でリモートSSH接続ができました。今後作業対象がどれだけ増えても、全く怖くありません。

この記事をお読みいただければ、遠隔地に設置した多数のルーターやサーバーに対する、リモートSSHログインとメンテナンス作業が、簡単にPythonで自動化できます。

ご注意事項

本記事における自動SSH接続プログラムの実行環境は、Linuxサーバー上での実行を前提としています。windows環境では基本的に動作しませんので、予めご留意ください。

自動化にPythonを使う理由

作業自動化には、主に以下のような手段があります。

  • シェルスクリプト
  • Tera Termマクロ
  • プログラミング言語(Python,Ruby,Perl .etc)

シェルスクリプトやTera Termマクロは、現在も多くのインフラエンジニアが利用中。手軽に使える半面、機能面や長期的な拡張性には物足りなさがあります。

その点で、プログラミング言語は優位です。なぜなら、各種ライブラリ開発やアップデートが盛んに行われているからです。

言語としてのPythonはコードの可読性が高く、難易度的にも初心者が習得しやすい言語と言われます。

プログラマーと比較して、インフラエンジニアは普段コードを書く機会は少ないもの。よって、Pythonはインフラエンジニアとっての作業自動化の手段として、最適な言語だと考えました。

なお、ネットワーク作業自動化に限らず、AIやデータサイエンスや機械学習など先端領域での需要も急速に高まるPython。

インフラエンジニアのキャリアアップに向けて、「Pythonが使える」ということは間違いなく強みになります。

Pythonの入門段階で使った参考書籍

私は「詳細!Python 3 入門ノート」のkindle版を読んで勉強しました。

2017年に刊行された本ですが、数年を経た現在でも売れ続けるPython入門本の名著です。Pythonは人気言語なので多くの入門書が刊行されて来ましたが、長期間に渡って読まれ続けていることが本書のクオリティの高さの裏付け

Amazonレビューは100件をゆうに超え、約半分が星5つの高評価。普段プログラミングをしない私でも、スポンジが水を吸収するかのようにPythonスキルを習得できました。

本書での学びがベースとなったおかげで、ネットワーク作業の自動化プログラムも自力で組むことが出来たと言えます。

電子版のご注意

本書は固定レイアウトで作成された電子書籍のため、使用端末の画面サイズによっては文字が小さくて読めません。

サファイア
サファイア

固定レイアウトは、紙面をそっくりそのまま電子化します。

お読みの際には、「PCのディスプレイ」か「10インチ前後のiPad」を利用してください。その根拠は以下の記事にまとめています。

自動化用Pythonライブラリ

ネットワーク作業が自動化出来る主なPythonのライブラリは、以下の4種類です。

ライブラリ名 特長
pexpect
(ピーエクスペクト)
  • SSHとtelnetのどちらでも接続可能
  • Tera Termマクロと同様に対話的にコマンドを投入
  • コード量は増えるが操作の自由度は高い
  • 動作対象のOSを問わない
  • マイナーなベンダー機器でも動作可能
netmiko
(ネットミコ)
  • SSHでの接続に用いる
  • 単純な操作であれば使いやすい
  • 複雑な操作には向かない
  • 動作対象が主要ベンダー機器のOSに限定
  • マイナーなベンダー機器のOSはサポートしていない
napalm
(ナパーム)
  • SSHでの接続に用いる
  • 使いやすいが可能な操作が限られる
  • 動作対象が一部ベンダー機器のOSに限られる
  • マイナーなベンダー機器のOSはサポートしていない
telnetlib
(テルネットライブ )
or
(テルネットリブ)
  • telnetでの接続に用いる
  • Tera Termマクロと同様に対話的にコマンドを投入
  • telnet接続に限れば使いやすい
  • 動作対象のOSを問わない
  • マイナーなベンダー機器でも動作可能

結論として、「pexpect」を使用しました。

なぜなら、ネットワーク構築作業の現場では必ずしも大手の主要ベンダーの製品が使われているとは限らないからです。

主要ベンダーの製品のみで動作する「netmiko」や「napalm」では、対応できないケースもあると考えました。

あらゆるユースケースを想定して、汎用的に使用できるライブラリが有用と言えます。

pexpectの基本動作

使用するPythonのバージョンはPython3.6で、実行環境のOSはLinuxのCentOS7です。

# python3 --version
# Python 3.6.8

まずpipでpexpectをインストールします。

# pip install pexpect

一般には具体的なプログラムを記述する前段階として、フローチャートを作成します。フローチャートは、プログラムの流れを図解したものです。

フローチャートでは様々な形のアイコンを用いて、実行させたい処理内容を表現します。アイコンの種類はたくさんありますが、以下にて主なアイコンとその処理内容を一覧にしました。

続いてpexpectの基本動作を確認する実行プログラムとして、「pwd_ps.py」を作成します。

pwd_ps.pyの処理内容をまとめたフローチャートは以下の様になります。

pwd_ps.py_フローチャート_処理内容版

pwd_ps.pyのコード内容をまとめたフローチャートは以下の様になります。

pwd_ps.pyのフローチャート:コード版

処理の流れとしては一本道なので、非常にシンプルな動きとなります。

フローチャートを元に、pwd_ps.pyのコードを記述します。

# pexpectをimportする
import pexpect

# rootユーザーに切り替える
p = pexpect.spawn('env LANG=C sudo su -')
p.expect("# ")
print(p.after.decode(encoding='utf-8')) 

# 現在のディレクトリを確認する
p.sendline("pwd")
p.expect("# ")
print(p.before.decode(encoding='utf-8'))
print(p.after.decode(encoding='utf-8')) 


# 実行中のプロセスを一覧表示する
p.sendline("ps")
p.expect("# ")
print(p.before.decode(encoding='utf-8'))
print(p.after.decode(encoding='utf-8')) 

処理内容としては、現在ログイン中のユーザーからrootユーザーに切り替え後、「pwd」と「ps」コマンドを投入し、現在のディレクトリと実行中のプロセスを確認します。

続いて、各コード内容を具体的に解説していきます。

expect関数

カッコ内の文字列を想定して応答を待ち受けます。
p.expect(“# “)ではrootユーザーのプロンプトである「#」の応答を待ち受けています。
「#」の応答が返り次第、次のコマンドの実行に進みます。

sendline関数

カッコ内の文字列を送信します。

p.sendline(“pwd")は「pwd」のコマンドを送信。
p.sendline(“ps") は「ps」のコマンドを送信。

beforeプロパティによる実行結果の出力

beforeプロパティは、expect関数で待ち受ける文字列パターンの直前までの、全てのテキストデータを保持しています。

・print(p.before.decode(encoding=’utf-8′))


print関数とbeforeプロパティを組み合わせることで、sendline関数実行後から、expect関数実行前までの出力結果が表示されます。プロンプト「#」は含まれません。

afterプロパティによる実行結果の出力

afterプロパティは、 expect関数で待ち受ける文字列パターンに一致したテキストデータを保持しています。

・print(p.after.decode(encoding=’utf-8′)


print関数とafterプロパティを組み合わせることで、expect関数で待ち受けたプロンプト「#」が出力結果として表示されます。

プログラムの実行結果

「pwd_ps.py」 を実行すると、以下のような出力が返ります。

「hostname」とディレクトリの部分は、使用環境に応じて読み替えて下さい。

# 
pwd
/root
[root@hostname ~]
# 
ps
  PID TTY          TIME CMD
32182 pts/6    00:00:00 sudo
32184 pts/6    00:00:00 su
32185 pts/6    00:00:00 bash
32200 pts/6    00:00:00 ps
[root@hostname ~]
# 

beforeとafterの使い分けはややこしい…

トパーズ
トパーズ

補足として、beforeプロパティとafterプロパティが保持するデータの違いが分かりやすい様に、実行プラグラムにコメント記載した「#出力結果1~5」に対して、プログラムの実行結果の各出力内容を「#出力結果1~5」に紐づけました。

beforeとafterで出力させたい内容を具体的に意識しながら、コードを作成してください。

# pexpectをimportする
import pexpect

# rootユーザーに切り替える
p = pexpect.spawn('env LANG=C sudo su -')
p.expect("# ")
print(p.after.decode(encoding='utf-8')) #出力結果1

# 現在のディレクトリを確認する
p.sendline("pwd")
p.expect("# ")
print(p.before.decode(encoding='utf-8')) #出力結果2
print(p.after.decode(encoding='utf-8')) #出力結果3


# 実行中のプロセスを一覧表示する
p.sendline("ps")
p.expect("# ")
print(p.before.decode(encoding='utf-8')) #出力結果4
print(p.after.decode(encoding='utf-8')) #出力結果5
# ⇒出力結果1
pwd ⇒出力結果2
/root ⇒出力結果2
[root@hostname ~] ⇒出力結果2
# ⇒出力結果3
ps ⇒出力結果4
  PID TTY          TIME CMD ⇒出力結果4
32182 pts/6    00:00:00 sudo ⇒出力結果4
32184 pts/6    00:00:00 su ⇒出力結果4
32185 pts/6    00:00:00 bash ⇒出力結果4
32200 pts/6    00:00:00 ps ⇒出力結果4
[root@hostname ~] ⇒出力結果4
# ⇒出力結果5

SSH接続と設定自動化

次に、いよいよ自動でSSHログインをします。pexpectライブラリの「pxssh」モジュールを使います。

ご注意

pxsshモジュールはwindows環境では基本的に非対応のため、importエラーとなります。

以降の記事は、Linux環境でのプログラム実行を前提としています。

もし自宅で学習するような場合には、独自にLinux上でPythonが動作する環境をご用意ください。

AWS等のクラウドサービスなら、手軽にLinuxサーバーのインスタンスを作成できるのでおススメです。

最低限必要となるのは、以下2つのサーバーです。

  • Pythonプログラムの実行サーバー:SSHで接続する
  • SSHサーバー:SSHで接続される

例えばAWSサービスのLightsailなら、1台当たり月額500円弱でLinuxサーバーを構築できます。

もし無料期間が経過してしまった方でも、不要になった段階でインスタンスを削除すれば大して課金はされません。

AWSのクラウド環境下でのLinuxサーバーの知見も高まるので、インフラエンジニアとしての成長にも繋がり一石二鳥です。

サファイア
サファイア

Lightsailは月額利用料金が定額なので、普通に使えば高額課金の心配もありません。

事前準備

SSHで接続される側のノードでは、事前にSSHサーバーとしての設定が必要です。
具体的には、パスワード認証を許可する設定一般ユーザーの作成をしておきます。

未設定の場合は、事前に以下のサイトを参照してご準備下さい。

・外部サイト(Qiita):CentOS7.3でSSH接続(パスワード認証)する方法
 └SSHの設定
 └サービスの起動
 └一般ユーザーの作成

元々SSHサーバーとして起動済みだった場合には、以下のコマンドでsshd.serviceを再起動することで、設定変更を有効にしてください。

# systemctl restart sshd.service

実行プログラム

続いて、任意のSSHサーバーに接続した後に、対話的にコマンドを投入する実行プログラム として、「 ssh_test.py 」を作成します。

ssh_test.pyの処理内容をまとめたフローチャートは以下の様になります。

ssh_test.pyのフローチャート:処理内容版

ssh_test.pyのコード内容をまとめたフローチャートは以下の様になります。

ssh_test.pyのフローチャート:コード版

1つ目のプログラムと同様に、一本道の処理でループや条件分岐はありません。

フローチャートを元に、ssh_test.pyのコードを記述します。

# pexpectライブラリからpxsshモジュールをインポート
from pexpect import pxssh
# timeモジュールをインポート
import time

# ログイン情報を設定しSSHサーバーにログイン
ssh = pxssh.pxssh()
ssh.login(server="x.x.x.x", #接続したいSSHサーバーのIPを記述
          username="testuser", #SSHサーバー側のユーザー名を記述
          password="xxxxxxxx") #SSHサーバー側のユーザーのパスワードを記述
print(ssh.after.decode(encoding='utf-8'), flush=True) #出力結果1

# テキストファイル「test.txt」を作成する
ssh.sendline("touch test.txt")
ssh.expect(r"\[.*\]\$ ")
print(ssh.before.decode(encoding='utf-8'), flush=True) #出力結果2
print(ssh.after.decode(encoding='utf-8'), flush=True) #出力結果3
time.sleep(1)

# カレントディレクトリのファイルを表示する
ssh.sendline("ls -l")
ssh.expect(r"\[.*\]\$ ")
print(ssh.before.decode(encoding='utf-8'), flush=True) #出力結果4
print(ssh.after.decode(encoding='utf-8'), flush=True) #出力結果5
time.sleep(1)

# SSHサーバーからログアウト
ssh.logout()
ssh_test.py:2行目

from pexpect import pxssh

「pxssh」はpexpectライブラリを拡張し、SSH接続に特化した機能を有するモジュールです。

SSHによるログインとログアウト、および接続先ノードのプロンプトを待ち受けるメソッドを追加します。

ssh_test.py:7行目

ssh = pxssh.pxssh()

ssh = pxssh.pxssh()では、pxsshモジュールのpxsshクラスから「ssh」というインスタンスを作成しています。

このsshインスタンスから各種関数を呼び出すことにより、目的となる作業を実行していきます。

ssh_test.py:8行目

ssh.login()

ssh.login()でsshインスタンスからlogin関数を呼び出し、作業対象のSSHサーバーにログインします。

カッコ内の引数には、接続先情報としてIPアドレスとユーザー名とパスワードを設定します。

ここではあらかじめSSHサーバー側にて、ユーザー名「testuser」でユーザーを作成しておきました。

IPアドレスとパスワードは伏字にしているので、ご利用環境に応じて読み替えて下さい。

ssh_test.py:11行目他

print(ssh.after.decode(encoding=’utf-8′), flush=True)

print関数には「flush」オプションを追加しています。

flush=Trueとすることにより、CLI上でプログラム実行中の出力結果が即時表示されます。

つまり、プログラムの進捗を逐次確認するための機能となります。

これを追加しないと、全ての処理が完了してから結果が表示されます。

ssh_test.py:18行目他

time.sleep(1)

timeモジュールのsleep関数にてカッコ内の引数で指定した秒数の間、実行中のプログラムの処理を一時停止できます。

もし設定しない場合、CLIの表示が速過ぎて目で追うことが困難となります。

そのため、time.sleep(1)を挿入することで敢えて1秒間のインターバルを設けています。

ssh_test.py:28行目

ssh.logout()

logout関数を呼び出してexitを送信し、SSH接続先からログアウトしてプログラムを終了します。

プログラムの実行結果

「ssh_test.py」 を実行すると、以下のような出力が返ります。

[PEXPECT]$ 
touch test.txt

[PEXPECT]$ 
ls -l
total 0
-rw-rw-r--. 1 testuser testuser 0 Dec  3 23:12 test.txt

[PEXPECT]$ 

touch test.txtのコマンド実行により、testuserを所有者としてtest.txtが作成されています。

ここでは非常に単純なコマンドを用いましたが、要件に応じてより複雑な処理を対話的に行うことができます。

この自由度の高さが、pexpectのメリットと言えるでしょう。

ここでもbeforeプロパティとafterプロパティの具体的な出力内容が分かりやすい様に、実行プログラムの出力結果1~5と照らし合わせます。

[PEXPECT]$ ⇒出力結果1
touch test.txt ⇒出力結果2

[PEXPECT]$ ⇒出力結果3
ls -l ⇒出力結果4
total 0 ⇒出力結果4
-rw-rw-r--. 1 testuser testuser 0 Dec  3 23:12 test.txt ⇒出力結果4

[PEXPECT]$ ⇒出力結果5

複数機器に自動で連続SSH接続

最後に、ループ処理により複数機器に対して順にSSHログインし、対話的にコマンドを投入する実行プログラムを作成します。

プログラム名は「ssh_loop_multi_node.py」とします。

処理内容をまとめたフローチャートは以下の様になります。分かりやすい様に、関数定義部分とループ処理部分の2つに分けました。

フローチャート①で定義した関数をフローチャート②のループ内で呼び出して、目的の作業を実行する流れです。

ssh_loop_multi_node.pyのフローチャート:処理内容版①
ssh_loop_multi_node.pyのフローチャート:処理内容版②

コード内容をまとめたフローチャートは以下の様になります。

なお、出力表示に関する記述は、煩雑さを避けるために敢えて割愛しています。

ssh_loop_multi_node.pyのフローチャート:コード内容版①
ssh_loop_multi_node.pyのフローチャート:コード内容版②

これまでのプログラムとは違い、フローチャート②ではループと定義済み処理の記号が登場しました。

この2つの要素を利用することで、複数機器に対する連続自動SSHログインを簡潔かつ効率良く実現できました。

ここまでのフローチャートを元に、ssh_loop_multi_node.pyのコードを記述します。

# pexpectライブラリからpxsshモジュールをインポート
from pexpect import pxssh
# timeモジュールをインポート
import time

# 作業内容をssh_work関数として定義
def ssh_work(ip_address, username, password):

    # ログイン情報を設定しSSHサーバーにログイン
    ssh = pxssh.pxssh()
    ssh.login(ip_address, username, password)
    print(ssh.after.decode(encoding='utf-8'), flush=True)

    # ログイン先のグローバルIPを表示
    ssh.sendline("curl inet-ip.info")
    ssh.expect(r"\[.*\]\$ ")
    print(ssh.before.decode(encoding='utf-8'), flush=True)
    print(ssh.after.decode(encoding='utf-8'), flush=True)
    time.sleep(1)

    # ログイン先のプライベートIPを表示
    ssh.sendline("ip -4 a")
    ssh.expect(r"\[.*\]\$ ")
    print(ssh.before.decode(encoding='utf-8'), flush=True)
    print(ssh.after.decode(encoding='utf-8'), flush=True)
    time.sleep(1)

    # ログイン先のユーザー情報を表示
    ssh.sendline("id")
    ssh.expect(r"\[.*\]\$ ")
    print(ssh.before.decode(encoding='utf-8'), flush=True)
    print(ssh.after.decode(encoding='utf-8'), flush=True)
    time.sleep(1)

    # テキストファイル「test.txt」を作成
    ssh.sendline("touch test.txt")
    ssh.expect(r"\[.*\]\$ ")
    print(ssh.before.decode(encoding='utf-8'), flush=True)
    print(ssh.after.decode(encoding='utf-8'), flush=True)
    time.sleep(1)

    # カレントディレクトリのファイルを表示
    ssh.sendline("ls -l")
    ssh.expect(r"\[.*\]\$ ")
    print(ssh.before.decode(encoding='utf-8'), flush=True)
    print(ssh.after.decode(encoding='utf-8'), flush=True)
    time.sleep(1)

    # SSHサーバーからログアウト
    ssh.logout()
    print("Logged out \n")


# 「各リストからのログイン情報読み込み」と「ssh_work関数の実行」をループ処理
with open('ip_list.txt') as ip_list, \
        open('user_list.txt') as user_list, \
        open('pw_list.txt') as pw_list:
    for ip, user, pw in zip(ip_list, user_list, pw_list):
        ssh_work(ip, user, pw)

次に、具体的なコード内容を解説していきます。

ssh_loop_multi_node.py :7行目

def ssh_work(ip_address, username, password):

まず始めに、作業内容をssh_work関数として定義します。

仮引数にはSSH接続先のログイン情報として、以下の3つを指定しています。

  • ip_address
  • username
  • password

実引数や具体的なデータの参照元は55行目以降で指定しており、詳細は後述します。

ssh_loop_multi_node.py :11行目

ssh.login(ip_address, username, password)

ssh_work関数から実引数で渡されるログイン情報を用いて、作業対象のSSHサーバーに接続します。

ssh_loop_multi_node.py :15行目

ssh.sendline(“curl inet-ip.info")

SSHで接続したノードのグローバルIPを表示するコマンドを送信します。

接続中の作業対象が間違いないかを確認する意図となります。

※プライベートIPで接続する場合は特段不要なコマンドです。

ssh_loop_multi_node.py :22行目

ssh.sendline(“ip -4 a")

SSHで接続したノードのプライベートIPを表示するコマンドを送信します。

接続中の作業対象が間違いないかを確認する意図となります。

「ip a」だけでは表示される情報がやや多いので、「-4」オプションを付加してIPv4の情報だけを表示させます。

※グローバルIPで接続する場合は特段不要なコマンドです。

ssh_loop_multi_node.py :29行目

ssh.sendline(“id")

コマンドを実行したユーザーのIDやユーザー名を表示します。

接続中のユーザーが間違いないかを確認する意図となります。

ssh_loop_multi_node.py :55~57行目

with open('ip_list.txt’) as ip_list, \
open('user_list.txt’) as user_list, ¥
open('pw_list.txt’) as pw_list:

※「¥」はバックスラッシュと読み替え下さい。

ログイン情報を3つのテキストファイルから読み込むため、with構文とopen関数を使います。

55行目でいうと、openで「ip_list.txt」ファイルを開き、asでそのファイルを「ip_list」という名前で変数として使えるようにしています。

with構文により、本来必要なファイルを閉じる処理の記述が不要となるので、不用意なエラーが回避しつつコードの簡略化が可能です。

カンマとバックスラッシュで区切ることで、複数のファイルを同時並行でopenできます。

なお事前準備として、上記コードのカッコ内の3ファイルをPythonの実行ファイルと同じディレクトリに作成して下さい。

各ファイルには、作業対象の各ログイン情報が同じ行で対応するように、IPとユーザー名とパスワードを記述します。

ip_list.txtには、各SSHサーバーのIPアドレスを記述します。複数台の作業ということで、IPアドレスは2つです。

ここでは伏字としますが、グローバルIPという想定です。実際には正しいIPアドレスを記述してください。

x.x.x.x
y.y.y.y

user_list.txtには各SSHサーバーのユーザー名を記述します。

もしSSHサーバー側でユーザーが未作成の場合は、事前に作成しておきましょう。

ここでは仮にtestuser1とtestuser2としていますが、実際には正しいユーザー名を記述してください。

testuser1
testuser2

pw_list.txtには各SSHサーバーのパスワードを記述します。

ここでは伏字としますが、実際には正しいパスワードを記述して下さい。

XXXXXXXX
YYYYYYYY
ssh_loop_multi_node.py :58行目

for ip, user, pw in zip(ip_list, user_list, pw_list):

前項の処理で変数化された3つのログイン情報をfor文で1つずつ取り出します。

複数の変数を1行のfor文でまとめて取得するために、zip関数を使います。

zip()のカッコ内の3つの要素から、ipとuserとpwを1セット取り出すようなイメージです。

各テキストファイルの上から順番に1セットずつ取り出すので、接続先の機器間でログイン情報の食い違い等は発生しません。

ssh_loop_multi_node.py :59行目

ssh_work(ip, user, pw)

7行目で定義したssh_work関数をfor文のブロックの中で実行してループさせます。

ループは処理は、3つのテキストファイルの最後の行を読み込むまで実行されます。

ssh_work関数のカッコ内には実引数を設定します。

実引数には、直前のfor文で取り出したログイン情報のセットである、以下の3つの変数を設定してください。

  1. ip
  2. user
  3. pw

この3つの実引数が、プログラム7行目の仮引数に渡され、プログラム11行目のlogin関数でSSH接続が実施されます。

プログラムの実行結果

「ssh_loop_multi_node.py」 を実行すると、以下のような出力が返ります。

[PEXPECT]$ 
curl inet-ip.info
x.x.x.x

[PEXPECT]$ 
ip -4 a
1: lo: #中略
2: eth0: #中略

[PEXPECT]$ 
id
uid=1003(testuser1) gid=1003(testuser1) groups=1003(testuser1) context=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023

[PEXPECT]$ 
touch test.txt

[PEXPECT]$ 
ls -l
total 0
-rw-rw-r--. 1 testuser1 testuser1 0 Dec  6 13:51 test.txt

[PEXPECT]$ 
Logged out 

[PEXPECT]$ 
curl inet-ip.info
y.y.y.y

[PEXPECT]$ 
ip -4 a
1: lo:  #中略
2: eth0: #中略 

[PEXPECT]$ 
id
uid=1001(testuser2) gid=1001(testuser2) groups=1001(testuser2) context=unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023

[PEXPECT]$ 
touch test.txt

[PEXPECT]$ 
ls -l
total 0
-rw-rw-r--. 1 testuser2 testuser2 0 Dec  6 13:51 test.txt

[PEXPECT]$ 
Logged out 

まず、グローバルIPがx.x.x.xのtestuser1のサーバーにログインできていることが、各確認コマンドから分かります。

テキストファイルの作成が、testuser1を所有者として出来ていることも確認できます。

次に、グローバルIPがy.y.y.yのtestuser2のサーバーにログインできています。

こちらも同様に、testuser2を所有者としてテキストファイルの作成が出来ています。

目的とする動作が問題なく出来ていることが確認出来ました。

実務では、作業を要するノードの数だけ、ログイン情報のテキストファイルに情報を記載して下さい。

作業内容は多岐に渡ると推察されますが、pexpectの各種関数を組み合わせれば大抵の処理は可能です。

まとめ

この記事では、Pythonを使っての複数ノードに対する自動ログインと設定投入の方法を紹介しました。

Pythonはプログラミング入門として学習しやすいオススメの言語です。

作業の自動化は業務効率改善に直結するので、現場でも非常に重宝されるスキルです。

ぜひ自動化技術を習得して、チームに貢献できるエンジニアを目指しましょう。

併せて読みたい記事

サブスクの読み放題サービスAmazon Kindle Unlimitedにて、ITエンジニアが読める本をまとめました。Pythonのおススメ学習書もあります。