【juniper.junosでNW工事手順自動化】

---juniper.junosを使ってNW工事を自動化---

Junosの設定は、Ansibleの公式ページのJuniperモジュールを利用する方法と、ansible-galaxyJuniper Networksが提供しているjuniper.junosrolesを使う方法がある。

juniper.junosroleを使えばyamlの構文を知らなくてもplaybookをほぼコピぺだけで簡単に作成できる。

juniper.junosでできること

  • OSのインストールとアップグレード
  • Junosのプロビジョニング
  • 変更configのロード、情報の取得、管理対象デバイスのリセット、再起動、シャットダウンなど等

前回netconfを有効化時は、Ansible公式サイトのJuniperモジュールを使ってみたが、工事に必要な機能のほとんどが実装できなかった。

これだとyamlの知識がない、Ansibleのモジュール機能の知識もない、調べる時間もないという場合はハードルが高い。

今回はjuniper.junosroleを使って、知識が無くても簡単に実装できることを確認する。

<<確認内容>>

  • configの投入冪等性を担保できること。
  • 排他的に設定できること。
  • 自装置宛ての通信フィルタがが正しい順序で投入されること。
  • 自装置宛てのフィルタ許可通信の疎通確認ができること。
  • ログ出力設定が確認できること。
  • configの保存とバックアップができること、差分確認できること
  • rollbackで切戻しできること。

<<結果>>

  • 設定モードかオペレーションモードのどちらでコマンドが実行されるかはモジュールにより決まっている。juniper_junos_configは設定を実行するモジュールでデフォルトでcommitまで実施する。juniper_junos_commandsはshow系の確認をする。
  • 冪等性について。mergeでset形式のconfigをlistで指定したところ、set、insert、deactivate は設定後は何度設定してもそのままとなるが、deleteやrenameは初回実行で設定が消えた後は状態で再実行するとエラーになる。
  • 排他制御について。config_modeexclusiveを指定できるので、もし他で設定中のconfigがある場合はcommitせず、以下のエラーが出てfailed終了する。

f:id:pinn38:20190511192652p:plain

  • 通信フィルタがが正しい順序かどうかは設定階層単位で比較する必要がある。自発通信と自側サービスポートの疎通確認はできる。結果NGならfailedとなる。stateなどオプションが無いように見えるのでそれ以外のハンドリングはできない。
  • ログ出力設定、ほか、show系のコマンド出力結果をwhenwait_forで判断させたい。やり方は調査中。
  • configの保存とバックアップは問題なくできる。committedcandidateのconfigをフルまたは、階層単位で取得することができる。
  • rollbackで切戻しはできる。
  • (補足)lineで記載しているCLIのコマンドはnetconfではRPC処理のためパイプでコマンドをつないだ形式では処理できない。(例) > show configuration | display set 等。

<<思ったこと>>

  • ciscoと異なりcommit単位で設定前後のconfigを確認するので分かりやすい。状態確認については、サンプルがなく、show系コマンドの出力結果で変更前、変更後の状態を判断してハンドリングする方法をあれば実装する予定、調査中。
  • 冪等性を担保するならjuniper_junos_configでsetコマンドをlineで入れるのではなく、configファイル単位または設定階層単位(system、interface、snmpなどの階層)でload replace するのがよさそう。

<<通信フィルタ追加工事手順>>

以下のエクセルの工事手順をAnsibleで自動化する

