てくなべ (tekunabe)

ansible / network automation / 学習メモ

第10回 Jenkins勉強会 の資料まとめ

参加できませんでしたが、2017/7/7 に第10回 Jenkins勉強会が実施されたそうです。 www.meetup.com

資料のまとめた見当たらなかったので、自分で探してこちらにまとめさせていただきます。

www.slideshare.net

www.slideshare.net

www.slideshare.net

www.slideshare.net

www.slideshare.net

www.slideshare.net

speakerdeck.com

ネットワーク自動化の勉強会を開催します(Ansible/SaltStack/Netmiko/NAPALM)

7月と8月にネットワーク自動化の勉強会を開催しますのでご案内いたします。(2回とも同一内容です。)

実施概要

近年、APIに対応していないネットワーク機器でも自動化できる方法が増えてきました。 一方で、「興味はあるけど、試してみる時間も環境もない!」という方も多いのではないでしょうか。

そんな方のために、自動化のためのツールやライブラリを使ってみた所感や、 それぞれの特徴などについてデモを交えながらご紹介します。 自動化ツール導入の参考にして下さい。

取り扱うルーツ

1.構成管理ツール

  • その1:Ansible
  • その2:SaltStack

2.Pythonライブラリ

  • その1:Netmiko
  • その2:NAPALM

※一部デモ実施予定

日時場所などの詳細は以下のconnpassのページをご覧ください。

7/21開催分 詳細

8a1-apc.connpass.com

8/18開催分 詳細

8a1-apc.connpass.com

よろしくお願いいたします。

Python 3 エンジニア認定基礎試験に合格しました

f:id:akira6592:20170612212149p:plain

2017/06/09 に「Python 3 エンジニア認定基礎試験」が開始されました。

www.pythonic-exam.com

6/10に受験して合格しましたので、感想や自分の勉強方法を書きたいと思います。

試験の感想

特にクセもなく、素直な問題が多く、基礎試験という名の通りとだ感じました。 公開されている各分野の出題率を確認するとわかりますが、基礎知識にあたるがよく出題されるようになっています。

勉強方法

利用した教材

試験の認定教材でもある、オライリーの「Pythonチュートリアル 第3版」を利用しました。 www.oreilly.co.jp

Pythonの公式サイトにもPythonチュートリアルのコンテンツがあるのですが、単純に紙が好きなので書籍を購入しました。 なお、書籍が想定しているバージョンは3.5.1です。

勉強の流れ

(1) 書籍の読み込み

Pythonチュートリアル 第3版」を一通り読み込みました。

なお、Pythonチュートリアルは、プログラミングの基礎についてはあまり書かれていません。 そのため、プログラミング自体の経験がない方は、必要に応じてもっと基礎的な内容を ていねいに説明した本を併せて読むほうが勉強を進めやすいかもしれません。

(2) 動作の確認

書籍を読んで気になった箇所はJupyter Notebook(厳密にはAzure Notebooks)に コードと自分用の説明を書いて「動くあんちょこ」としてまとめました。

(3) 問題の作成

まだこの試験対策の問題が見当たらなかったので、自分で問題を作って勉強仲間のコミュニティに出題していました。 正解と不正解の選択肢を考えて作ることで、勘違いしやすい仕様や曖昧な理解の箇所も整理できた気がします。


Pythonの基礎を身に付けるける良いきっかけになったと思います。 PythonにはNAPALMのように開発が活発なネットワーク機器向けのライブラリがありますし、Pythonが読めるとAnsibleの詳細な挙動も読み取れたりするので、今後もPythonとのお付き合いはこれからも続くと思います。

ネットワーク自動化関連の気になる書籍

ネットワーク自動化関連で、気になっている書籍が2つあるのでご紹介します。 どちらも現在のところ2017年8月発売予定となっています。

Network Programmability and Automation: Skills for the Next-generation Network Engineer

https://www.amazon.co.jp/dp/1491931256/

自動化に向けてネットワークエンジニアが身に着けるべきスキルについての書籍。 オライリーのサイトで、Early Release 版がチラ見できます。 https://library.oreilly.com/book/0636920042082/network-programmability-and-automation/toc

