paramiko で対話式を処理するにはどうしたら良いのか?
paramiko-pexpect とかを使えば良いのかもしれないが、invoke_shell() 、シェルとして実行する方法で
踏み台の先の telnet 接続してコマンドを流す方法を考えた。
以下の例は最初のSSH接続の後、もう1台 SSH で踏み台に入り、そこで telnet でコマンド実行するサンプル
まずは、最後に使う telnet 接続してコマンド実行するためのクラス・メソッドの定義
expectshell.py
# -*- coding: utf-8 -*- import re class ExpectShell: def __init__(self, client, recvsize=1000): self.size = recvsize self.shell = client.invoke_shell() self.shell.recv(self.size) def send(self, command, until=None): self.shell.send('{}\n'.format(command)) if until==None: return command output = '' while True: output = output + self.shell.recv(self.size).decode('utf-8') if re.search(until, output): break return output
踏み台1→2→ telnet 実行サンプル
踏み台1は、pem 鍵ファイルで接続する。
# -*- coding: utf-8 -*- import paramiko import time from expectshell import ExpectShell jump1_host = '1xx.1xx.1xx.1xx' jump1_user = 'admin' jump1_port = 22 key_file = 'admin.pem' # jump1 client pkey = paramiko.Ed25519Key.from_private_key_file(key_file) jump1Cl = paramiko.SSHClient() jump1Cl.set_missing_host_key_policy(paramiko.AutoAddPolicy()) print("jump1 connecting...") jump1Cl.connect(hostname=jump1_host, port=jump1_port, username=jump1_user, pkey=pkey) print('jump1 connected') (stdin, stdout, stderr) = jump1Cl.exec_command('hostname') time.sleep(1) hostname = stdout.read().decode() print('hostname = %s' % hostname) # jump2 ⇒ jump2 jump2_host = '2xx.2xx.2xx.2xx' jump1 = (jump1_host, jump1_port) jump2 = (jump2_host, 22) transport1 = jump1Cl.get_transport() channel1 = transport1.open_channel("direct-tcpip", jump2, jump1) jump2Cl = paramiko.SSHClient() jump2Cl.set_missing_host_key_policy(paramiko.AutoAddPolicy()) print("jump2 connecting...") jump2Cl.connect(hostname=jump2_host, username='admin', password='XXXXXX', sock=channel1) print('jump2 connected') shell = ExpectShell(jump2Cl) res = shell.send('telnet 3xx.3xx.3xx.33', 'login: ') print(res) res = shell.send('root', 'Password: ') print(res) res = shell.send('XYZ112233', 'Prompt\([0-9]+\)# ') print(res) # telnet 接続して実行したいコマンド res = shell.send('ls -la', 'Prompt\([0-9]+\)# ') print(res) res = shell.send('exit') print(res) jump2Cl.close() jump1Cl.close()