大項目 項番 項目 対象機器 設定/確認コマンド/出力確認
事前確認 1_1 設定モードuser確認 SW user@SW> show system users
fpc0:
--------------------------------------------------------------------------
1:26PM up 185 days, 18:37, 2 users, load averages: 0.00, 0.03, 0.03
USER TTY FROM LOGIN@ IDLE WHAT
NW機器で設定モードのユーザがいないこと
1_2 WEBアクセス有効化設定
無し確認
SW user@SW> show configuration system services
ftp;
telnet;
ssh;
web-managementの出力がないこと
1_3 lo向けアクセスフィルタ
設定前確認
SW user@SW>show configuration firewall family inet filter JUNIPER_Lo
term TELNET {
from {
source-address {
192.168.1.0/24;
}
destination-address {
10.10.10.1/32;
}
destination-port 23;
}
then accept;
}
WEBアクセス
許可フィルタ設定が無いこと
設定 2_1 排他制御して設定モード移行 SW user@SW> configure exclusive
Entering configuration mode
{master:0}
user@SW#
エラーがないこと。設定モードに移行することを以下のプロンプト出力で確認
#
2_2 web-managemen
有効化
SW set system services web-management http port 8888 プロンプト表示のみ確認
2_3 lo向けアクセスフィルタ
設定階層へ移動
SW user@SW# edit firewall family inet filter JUNIPER_Lo
{master:0}[edit firewall family inet filter JUNIPER_Lo]
user@SW#
階層移動後プロンプト表示確認
2_4 lo向けアクセスフィルタ
web-managemen
ICMP
許可
SW user@SW#  ここに以下設定を貼り付け
set firewall family inet filter JUN_Lo term ICMP from protocol icmp
set firewall family inet filter JUN_Lo term ICMP then accept
insert firewall family inet filter JUN_Lo term ICMP before term ALL_discard
set firewall family inet filter JUN_Lo term WEB_MANAGE from destination-port 8888
set firewall family inet filter JUN_Lo term WEB_MANAGE then accept
insert firewall family inet filter JUN_Lo term WEB_MANAGE before term ALL_discard
階層移動後プロンプト表示に戻ること
エラーがないこと
事後確認 3_1 設定差分確認 SW user@SW# show | compare
[edit firewall family inet filter JUN_Lo term ICMP]
+ from {
+ protocol icmp;
+ }
[edit firewall family inet filter JUN_Lo]
term ICMP { ... }
+ term WEB_MANAGE {
+ from {
+ destination-port 8888;
+ }
+ then accept;
---snip---
差分表示が正しいこと
3_2 設定config構文確認 SW user@SW# commit check
configuration check succeeds
configuration check succeeds
表示確認
3_3 commit SW user@SW# commit
configuration check succeeds
commit complete
commit complete
表示確認
3_4 web-managemen設定
config確認
SW user@SW> show configuration system services
ftp;
---snip---
web-management {
http {
port 8888;
}
}
web-management の設定出力があること
3_5 lo向けアクセスフィルタ確認 SW user@SW>show configuration firewall family inet filter JUN_Lo
term ICMP {
from {
protocol icmp;
}
then accept;
}
term WEB_MANAGE {
from {
destination-port 8888;
}
then accept;
---snip---
許可フィルタ設定があること
3_6 web-management
ポート開放確認
SW user@SW>show system connections
---snip---
tcp4 0 0 *.8888 *.* LISTEN
8888コネクションがlitsen又はestablisであること
3_7 ping疎通確認 SW user@SW> ping 192.168.3.218
PING 192.168.3.218 (192.168.3.218): 56 data bytes
64 bytes from 192.168.3.218: icmp_seq=0 ttl=64 time=1.921 ms
64 bytes from 192.168.3.218: icmp_seq=1 ttl=64 time=2.751 ms
ping疎通可能なこと

 ※本手順書は実工事とは関係なく、パラメータはすべてサンプルです。

 

<<playbook>>

 /etc/ansible/Jjunos_command.yml

- hosts: junos
  gather_facts: no
  roles:
    - Juniper.junos  

  tasks:
    - name: getting log but don't display out
      juniper_junos_command:
        commands:
          - "show version"
          - "show interfaces terse"
          - "show system uptime"
          - "show chassis alarms"
          - "show chassis environment"
        formats:
          - "text"
        dest_dir: "./{{ inventory_hostname }}before_log/"
        return_output: false

#    - name: Execute single "show version" command.    
#      juniper_junos_command:    
#        commands: "show version"    
#      register: response    
#
#    - name: Print the sh ver command output  
#      debug:    
#        var: response.stdout    

    - name: commit config
      juniper_junos_config:
        check: true
        diff: true
        commit: true
        config_mode: 'exclusive'
        load: 'merge'
        comment: 'merge from a config'
        lines:
          - 'set system services web-management http port 8888'
          - 'set firewall family inet filter JUN_Lo term ICMP from protocol icmp'
          - 'set firewall family inet filter JUN_Lo term ICMP then accept '
          - 'insert firewall family inet filter JUN_Lo term ICMP before term ALL_discard'
          - 'set firewall family inet filter JUN_Lo term WEB_MANAGE from destination-port 8888'
          - 'set firewall family inet filter JUN_Lo term WEB_MANAGE then accept '
          - 'insert firewall family inet filter JUN_Lo term WEB_MANAGE before term ALL_discard'
#          - 'rename firewall family inet filter JUN_Lo term SSH to term SSH2'
      register: resp_commit 
   
    - name: Print the complete response
      debug:
        var: resp_commit

    - name: Ping to AnsibleController
      juniper_junos_ping:
        dest: "192.168.3.218"
        source: "192.168.3.39"
      register: response

    - name: Print the packet_loss
      debug:
        var: response.packet_loss

    - name: Checking WEB_MANAGE local connectivity
      wait_for: host={{ inventory_hostname }} port=8888 timeout=5
      register: response

    - name: Checking DNS remort connectivity
      wait_for: host=8.8.8.8 port=53 timeout=5
      register: response

    - name: Print the connectivity
      debug:
        var: response

 

<<inventory>>

  /etc/ansible/inventory/junos

[junos]
SW ansible_host=192.168.3.39

[junos:vars]
ansible_ssh_user=hoge
ansible_ssh_pass=1234
ansible_network_os=junos
ansible_connection=netconf
#ansible_connection=local
#ansible_connection=network_cli

 <<実行結果>>

 

[root@hoge ansible]# ansible-playbook -i inventory/junos Jjunos_command.yml 

PLAY [junos] ***********************************************************************************************************************************************************************************

TASK [getting log but don't display out] *******************************************************************************************************************************************************
ok: [SW104]

TASK [commit config] ***************************************************************************************************************************************************************************
changed: [SW104]

TASK [Print the complete response] *************************************************************************************************************************************************************
ok: [SW] => 
  resp_commit:
    changed: true
    diff: |2-
  
      [edit system services]
      +    web-management {
      +        http {
      +            port 8888;
      +        }
      +    }
      [edit firewall family inet filter JUN_Lo]
             term FTP { ... }
      +      term ICMP {
      +          from {
      +              protocol icmp;
      +          }
      +          then accept;
      +      }
      +      term WEB_MANAGE {
      +          from {
      +              destination-port 8888;
      +          }
      +          then accept;
      +      }
             term ALL_discard { ... }
    diff_lines:
    - ''
    - '[edit system services]'
    - +    web-management {
    - +        http {
    - +            port 8888;
    - +        }
    - +    }
    - '[edit firewall family inet filter JUN_Lo]'
    - '       term FTP { ... }'
    - +      term ICMP {
    - +          from {
    - +              protocol icmp;
    - +          }
    - +          then accept;
    - +      }
    - +      term WEB_MANAGE {
    - +          from {
    - +              destination-port 8888;
    - +          }
    - +          then accept;
    - +      }
    - '       term ALL_discard { ... }'
    failed: false
    msg: 'Configuration has been: opened, loaded, checked, diffed, committed, closed.'

TASK [Ping to AnsibleController] ***************************************************************************************************************************************************************
ok: [SW]

TASK [Print the packet_loss] *******************************************************************************************************************************************************************
ok: [SW] => 
  response.packet_loss: '0'

TASK [Checking WEB_MANAGE local connectivity] **************************************************************************************************************************************************
ok: [SW]

TASK [Checking DNS remort connectivity] ********************************************************************************************************************************************************
ok: [SW]

TASK [Print the connectivity] ******************************************************************************************************************************************************************
ok: [SW] => 
  response:
    changed: false
    elapsed: 0
    failed: false
    path: null
    port: 53
    search_regex: null
    state: started

PLAY RECAP *************************************************************************************************************************************************************************************
SW                      : ok=8    changed=1    unreachable=0    failed=0   

 

<<実行時 出力logファイル>>

今回は設定前でのみ取得

[root@hoge SWbefore_log]# pwd
/etc/ansible/SWbefore_log
[root@hoge SWbefore_log]# ls -altr
合計 92
-rw-r--r--   1 root root   523  5月 12 11:31 SW_show_version.text
-rw-r--r--   1 root root  4022  5月 12 11:31 SW_show_interfaces_terse.text
-rw-r--r--   1 root root   375  5月 12 11:31 SW_show_system_uptime.text
-rw-r--r--   1 root root   185  5月 12 11:31 SW_show_chassis_alarms.text
-rw-r--r--   1 root root   831  5月 12 11:31 SW_show_chassis_environment.text


実行ログは/etc/ansible/ansible.cfgで以下に指定
log_path=/etc/ansible/route_test/route.log