「そもそもJSONYAMLとは何か」といった説明もあり、結構基礎的なことも書かれているようです。


Mastering Python Networking

https://www.amazon.co.jp/dp/B06XPQV549/

Python をベースとしたネットワーク自動化についての書籍で、Ansibleについても書かれているようです。

以下引用です。

What you will learn

  • Review all the fundamentals of Python and the TCP/IP suite
  • Use Python to execute commands when the device does not support the API or programmatic interaction > with the device
  • Implement automation techniques by integrating Python with Cisco, Juniper, and Arista eAPI
  • Integrate Ansible using Python to control Cisco, Juniper, and Arista networks
  • Achieve network security with Python
  • Build Flask-based web-service APIs with Python
  • Construct a Python-based migration plan from a legacy to scalable SDN-based netwo

Ansible のフィルターでリストから組み合わせを生成する(combinations, zip, zip_longest)

f:id:akira6592:20170604104846p:plain

■ はじめに

Ansible 2.3 でCombination Filters というリストの組み合わせを生成するフィルターが追加されました。 公式ドキュメントに使用例が載っていますが、いくつか実際に試してみて出力結果を含めて確認します。

Filters — Ansible Documentation

■ combinations で組み合わせを生成する

1つのリストを元に組み合わせを生成します。

使い方

例:リスト[1,2,3,4,5] から2つ選ぶ組み合わせを生成する

- name: give me combinations for sets of 2
  debug: msg="{{ [1,2,3,4,5]|combinations(2)|list }}"

実行結果

"msg": [
    [
        1,
        2
    ],
    [
        1,
        3
    ],
    [
        1,
        4
    ],
    [
        1,
        5
    ],
    [
        2,
        3
    ],
    [
        2,
        4
    ],
    [
        2,
        5
    ],
    [
        3,
        4
    ],
    [
        3,
        5
    ],
    [
        4,
        5
    ]
]

■ zip でリストを統合する

Pythonzip 関数のように、リストから組み合わせを生成します。 2つのリストの長さが異なる場合は、短いほうに合わせられます。

使い方

例:2つのリストが統合する

- name: give me shortest combo of 2 lists
  debug: msg="{{ [1,2,3]|zip(['a','b','c','d','e','f'])|list }}"

実行結果

"msg": [
    [
        1,
        "a"
    ],
    [
        2,
        "b"
    ],
    [
        3,
        "c"
    ]
]

■ zip_longest でリストを統合する

Pythonzip_longest関数のように、リストから組み合わせを生成します。 前述の zip とは異なり、2つのリストの長さが異なる場合は、長いほうに合わせられます。 足りない部分はfillvalueで指定したもので補完されます。

使い方

例:3つのリストを統合し、足りない部分は 'X' で補完する

- name: give me longest combo of 3 lists , fill with X
  debug: msg="{{ [1,2,3]|zip_longest(['a','b','c','d','e','f'], [21, 22, 23], fillvalue='X')|list }}"

実行結果

"msg": [
    [
        1,
        "a",
        21
    ],
    [
        2,
        "b",
        22
    ],
    [
        3,
        "c",
        23
    ],
    [
        "X",
        "d",
        "X"
    ],
    [
        "X",
        "e",
        "X"
    ],
    [
        "X",
        "f",
        "X"
    ]
]

■ さいごに

他の方法で代替できるケースもありそうですが、複雑になる場合はこれらのフィルターを利用するのが便利そうです。

以上です。

Netmikoで 「TELNET」経由のネットワーク機器自動化を試す

■ はじめに

Netmiko とは、Cisco IOS や Juniper Junos などのネットワーク機器にSSHでログインして操作するのを助けてくれるPythonのライブラリです。 例えば、ログインやコンフィギュレーションモードへの移行、ログアウトなどの操作は関数として抽象化されています。 IPアドレスやOSPFの設定など、細かい設定はコマンドを直接指定するタイプです。

github.com

上記リポジトリの説明にはSSH接続と記載されていますが、過去のリリースノート等を確認するとTELNETでも接続できるようです。 今回はCisco IOS機器へのTELNETを試してみます。

