Netmikoを使ってASAコンフィグ変更

#概要
Cisco ASA (ファイアーウォール)のLocal DBにユーザーを登録した時の話。
ユーザー数が多くて、CLIのコマンドをExcelで作ろうかなと思いましたが、せっかくなのでPythonの**Netmiko**モジュール使って登録してみました。

#実行環境
Python 3.8
Cisco ASA 9.8.4

使用するPythonモジュール
・netmiko 3.1.0
・pandas 1.0.3

#フォルダ構成

project/
　├ input
　│　└ user_list 
　├ output　　　
　└ asa_conf.py

**input/user_list**
csv形式のファイルでasa_conf.pyからユーザー情報を読み取ります。

内容↓
username1 , password , group
username2 , password , group 
...

※ヘッダーはつけてません＾＾；

#コーディング

```python
import pandas as pd
import os
import netmiko

cwd = os.path.dirname(os.path.abspath(__file__))
userlist = os.path.join(cwd, r"input\userlist")

#Cisco ASAへの接続情報
asa = {
         "device_type":"cisco_asa",
         "ip":"10.0.1.1",
         "username":"asa_user",
         "password":"asa_pass",
         "secret": "super"
     }

 con=netmiko.ConnectHandler(**asa)
 con.enable()

#ユーザーリストの読み込み
df = pd.read_csv(userlist, header=None, names=("user","pass","group"), sep=",")

#一行ずつ読みこみ
for index,row in df.iterrows():
    data = pd.Series(row, index=["user", "pass","group"])

#変数に代入しコマンドセット作成
    command_set=[
             "username {0} password {1}\n".format(data["user"],data["pass"]),
             "username {0} attributes\n".format(data["user"]),
             "vpn-group-policy {0}\n".format(data["group"]),
             "service-type remote-access\n",
    ]
#デバッグ用
    output = con.send_config_set(cm, exit_config_mode=False)
    print(output)

#接続切断
con.disconnect()

```

#解説

```python
cwd = os.path.dirname(os.path.abspath(__file__))
userlist = os.path.join(cwd, r"input\userlist")
```
user_listファイルの場所を指定しています。
今回のディレクトリ構成を考慮し、１行目で実行ファイルの絶対パス情報から、projectディレクトリまでのパスを取得、2行目で以降、userlistまでのパスを連結しています。


```python
asa = {
         "device_type":"cisco_asa",
         "ip":"10.0.1.1",
         "username":"asa_user",
         "password":"asa_pass",
         "secret": "super"
     }

 con=netmiko.ConnectHandler(**asa)
 con.enable()
```

接続するための情報を辞書型で指定し、接続ハンドラーに渡しています。
Device_Typeは機器に応じたものを指定する必要がありますので以下リンク参照。
[Git-Hub_ssh_dispatcher.py]
https://github.com/ktbyers/netmiko/blob/master/netmiko/ssh_dispatcher.py

#####・ユーザーリスト読み込み
```python
df = pd.read_csv(userlist, header=None, names=("user","pass","group"), sep=",")

for index,row in df.iterrows():
    data = pd.Series(row, index=["user", "pass","group"])
```
pandasを使ってユーザーリストを読み込んでいます。
ファイル内でヘッダーを用意していないので、names引数で読み込むときにヘッダーをつけています。
登録するユーザーごとに登録コマンドを生成する必要があったので、今回は順読みする形で処理をしています。
df.iterrowsを使うと、行データを(index, data)の形式で値を返し、実際の行データを取得するにはpd.serieseを使う必要があります。

#####・コマンドの作成
```python
    command_set=[
             "username {0} password {1}\n".format(data["user"],data["pass"]),
             "username {0} attributes\n".format(data["user"]),
             "vpn-group-policy {0}\n".format(data["group"]),
             "service-type remote-access\n",
    ]
```
実際の行データへのアクセスはdata["index"]で行えるので、コマンドテンプレートをあらかじめ用意しておき、formadメソッドで値を置き換えてます。

#####・コマンド実行
```python
    for cm in command_set:
        output = con.send_config_set(cm, exit_config_mode=False)

```
作成したコマンドをcon.send_config_setで実行しています。ここで**ポイント**なのが、**exit_config_mode=False**とすること。
デフォルトでは１回コマンドを実行するごとにendを実行するようで、各コンフィグレーションモードに以降してから実行する必要があるコマンドはErrorになります。※今回のケースだと、コマンドセットの2行目以降。

#まとめ
とりあえず、あまり時間をかけず、エイヤァで作成したので例外処理はしていません。
今回のようにコマンドが複数行にわたる場合はExcelだと結構面倒くさいイメージなので、その点は解消できるかなと思います。※単純に自分にExcelスキルがないだけ。。。

今回、勉強のためPandasを無理やり使いましたが、csvモジュールでも全く問題ありません。

con.send_config_setはコマンド実行間隔がデフォルト1秒(delay_factorで変更可能)になっていますので対話作業でのツール用途としてはストレスかも。Netmikoではなく、コマンドをファイルに吐き出してTeratermでコマンド流しこむのもありかと思います。

Netmikoのドキュメント
[Nttmiko]https://ktbyers.github.io/netmiko/docs/netmiko/base_connection.html