技術を楽しもう!

IT(ネットワーク)業界を中心に、仕事や趣味等、色々な技術を記録します。

ネットワークエンジニアのための自動化入門(Python / REST API等)

https://4.bp.blogspot.com/-d_h8UwEDyfc/WAhyyPS07fI/AAAAAAAA_GQ/uv4gut8QZjI3cjfpss52hiVoZdpuh7O1ACLcB/s550/ai_shigoto_makaseru.png

昔からネットワーク機器を多く相手にしてきたエンジニアは、 CLIで設定を作って投入することが多く、プログラミングが苦手な方が多い印象です。

近頃はネットワークも自動化の波が大きく、 APIによる設定変更に対応している機器も増えてきました。

ネットワークに詳しく、自動化等にも長けたエンジニアは、 現在も希少価値が高い印象ですので、 まず、どんな手法があるのかを知ることから始めてはいかがでしょうか。

はじめに

古くからある手法ですが、Excel関数を駆使してConfigを出力して、 Teratermマクロで投入することも立派なネットワーク自動化(効率化)です。

例えば、下記の記事のようなものです。 itchrome.blogspot.com

ただ、初期構築時ならまだしも、 商用環境の変更用ConfigをTeratermマクロで投入することは反対する人も多いと思います。 CLI操作ができる状態でTeratermマクロが止まれば、誤操作による事故のもとです。

また、Teratermマクロは書式が独特で、古くから存在するマクロは、 修正したくても解析がしにくく、手が付けられない状態になることが多い印象ですし、 〇〇を実行して××行目の値が△△だったら、のような処理を書くのも難しいです。

なので、別の自動化手法が流行っているのだと考えています。

Python

ネットワークの自動化ではPythonが多く使われています。 設定情報のやり取りなどのデータ構造はjson形式が多く使われていますが、 これがPythonの辞書型と書式が同じであるため、データの整形(パース)や、 条件分岐処理をコーディングしやすいというメリットのためと考えられます。

pexpect

pythonライブラリのひとつです。所定のプロンプトを待ち、 決まったコマンドを投入することが主要動作です。 まさにTeratermマクロのような動きをします。 下記は機器にSSHしてenableパスワードを入力し、show versionを表示します。

import pexpect
device ='ssh admin@172.16.1.1'
p = pexpect.spawn(device)

p.expect('Password:')
p.sendline('sshpw')
p.expect('>')

p.sendline('enable')
p.expect('Password:')

p.sendline('enapw')
p.expect('#')

p.sendline('terminal length 0')
p.expect('#')

p.sendline('show version')
p.expect('#')

result = p.after
print(result.decode('utf-8'))

【メリット】作りこもうとすれば何でも作れる
【デメリット】完成まで時間がかかり、保守するのが難しい

netmiko

こちらもpythonライブラリのひとつです。 ネットワーク機器独特の「enableパスワードを入力する」ことも基本機能に含まれているため、 「enable」を入力→「Password:」というプロンプトを待つ→「パスワードを投入する」という処理を書く必要はありません。 コマンド投入完了を自動判定するため、毎回プロンプトを待つ処理を書く必要はありません。

import netmiko
session = netmiko.ConnectHandler(device_type='cisco_ios', host='172.16.1.1', username='admin', password='sshpw', secret='enapw')

session.enable()
result = session.send_command('show version')
print(result)
session.disconnect()

【メリット】 簡易なため、情報収集のみなら便利
【デメリット】出力を整形する必要があるため、条件分岐処理等には不向き

Ansible

Playbookと呼ばれるYAML形式のファイルを使用して動作します。 内部の仕組みとしては、Pythonで作成された各モジュールを使用し、 SSHでネットワーク機器にアクセスして実行されます。

各モジュールは、別途インストールするものではなく、
当該Ansibleのバージョンに含まれていれば、そのまま使えます。 下記はバージョンをチェックする例です。

<認証情報(auth.yml)>

ansible_connection: network_cli
ansible_network_os: ios
ansible_user: admin
ansible_ssh_pass: password

<Playbook>

- hosts: DEVICES
  gather_facts: no
  vars_files:
    - ../vars/auth.yml

  tasks:
    - name: Check Version
      ignore_errors: True
      ios_command:
        commands:
          - "show version"
        wait_for:
          -  result[0] contains "16.9"

昔は対話処理(実行する場合はyを入力してください のような)ができなかったのですが、 「cli_command」というモジュールを使えば対応可能です。

条件分岐についても「when」を使えばできるのですが、 「〇と△の変数が☆で、かつ××の処理が失敗した場合のみ実行」のようなことをやろうとすると、 途端に可読性が悪くなります。 やはりドキュメント化をしっかりすべきかと思います。

  when: (work1_result.failed is defined) and
        (work1_result.failed == true and parameter1 == True and parameter2 != True)

可読性が良いことがウリのように思うのですが、これを悪くしてしまっては本末転倒に思います。

【メリット】 手順書的な内容をシンプルに表記でき、プログラミング要素が少ない
【デメリット】複雑にしすぎると条件分岐が読み取りにくい

REST API (RESTCONF)

これが一番流行っていると思います。 HTTPで情報を取得する方法です。

REST APIは今後RESTCONFに移り変わりつつある流れですが、 Pythonで実行する分には、APIのパスが変わるくらいのはずです。

結果をJSONフォーマットで受け取り、 値に応じてif構文で条件分岐させたりします。

下記はポートチャネルインタフェースの設定値を、 RESTCONFで取得する例です。

import requests

url = "https://192.168.1.1/restconf/data/Cisco-IOS-XE-native:native/interface/Port-channel-subinterface/Port-channel=1.100"

payload={}
headers = {
  'Accept': 'application/yang-data+json, application/yang-data.errors+json',
  'Content-Type': 'application/yang-data+json',
  'Authorization': 'Basic <認証トークンを記載>'
}

response = requests.request("GET", url, headers=headers, data=payload)

print(response.text)

結果

{
    "Cisco-IOS-XE-native:Port-channel": {
        "name": "1.100",
        "encapsulation": {
            "dot1Q": {
                "vlan-id": 100
            }
        },
        "ip": {
            "address": {
                "primary": {
                    "address": "192.168.1.1",
                    "mask": "255.255.255.0"
                }
            }
        }
    }
}

【メリット】 Pythonスクリプトなので何でもできる
【デメリット】機器のAPIドキュメントが少ない場合、試行錯誤が多くなる

Jenkins

直接コマンドを実行しても良いのですが、 Jenkinsを使うとWebブラウザから所定のコマンドを実行できるようです。 今後、学習してみたいと思います。