[参考] Netmiko 1.0 Release · Issue #245 · ktbyers/netmiko · GitHub

[通常の使い方] Netmiko Quickstart - Network to Code, LLC

【ご注意】
盗聴や改ざん等のセキュリティ上の観点により、
TELNETではなくSSHが推奨されます。
この記事はTELNETを推奨する意図はありません。
ネットワーク自動化系のライブラリやツールは、
CLIはSSH経由のものが多いため「TELNETが可能なものもある」
ということを知識、経験としておさえておくために
検証した結果を記事にしたものです。

■ 準備

Netmiko をインストールします。

pip install netmiko

■ コード

以下の要件のコードを記述します。

  • TELNETでログインして、vlan 1 の description を設定
  • 事前事後で running-config を確認

Netmiko の仕様として、通常通りSSHであれば device_type"cisco_ios" と指定するところ、 "cisco_ios_telnet" と指定するところがポイントです。

from netmiko import ConnectHandler

# デバイスのタイプやIPアドレス、認証情報をディクショナリで定義
cisco = {
    "device_type": "cisco_ios_telnet",
    "ip": "192.168.1.13",        # 接続先のCisco IOS機器
    "username": "testuser",      # ログインユーザー
    "password": "testpassword",  # ログインパスワード
    "secret": "enablepassword"   # enable パスワード
}

# TELNET接続して、コネクションオブジェクトを取得
net_connect = ConnectHandler(**cisco)

# 特権モードへ移行する
net_connect.enable()

print("--- [●事前確認] ---")
# show コマンドを実行
output = net_connect.send_command("show run int vlan 1")
# 結果を出力
print(output)

# 実行したい設定コマンドをリストで定義
lines = ["int vlan 1", "description hogehoge"]
# 設定コマンドを実行(事前のconf tも自動で実行される)
output= net_connect.send_config_set(lines)

print("\n--- [●事後確認] ---")
# show コマンドを実行
output = net_connect.send_command("show run int vlan 1")
# 結果を出力
print(output)

# 切断
net_connect.disconnect()

■ 実行結果

以下のように description が正常に追加されました。

--- [●事前確認] ---
Building configuration...

Current configuration : 77 bytes
!
interface Vlan1
 ip address 10.0.101.1 255.255.255.0
 ip ospf cost 10
end


--- [●事後確認] ---
Building configuration...

Current configuration : 99 bytes
!
interface Vlan1
 description hogehoge
 ip address 10.0.101.1 255.255.255.0
 ip ospf cost 10
end

■ 本当にTELNETか確認

念のため、本当にTELNET接続しているのか確認します。ここでは wireshark でパケットキャプチャして確認します。

※自身の管理下の環境で確認しています。 f:id:akira6592:20170528205334p:plain

さらに 「Follow TCP Stream」で当該TELNETセッションを流れを確認します。

f:id:akira6592:20170528205345p:plain

■ さいごに

Netmiko を利用して、TELNET経由で Cisco IOS 機器へ簡単な設定をすることができました。 ただし、冒頭の注意書きの通りTELNETはセキュリティ観点で推奨されません。 もし、既存の自動化システムの調査していてNetmikoが利用されている場合、SSHだと決めつけずにtelnetかもしれないという確認のきっかけにはなるかと思います。

Ansible の napalm-ansible モジュール群でCisco IOS 機器の様々な情報を取得する

f:id:akira6592:20170527215846p:plain

■ はじめに

マルチベンダー対応のネットワーク機器制御ライブラリのNAPALMには、ansibleと連携するための napalm-ansible というモジュール群があります。 今回はその中の napalm_get_facts というモジュールを利用して Cisco IOS 機器の様々な情報を取得してみます。

[githubリポジトリ]

GitHub - napalm-automation/napalm-ansibleGitHub - napalm-automation/napalm-ansible

[参考情報(Aristaでの例)]

AnsibleとNAPALMの連携を試してみた – ネットワークエンジニアが日々の出来事を語る

なお、標準モジュールである ios_facts を利用する場合は、以下の記事をご参照ください。

tekunabe.hatenablog.jp


■ 準備

