サーバの運用管理業務では定型作業も少なくないと思うが、その自動化はどうしているだろう。
本番機とかでシェルスクリプトを自由に置けない場合、ターミナルソフト(PuTTY、Tera Term、Rlogin、etc...)が備えるマクロ機能で自動運転するのも良いが、ここではPythonで実現してみようと思う。
よくあるケース
- サーバまたはネットワーク機器(Cisco IOS)でコマンドを実行し、結果をクライアント端末(Windows PC)にダウンロード
- クライアント端末(Windows PC)からファイルをアップロードし、サーバまたはネットワーク機器(Cisco IOS)でコマンドを実行
というケースが殆どではないだろうか。
ここでは後者のサンプルコードを示す。
必要なパッケージ
SSHv2プロトコルのPython実装である Paramiko と scp をクライアント端末に導入する。
サーバの環境変更には厳しいプロジェクトであっても、クライアント端末であれば自由が利く。
pip install paramiko
pip install scp
サンプルコード
ファイルをscpで転送し、sshでコマンドを実行する必要最小限のコード。
パスワード認証方式の場合は、pkey
の代わりにpassword
を指定すること。
import paramiko
import scp
def exec_cmd(cmd, ssh):
print('# ' + cmd)
stdin, stdout, stderr = ssh.exec_command(cmd)
for out_line in stdout:
print(out_line.strip('\n')) # 標準出力
for err_line in stderr:
print(err_line.strip('\n')) # 標準エラー出力
with paramiko.SSHClient() as ssh:
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
pkey = paramiko.RSAKey.from_private_key_file('秘密鍵ファイル') # 今回はパスフレーズ無し
ssh.connect(hostname='192.168.10.1', port=22, username='myuser', pkey=pkey)
with scp.SCPClient(ssh.get_transport()) as scp:
scp.put('foo.csv', '/tmp/foo.csv') # ファイルをアップロード
time.sleep(1) # 念の為、待ち時間を挿入
exec_cmd('./bar.sh /tmp/foo.csv', ssh) # サーバでシェルを実行
おまけ
せっかくPythonで書くのだから、実行結果もメールで自動送信してみよう。
CSVファイルをメールに添付して送信するサンプルコードを示す。
import smtplib
from email import Encoders
from email.mime.text import MIMEText
from email.mime.base import MIMEBase
from email.mime.multipart import MIMEMultipart
from_addr = 'XXXXX@gmail.com'
to_addr = 'YYYYY@aaaaa.co.jp'
bcc_addr = 'ZZZZZ@aaaaa.co.jp' # カンマ区切りで複数指定可
rcpt = bcc_addr.split(',') + [to_addr]
msg = MIMEMultipart()
msg['Subject'] = '【XXサーバ】コマンド実行結果'
msg['From'] = '名無し'
msg['To'] = to_addr
msg.attach(MIMEText('''
関係各位
お疲れさまです。
本日のコマンド実行結果を添付しますのでご確認ください。
'''.strip())
attachment = MIMEBase('application', 'csv') # 添付ファイルの種類に応じて適宜変更すること
file = open('/tmp/results.csv', 'rb+')
attachment.set_payload(file.read())
file.close()
Encoders.encode_base64(attachment)
attachment.add_header('Content-Disposition', 'attachment', filename='results.csv')
msg.attach(attachment)
smtp = smtplib.SMTP('smtp.gmail.com', 587) # Gmailの場合
smtp.starttls()
smtp.login(from_addr, 'password')
smtp.sendmail(from_addr, rcpt, msg.as_string())
smtp.close()