9月 152019
 

わけあって ansible を触るようになりました。ネットワーク機器の設定を自動更新できたら良い感じー。みたいな雰囲気で。

で、話のテンポはサササっと行くのですが、Cisco スイッチとかにアクセスする場合、 ssh ではなく今でも telnet を利用している人(会社)は多いかな?
エッジスイッチなんてのはグローバルアドレスが付いてないので外部から攻撃される心配ないし、パケットをキャプチャされることもないので『telnet でじゅーぶん。』みたいな。

そうなるといつまで経っても telnet を利用してしまうわけですが、 ansible が Cisco のネットワーク機器にアクセスするときには ios_command というモジュールを利用すると便利なのですが、こいつは ssh にしか対応してないので、それを使わず telnet モジュールでシコシコ tasks: を並べていく必要があるんですけども。

以下は telnet モジュールを利用した場合の標準的な playbooks の書き方です。

- name: send configuration commands to IOS
  telnet:
    user: admin
    password: cisco
    login_prompt: "Username: "
    prompts:
      - "[>|#]"
    command:
      - terminal length 0
      - show running-config
      - configure terminal
      - hostname ios01
    register: result

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

 
この通りにやっても動かないことが多々ある。debug: を指定して output の中を見てももーぐちゃぐちゃ。初めて ansible をテスト的に利用してみると

『ansible ってこんなダサいの? perl の Net::Telnet 使ったほうがよっぽどいーじゃん。』

とかになってしまうのであります。

 
ansible の telnet モジュールがまともに動かない。答えを先に書くと、その原因は “#” にあります。

以下、Cisco 機器のネットワークインターフェースの設定だとします。

interface GigabitEthernet4
  description # VLAN1 Network #
 no ip address
!

 
description に “#” を使っていると telnet モジュールはプロンプトだと勘違いして処理がそこで止まります。
show interfaces status や show interfaces description ・ show running-config など何一つまともに動きません。

telnet モジュールの prompts: はプロンプトの “#” のみを見ているのでは無く Cisco ルータから出力された全ての “#” を見て動作しています。ヘボ過ぎる・・。 orz

telnet モジュールを利用した場合、出力された内容に “#” があるとまともに動作しません。ではどうやって対応するか? 以下は Cisco ルータの場合の対応策です。

- name: send configuration commands to IOS
  telnet:
    user: admin
    password: cisco
    login_prompt: "Username: "
    prompts:
      - "[o|)][>|#]"
    command:
      - terminal length 0
      - show running-config
      - configure terminal
      - hostname ios01
    register: result

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

 
prompts: に指定する文字が一文字だからダメで、二文字にマッチさせると何とか無事に動作するようになります。二文字でマッチできない場合はもう一文字追加で;-)。

上記の prompts: の設定では、本スト名が cisco の場合、プロンプトは以下になります。

cisco>
cisco>enable
cisco#
cisco#configure terminal
cisco(coinfig)#interface gigabitEthernet4
cisco(config-if)#

 
つまり、ホスト名の最後の一文字と “#” を組み合わせた “o#” と、いう prompts: 、あと configure terminal 時にはプロンプトの前に “)” がつくので “)#” にマッチするように prompts: を記述します。

これで show running-config したときに設定中に “#” があっても無事に動作するようになります。

 
ansible で telnet モジュールを利用する場合には prompts: に設定した文字列に十分に注意しましょう。 prompts: に指定する文字は register: に出力される前に吸収されてしまいます。