NAPALM のインストール

あらかじめ NAPALM をインストールします。

pip install napalm

napalm-ansible モジュール群のダウンロードと配置

git clone https://github.com/napalm-automation/napalm-ansible.git

napalm-automation ディレクトリ配下の library ディレクトリを、作成予定の playbook と同じディレクトリに配置します。


■ 基本情報の取得

まず、基本的な情報を取得してみます。

Playbook

以下のようなplaybook を作成します。ansible.cfg は特に作成していません。

---
- hosts: cisco   # イベントリファイルで定義済み
  gather_facts: no
  connection: local

  tasks:
    - name: get facts from device
      napalm_get_facts:
        hostname: "{{ inventory_hostname }}"
        provider: "{{ cli }}"
      register: result

    - name: debug
      debug:
        msg: "{{ result }}"

  vars:
    cli: # 認証情報
      username: "{{ ansible_user }}"          # ログインユーザー
      password: "{{ ansible_password }}"      # ログインパスワード
      dev_os: "ios"                           # デバイスのOS

なお、napalm_get_facts モジュールには filter オプションがあり、情報取得する対象を指定することができます。 デフォルトは facts となっており、ホスト名やシリアルナンバーなど基本的な情報を取得します。facts 以外については後述します。

実行結果

実行して結果を確認してみます。

[root@localhost ~]# ansible-playbook nf.yml

PLAY [cisco] **********************************************************************

TASK [get facts from device] ******************************************************
ok: [x.x.x.x]

TASK [debug] **********************************************************************
ok: [x.x.x.x] => {
    "changed": false,
    "msg": {
        "ansible_facts": {
            "facts": {
                "fqdn": "csr1.********.com",
                "hostname": "csr1",
                "interface_list": [
                    "GigabitEthernet1",
                    "GigabitEthernet2",
                    "GigabitEthernet3",
                    "GigabitEthernet4"
                ],
                "model": "CSR1000V",
                "os_version": "CSR1000V Software (X86_64_LINUX_IOSD-UNIVERSALK9-M),                                                                        SOFTWARE (fc3)",
                "serial_number": "XXXXXXXXXXX",
                "uptime": 1080,
                "vendor": "Cisco"
            }
        },
        "changed": false
    }
}

PLAY RECAP ************************************************************************
x.x.x.x             : ok=2    changed=0    unreachable=0    failed=0

基本的な情報が取得できました。


■ facts 以外の情報取得方法について

指定できる対象

前述のように filter オプションでは情報取得する対象を指定することができます。 指定できるものは Cisco IOS の場合は以下の通りです。

  • arp_table
  • bgp_neighbors
  • config
  • environment
  • facts
  • interfaces
  • interfaces_counters
  • interfaces_ip
  • lldp_neighbors
  • lldp_neighbors_detail
  • mac_address_table
  • ntp_servers
  • ntp_stats
  • optics
  • snmp_information

指定できる値は、napalm-automation 自身のドキュメントには記述されいませんが、 NAPALM本体の「Getters support matrix」のIOS(今回の場合)の列を見ると分かります。

Supported Devices — NAPALM 1 documentation

例) get_config に対応していれば filterconfig が指定でき、以下のように記述できる。

      napalm_get_facts:
        hostname: "{{ inventory_hostname }}"
        provider: "{{ cli }}"
        filter:
          - "config"

それぞれどのように取得できるのか試します。 ※あまり設定が入っていない機器で試したので情報が少ないです。

arp_table

今回の環境では特に通信していないため空となりました。

"arp_table": []

bgp_neighbors

今回の環境ではBGPは未設定のため空となりました。

"bgp_neighbors": {}

config

running-config が取得できました。

"config": {
                "candidate": "",
                "running": "Building configuration...\n\nCurrent configuration : 39iguration change at 11:25:09 UTC Sat May 27 2017\n!\nversion 16.3\n(略)
}

environment

ハードウェア状況の情報が取得できました。

