paramiko で対話式の処理

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()