本記事について
本記事では、Red Hat から提供されている構成管理ツールである Ansible を使用して、ネットワーク機器である Cisco Nexus スイッチのコマンドログを取得しファイルに保存する方法の一例を説明します。
動作確認環境
本記事は以下の環境にて検証した結果に基づき作成されています。
- Ansible 環境
- CentOS Stream release 9
- Python 3.12.6
- pip 24.2
- ansible-core 2.17.4
- Ansible community version 10.4.0
- cisco.nxos 8.1.0
- ターゲット機器環境
- Cisco Nexus 9000v
- NXOS version 9.3(10)
- Cisco Nexus 9000v
前提
本記事では、Cisco Nexus スイッチを Ansible を使用して設定する方法について記載します。Ansible でターゲット機器を操作するためには、Ansible からターゲット機器に対して、SSH 接続できる必要があります。このため、Cisco Nexus スイッチ側では以下の最低限の設定がされていることを前提とします。
- SSHログイン用ユーザの設定
- SSH接続を受け付けるインターフェースのIPアドレス設定
- ルーティング設定(必要な場合)
ここでは Cisco Nexus スイッチ (NXOS 機器) を対象としています。同じ Cisco 機器でも OS の異なる IOS ルータ・スイッチ や ASA 等は対象外となります。
また Ansible では Cisco Nexus スイッチに SSH 接続するための初期設定が完了していることを前提とします。
CentOS Stream 9 での Ansible のインストール方法についてはこちらの記事を参照してください。
想定するネットワーク構成
ここでは以下のようにターゲットとなる Cisco Nexus スイッチと Ansible マシンが L2 ネットワークで接続されている環境で操作を行うことを想定します。
使用する Ansible モジュールと出力イメージ
本記事では Cisco Nexus スイッチのコマンドログを取得するために、cisco.nxos コレクションの nxos_command モジュールを使用します。
cisco.nxos コレクションは、ansible パッケージをインストールするとデフォルトで含まれています。
cisco.nxos コレクションがインストールされているかどうかはansible-galaxy collection list
コマンドで確認できます。以下のようにcisco.nxos
が表示されていればインストールされています。
(venv) [root@CentOSST9 ~]# ansible-galaxy collection list
# /root/venv/lib/python3.12/site-packages/ansible_collections
Collection Version
---------------------------------------- -------
amazon.aws 8.2.1
ansible.netcommon 6.1.3
ansible.posix 1.5.4
ansible.utils 4.1.0
ansible.windows 2.5.0
(中略)
cisco.ios 8.0.0
cisco.iosxr 9.0.0
cisco.ise 2.9.3
cisco.meraki 2.18.1
cisco.mso 2.9.0
cisco.nxos 8.1.0
cisco.ucs 1.11.0
cloud.common 3.0.0
cloudscale_ch.cloud 2.4.0
(以下略)
またログテキストをファイルに保存するために ansible.builtin コレクションの blockinfile モジュールを使用します。nxos_command モジュールで取得されるコマンドログは Nexus スイッチの CLI のプロンプト部分までは含まれず出力ログのみになるため、本記事ではどのコマンドのログなのかが分かりやすいように blockinfile モジュールのマーカー部分に実行コマンドを表示するように設定することにします。
保存されるログファイルの内容は以下のような形式になります。
The hostname is Nexus01.
# =========================== Start: show clock ===========================
"Warning: No NTP peer/server configured. Time may be out of sync.
06:40:24.876 UTC Sun Sep 29 2024
Time source is NTP"
# =========================== End : show clock ===========================
# =========================== Start: show version ===========================
"Cisco Nexus Operating System (NX-OS) Software
TAC support: http://www.cisco.com/tac
(中略)
Active Package(s):"
# =========================== End : show version ===========================
# =========================== Start: show running-config ===========================
"!Command: show running-config
!Running configuration last done at: Sun Sep 29 05:38:13 2024
!Time: Sun Sep 29 06:40:33 2024
version 9.3(10) Bios:version
(以下略)
ログファイルは Playbook を実行するごとに以下のように実行した日付・時刻毎のフォルダ内に保存されるようにします。
log
20240929-151919
1-1_Nexus01_20240929.txt
20240929-152018
1-1_Nexus01_20240929.txt
20240929-152207
1-1_Nexus01_20240929.txt
20240929-154309
1-1_Nexus01_20240929.txt
ログ取得対象コマンドリストの指定方法
本記事では、機器ごとのログ取得コマンドリストをインベントリの中でホストグループ変数としてリスト型変数で指定することとします。ログ取得コマンドリストが同じ機器は同じホストグループに分類します。
インベントリの作成形式として、標準の形式だとリスト型変数の定義に適さないため、本記事ではYAML形式でインベントリを作成することにします。
インベントリの作成
本記事では hosts_nxos_getlog というファイル名でYAML形式のインベントリを作成します。
内容例は以下の通りです。
all:
hosts: #←いずれのホストグループにも属さないホストはこの配下に記載。本例ではこのようなホストとは無し
vars: #←全ホスト共通の変数はこの配下に記載
ansible_connection: ansible.netcommon.network_cli
ansible_network_os: cisco.nxos.nxos
ansible_become: yes
ansible_become_method: enable
fname_prefix: "1-1_" #←保存するログファイル名の頭に付与する文字列を定義
children: #←ホストグループはchildren配下に記載
nxos: #←本例ではnxosという名前のグループを定義
hosts: #←このホストグループに所属するホストはhosts配下に記載
Nexus01: #←個別ホストの定義と、ホスト固有変数の定義
ansible_host: 192.168.75.253
ansible_user: admin
ansible_password: admin
ansible_become_password: "" #←enableパスワードは必要な場合のみ記載
vars: #←ホストグループ変数
cmd_list: #←このホストグループで使用するコマンドリストをリスト型変数で定義
- show clock
- show version
- show running-config
- show inventory
- show environment
- show ip route
このインベントリ例では、「nxos」という名前のホストグループを定義し、ホストグループ内に対象ホストを定義しさらにグループ変数として実行コマンドリストを示すリスト型の変数「cmd_list」を定義しています。上記例ではホストを1台のみ定義していますが、2台以上ターゲット機器がある場合はホストグループを増やしたりグループ内ホストを増やしたりします。
ホストグループ、ホスト、コマンドリスト、ログファイル名接頭辞用変数(fname_prefix)は実行する環境や状況に合わせて変更してください。
Nexus スイッチではデフォルトの設定では特権モードへの移行のための enable パスワードは必要ありませんが、対象 Nexus スイッチにて enable パスワードが必要な設定となっている場合はインベントリで enable パスワードを定義してください。上のインベントリ例ではホスト固有変数として定義している「ansible_become_password:」が enable パスワードに該当します。
ログファイル名接頭辞用変数(fname_prefix)は全ホスト共通変数として定義していますが、機器ごとに変えたい場合は変数の定義位置をグループ変数やホスト変数の位置に変更してください。ログファイル名に接頭辞を付けたくない場合は「fname_prefix: “”」と定義してください。
コマンドリストを示す「cmd_list」の変数名をこの後作成する Playbook で使用します。この変数名は変えることができますが、その場合は Playbook 内で記載する変数名も合わせて変更する必要があります。
Playbook の作成
本記事では nxos_getcmdlog.yml というファイル名で Playbook を作成します。
内容例は以下の通りです。なお、基本的に変数はすべてインベントリで定義する設計にしているので、細かいカスタマイズを必要とする場合以外は以下の内容をそのままコピペで問題ありません。
- name: Get Command Log
hosts: all
gather_facts: no
tasks:
- name: STEP1_Set Date Time
set_fact:
date: "{{ now(False, '%Y%m%d') }}"
datetime: "{{ now(False, '%Y%m%d-%H%M%S') }}"
run_once: true
- name: STEP2_Gather Facts
cisco.nxos.nxos_facts:
gather_subset: min
- name: STEP3_Set File Path
set_fact:
filepath: "./log/{{ datetime }}/{{ fname_prefix }}{{ ansible_net_hostname }}_{{ date }}.txt"
- name: STEP4_Execute Commands
cisco.nxos.nxos_command:
commands: "{{ item }}"
register: command_log
with_items: "{{ cmd_list }}"
ignore_errors: true
- name: STEP5_Create File and Add Hostname
lineinfile:
path: "{{ filepath }}"
line: "The hostname is {{ ansible_net_hostname }}."
create: yes
- name: STEP6_Add Command Log
blockinfile:
path: "{{ filepath }}"
marker: "# {mark}"
marker_begin: "=========================== Start: {{ item.item }} ==========================="
marker_end: "=========================== End : {{ item.item }} ==========================="
prepend_newline: true
block: |
"{{ item.stdout | join('\n') }}"
create: yes
with_items:
- "{{ command_log.results }}"
loop_control:
label: "{{ item.item }}"
when: item.stdout is defined
各タスクの内容は以下の通りです。
- name: STEP1_Set Date Time
- 保存するログファイルパスに使用する現在日時と現在日時・時刻を変数に保存するタスクです
- set_fact:
- 変数を定義することができるモジュールです
- date: “{{ now(False, ‘%Y%m%d’) }}”
- 現在時刻を取得し「YYYYMMDD」形式の日付を格納した変数 date を定義しています
- datetime: “{{ now(False, ‘%Y%m%d-%H%M%S’) }}”
- 現在時刻を取得し「YYYYMMDD-HHMMSS」形式の日付・時刻を格納した変数 date を定義しています
- run_once: true
- この指定により対象ホストが複数ある場合でも最初の1ホストのみに対してのみこのタスクを実行するようになります
- このタスクで取得する現在時刻を保存するファイルパスに使用しますが、機器ごとにこの処理を行うと取得される時刻がずれてファイルパスが機器別に分かれてしまいます。同一フォルダ内に全ログファイルを保存するためにこの指定をしています
- name: STEP2_Gather Facts
- 保存するログファイル名に使用する機器ホスト名を取得するタスクです
- cisco.nxos.nxos_facts:
- Cisco Nexus スイッチから様々な情報を取得することができるモジュールです
- gather_subset: min
- この指定で機器ホスト名を含む情報を取得できます
- ホスト名は変数
ansible_net_hostname
に格納されます
- name: STEP3_Set File Path
- 保存するログファイルパスを変数として定義するタスクです
- set_fact:
- 変数を定義することができるモジュールです
- filepath: “./log/{{ datetime }}/{{ fname_prefix }}{{ ansible_net_hostname }}_{{ date }}.txt”
- Playbook と同フォルダ内に log フォルダを作成し、更にそのフォルダ内に日付時刻を名前としたフォルダを作成して、日付時刻フォルダ内に機器別にログファイルを保存することにしています。このようなファイルパスを格納した変数 filepath を定義しています
- {{ datetime }}と{{ date }}は STEP1 のタスクで定義した日付・時刻の変数です
- {{ fname_prefix }} はインベントリで定義したファイル名接頭辞に該当する変数です
- {{ ansible_net_hostname }} は STEP2 のタスクで取得したホスト名です
- name: STEP4_Execute Commands
- Cisco Nexus スイッチでコマンドを実行するタスクです
- cisco.nxos.nxos_command:
- Cisco Nexus スイッチでコマンドを実行できるモジュールです
- commands: “{{ item }}”
- 実行するコマンドを指定しています。コマンド毎にループ処理としているため“{{ item }}”でコマンドを指定しています
- register: command_log
- コマンドログを含むコマンド実行結果を変数 command_log に保存します
- with_items: “{{ cmd_list }}”
- インベントリで定義したコマンドリストを示すリスト型の変数 cmd_list を使用してループ処理を行っています
- ignore_errors: true
- この指定をすると Playbook 実行時に発生したエラーを無視して処理を実行できます
- コマンドリストとして対象機器で実行できないコマンドが指定されていた場合、cisco.nxos.nxos_command モジュールの結果としてエラーになり、Playbook の処理が停止してしまいます。実行できないコマンドがあった場合でもエラーを無視して処理を続行するためにこの指定をしています
- name: STEP5_Create File and Add Hostname
- ログファイルを作成すると同時にログファイルの一行目にホスト名情報を記載するタスクです
- lineinfile:
- ファイルの行操作ができるモジュールです
- path: “{{ filepath }}”
- 操作対象ファイルのパスを指定しています。filepath は STEP3 で定義した変数です
- line: “The hostname is {{ ansible_net_hostname }}.”
- ホスト名を示す行を対象ファイルに挿入しています。ansible_net_hostname は STEP2 のタスクで取得したホスト名が格納されている変数です
- create: yes
- 指定のパスにファイルが存在しない場合ファイルを新規作成します
- name: STEP6_Add Command Log
- 取得したコマンドログを1コマンド分ずつログファイルに追記するタスクです
- blockinfile:
- ブロック(複数行のテキスト)をファイルに追記できるモジュールです
- path: “{{ filepath }}”
- 操作対象ファイルのパスを指定しています。filepath は STEP3 で定義した変数です
- marker: “# {mark}”
- 追記するブロックの上下に追記されるマーカーの形式を指定しています
- marker_begin: 及び marker_end:
- 追記するブロックの上下に追記されるマーカーの内容を指定しています
- item.item は対象のコマンドを示しています
- prepend_newline: true
- 追記するブロックの上に空白行を挿入しています
- block:
- 追記するブロックの内容を示しています
- item.stdout は対象のコマンドの出力ログを示しています
- join(‘\n’) ログ1行ごとに改行するため指定しています
- create: yes
- 指定のパスにファイルが存在しない場合ファイルを新規作成します
- with_items: – “{{ command_log.results }}”
- command_log は STEP4 のタスクで定義したコマンド実行結果を格納した変数です
- 各コマンドの実行結果は command_log の results 属性内にリストとして格納されているため、このリストを利用してループ処理を行っています
- コマンドログは stdout 属性に格納されるため、block: で item.stdout と指定しています
- 実行コマンドは item 属性に格納されるため、marker_begin: 及び marker_end: で item.item と指定しています
- loop_control:
- label: “{{ item.item }}”
- with_items: でループ処理を行った場合、タスクの実行結果ログとしてループで使用する変数の値(コマンド実行結果情報)が表示されますが、コマンド実行結果情報にはコマンドログがそのまま含まれるため、タスク実行結果ログが非常に長いものになってしまいます。表示されるタスク実行結果ログに表示される変数値を実行コマンドのみにするために loop_control: にて label: “{{ item.item }}” と指定しています
- when: item.stdout is defined
- このタスクの実行条件を item.stdout(コマンド実行ログを格納する属性)が定義されていることとして指定しています
- コマンドリストの中に対象機器で実行できないコマンドが含まれていた場合、stdout 属性は定義されません。stdout 属性は定義されていない状態でこのタスクを実行すると、stdout 属性が存在しないというエラーになり Playbook の処理が停止してしまいます。実行できなかったコマンドについてはログ保存処理をスキップするために when: を指定しています
Playbook の実行
以下コマンドで Playbook を実行します。
- ansible-playbook -i <インベントリ> <Playbook>
以下は実行例です。
(venv) [root@CentOSST9 ansible]# ansible-playbook -i hosts_nxos_getlog nxos_getcmdlog.yml
PLAY [Get Command Log] **********************************************************************************************
TASK [STEP1_Set Date Time] ******************************************************************************************
ok: [Nexus01]
TASK [STEP2_Gather Facts] *******************************************************************************************
ok: [Nexus01]
TASK [STEP3_Set File Path] ******************************************************************************************
ok: [Nexus01]
TASK [STEP4_Execute Commands] ***************************************************************************************
ok: [Nexus01] => (item=show clock)
ok: [Nexus01] => (item=show version)
ok: [Nexus01] => (item=show running-config)
ok: [Nexus01] => (item=show inventory)
ok: [Nexus01] => (item=show environment)
ok: [Nexus01] => (item=show ip route)
TASK [STEP5_Create File and Add Hostname] ***************************************************************************
changed: [Nexus01]
TASK [STEP6_Add Command Log] ****************************************************************************************
changed: [Nexus01] => (item=show clock)
changed: [Nexus01] => (item=show version)
changed: [Nexus01] => (item=show running-config)
changed: [Nexus01] => (item=show inventory)
changed: [Nexus01] => (item=show environment)
changed: [Nexus01] => (item=show ip route)
PLAY RECAP **********************************************************************************************************
Nexus01 : ok=6 changed=2 unreachable=0 failed=0 skipped=0 rescued=0 ignored=0
実行できないコマンドが含まれていた場合、以下のように STEP4 でエラーになりますが処理は続行されます。STEP6 ではエラーになったコマンドについては処理がスキップされます。
(venv) [root@CentOSST9 ansible]# ansible-playbook -i hosts_nxos_getlog nxos_getcmdlog.yml
PLAY [Get Command Log] **********************************************************************************************
TASK [STEP1_Set Date Time] ******************************************************************************************
ok: [Nexus01]
TASK [STEP2_Gather Facts] *******************************************************************************************
ok: [Nexus01]
TASK [STEP3_Set File Path] ******************************************************************************************
ok: [Nexus01]
TASK [STEP4_Execute Commands] ***************************************************************************************
ok: [Nexus01] => (item=show clock)
ok: [Nexus01] => (item=show version)
ok: [Nexus01] => (item=show running-config)
failed: [Nexus01] (item=show hogepiyo) => {"ansible_loop_var": "item", "changed": false, "item": "show hogepiyo", "msg": "show hogepiyo\r\r\n ^\r\n% Invalid command at '^' marker.\r\n\rNexus01# "}
ok: [Nexus01] => (item=show inventory)
ok: [Nexus01] => (item=show environment)
ok: [Nexus01] => (item=show ip route)
...ignoring
TASK [STEP5_Create File and Add Hostname] ***************************************************************************
changed: [Nexus01]
TASK [STEP6_Add Command Log] ****************************************************************************************
changed: [Nexus01] => (item=show clock)
changed: [Nexus01] => (item=show version)
changed: [Nexus01] => (item=show running-config)
skipping: [Nexus01] => (item=show hogepiyo)
changed: [Nexus01] => (item=show inventory)
changed: [Nexus01] => (item=show environment)
changed: [Nexus01] => (item=show ip route)
PLAY RECAP **********************************************************************************************************
Nexus01 : ok=6 changed=2 unreachable=0 failed=0 skipped=0 rescued=0 ignored=1
Playbook 実行後、以下のように実行毎に日時フォルダが作成され、そのフォルダ内に機器別にログファイルが保存されます。
log
20240929-151919
1-1_Nexus01_20240929.txt
20240929-152018
1-1_Nexus01_20240929.txt
20240929-152207
1-1_Nexus01_20240929.txt
20240929-154309
1-1_Nexus01_20240929.txt
参考資料
Ansible 関連記事一覧
- Ansible インストール
- Cisco IOS 操作
- Cisco Nexus スイッチ操作
Amazon アフィリエイトリンク
以下は Amazon アフィリエイトリンクです。インフラエンジニアにそこそこおすすめなアイテムです。
note メンバーシップへの参加もお待ちしています!
【アフィリエイト】おすすめ WordPress テーマ【SWELL】
当サイトでは WordPress テーマとして SWELL を使用しています。以前は無料・高機能テーマとして知られる Cocoon を使用していて Cocoon も使いやすかったのですが、SWELL を使い始めてからは SWELL のほうが圧倒的に使いやすいなと思いました。そして何より読み込み速度が速い。SWELL を使い始めてから、過去の Cocoon のブログを見直したときに「あれ、こんなに表示遅かったっけ?」という感覚になりました。
また SWELL はデフォルトでもオシャレなデザインですが柔軟にカスタマイズすることもでき個性のあるサイトを作成できます。さらにブログパーツや広告タグといった再利用可能なブログの「部品」も作成することができ、ブログ作成効率も高いです。
技術ブログやアフィリエイト等での収益化を見据えたブログの作成に SWELL は最適です。初見では価格が高いなと思うと思いますが、私としては SWELL を採用して良かったしそれ以上の価値があると感じています。
ブログの新設やテーマ変更を考えている人は一度 SWELL を検討してみてください。
以下の画像リンクから詳細な情報を確認できます。
レンタルサーバーを探している人には安定性に定評のあるエックスサーバーをお勧めします。
当サイトもエックスサーバーを使用しています。WordPress のインストールも簡単にできます。
コメント