"environment": {
    "cpu": {
        "0": {
            "%usage": 0.0
        }
    },
    "fans": {
        "invalid": {
            "status": true
        }
    },
    "memory": {
        "available_ram": 1765843468,
        "used_ram": 333704364
    },
    "power": {
        "invalid": {
            "capacity": -1.0,
            "output": -1.0,
            "status": true
        }
    },
    "temperature": {
        "invalid": {
            "is_alert": false,
            "is_critical": false,
            "temperature": -1.0
        }
    }
}

facts

再掲になりますが、ホスト名やシリアルナンバーなどの基本的な情報が取得できました。

"facts": {
    "fqdn": "csr1.********.com",
    "hostname": "csr1",
    "interface_list": [
        "GigabitEthernet1",
        "GigabitEthernet2",
        "GigabitEthernet3",
        "GigabitEthernet4"
    ],
    "model": "CSR1000V",
    "os_version": "CSR1000V Software (X86_64_LINUX_IOSD-UNIVERSALK9-M), SOFTWARE (fc3)",
    "serial_number": "XXXXXXXXXXX",
    "uptime": 1200,
    "vendor": "Cisco"
}

interfaces

インターフェース情報が取得できました。

"interfaces": {
    "GigabitEthernet1": {
        "description": "N/A",
        "is_enabled": true,
        "is_up": true,
        "last_flapped": -1.0,
        "mac_address": "2C:C2:60:XX:XX:XX",
        "speed": 1000
    },
    "GigabitEthernet2": {
        "description": "N/A",
        "is_enabled": true,
        "is_up": true,
        "last_flapped": -1.0,
        "mac_address": "2C:C2:60:XX:XX:XX",
        "speed": 1000
    },
    "GigabitEthernet3": {
        "description": "N/A",
        "is_enabled": true,
        "is_up": true,
        "last_flapped": -1.0,
        "mac_address": "2C:C2:60:XX:XX:XX",
        "speed": 1000
    },
    "GigabitEthernet4": {
        "description": "N/A",
        "is_enabled": true,
        "is_up": true,
        "last_flapped": -1.0,
        "mac_address": "2C:C2:60:XX:XX:XX",
        "speed": 1000
    }
}

interfaces_counters

インターフェースのカウンタ情報が取得できました。

"interfaces_counters": {
    "GigabitEthernet1": {
        "rx_broadcast_packets": 0,
        "rx_discards": 0,
        "rx_errors": 753,
        "rx_multicast_packets": 0,
        "rx_octets": 68538,
        "rx_unicast_packets": 980,
        "tx_broadcast_packets": -1,
        "tx_discards": 0,
        "tx_errors": 0,
        "tx_multicast_packets": -1,
        "tx_octets": 199698,
        "tx_unicast_packets": 1358
    },
    (省略)
    }
}

interfaces_ip

IPアドレスが設定されているインターフェースの情報が取得できました。

"interfaces_ip": {
    "GigabitEthernet1": {
        "ipv4": {
            "10.0.0.51": {
                "prefix_length": 24
            }
        }
    }
}

lldp_neighbors

今回の環境では未設定のため空となりました。

"lldp_neighbors": {}

lldp_neighbors_detail

今回の環境では未設定のため空となりました。

"lldp_neighbors_detail": {}

mac_address_table

今回の環境では未通信のため空となりました。

"mac_address_table": []

ntp_servers

今回の環境では未設定のため空となりました。

"ntp_servers": {}

ntp_stats

今回の環境では未設定のため空となりました。

"ntp_stats": []

optics

今回の環境ではSFP等のスロットはないため空となりました。

"optics": {}

snmp_information

今回の環境では未設定のため特に意味のない値となりました。

"snmp_information": {
    "chassis_id": "%SNMP agent not enabled",
    "community": {},
    "contact": "unknown",
    "location": "unknown"
}

■ さいごに

稼働中のネットワーク機器の情報を収集したいケースは割とよくあると思いますが、自作しなくてもここまでできますので、もし、取得したい情報がこのモジュールで取得できるのであれば、利用してみるのもよいのではないでしょうか。

なお、Ansible を利用せずに、pythonスクリプト中でなるべくパース処理の手間を省きたい場合は、TextFSMというライブラリと ntc-template というテンプレート集を利用するのが良いと思います。 github.com github.com