paramiko-expectでネットワーク機器の情報を取得してみた 

##背景
- ネットワーク機器の情報を自動で取得するプログラムを作りたい
- ログイン時にユーザモードである場合、特権モードに昇格するように対話処理を行う必要がある

なんとなくparamiko-expectを使用してみることにしました。

##実行環境
Python version : 3.6.1
あらかじめpipで`paramiko`と`paramiko-expect`を入れておきます。

ネットワーク機器
- Cisco ISR 891FJ
- IOS : 15.4(3)M1


##コード


```python
import os
import datetime
import paramiko
from paramiko_expect import SSHClientInteraction

def main():
    date = datetime.date.today().strftime("%Y-%m-%d")

    try:
        os.mkdir(str(date))
    except Exception as e:
        print (e)

    commands = ['show version','show running-config']
    host = ['hostname','ipaddress','username','password','EnablePassword']

    correct_log(host,commands,date)


def correct_log(host,commands,date):
    separate = '-------------------------------'
    PROMPT = ['.*>\s*','.*#\s*','Password: ']

    hostname = host[0]
    ipaddress = host[1]
    username = host[2]
    password = host[3]
    EnablePassword = host[4]
    
    
    try:
        client = paramiko.SSHClient()
        client.set_missing_host_key_policy(paramiko.AutoAddPolicy())
    
        client.connect(hostname=ipaddress,username=username,password=password,timeout=10,look_for_keys=False)

        with SSHClientInteraction(client, timeout=30,display=False) as interact:
            interact.send('')
            index = interact.expect(PROMPT)
            
            if index == 0:
                interact.send('enable')
                interact.expect(PROMPT)
                interact.send(EnablePassword)
                index = interact.expect(PROMPT)

                if index == 0:
                    with open(date+"/"+hostname+".txt","a") as config_file:
                        config_file.write('Failed Authentication\n')
                    interact.send('exit')

            interact.send('terminal length 0')
            interact.expect(PROMPT)

            for command in commands:
                if index == 1:
                    interact.send(command)
                    index = interact.expect(PROMPT)
                    output = interact.current_output_clean

                    with open(date+"/"+hostname+".txt","a") as config_file:
                        config_file.write(separate + command + separate + '\n')
                        config_file.write(str(output) + '\n')

            interact.send('exit')
            index = interact.expect()


    
    except Exception as e:
        with open(date+"/"+hostname+".txt","a") as config_file:
            config_file.write(str(e) + '\n')


if __name__ == '__main__':
    main()


```
##補足
`interact.send()`
- リモートホストに文字列を送信します。
　
`index = interact.expect(PROMPT)`
- リモートホストのプロンプトの文字が`PROMPT`のいずれかと一致したらインデックスを返す処理になっています。
- `interact.send()`の結果を待ち受ける処理も含まれています。
　
`SSHClientInteraction(client,timeout=30,display=False)`
- 対話処理をするインスタンスを生成します。
 

paramikoを使用してSSHを行います。

```python
client = paramiko.SSHClient()
client.set_missing_host_key_policy(paramiko.AutoAddPolicy())

client.connect(hostname=ipaddress,username=username,password=password,timeout=10,look_for_keys=False)
```
　
空のコマンドを送っている部分ですが、`interact.send('')`がないと`interact.expect(PROMPT)`の処理が止まることがありました。

```
interact.send('')
index = interact.expect(PROMPT)
```
　
ネットワーク機器にコマンドを送り、出力を受け取っているのは下記の部分です。

```python
interact.send(command)
index = interact.expect(PROMPT)
output = interact.current_output_clean
```

##出力
```:hostname.txt
-------------------------------show version-------------------------------
Cisco IOS Software, C800 Software (C800-UNIVERSALK9-M), Version 15.4(3)M1, RELEASE SOFTWARE (fc1)
Technical Support: http://www.cisco.com/techsupport
Copyright (c) 1986-2014 by Cisco Systems, Inc.
Compiled Sat 25-Oct-14 07:36 by prod_rel_team
・
・
-------------------------------show running-config-------------------------------
Building configuration...
・
・
```