LoginSignup
7
8

More than 5 years have passed since last update.

Ruby/XMPPでCiscoルータとチャットしてみた

Posted at

はじめに

この記事はNetOpsCoding Advent Calendar 2015 の17日目の記事です。ネットワークプログラマビリティ勉強会 #6ルータとチャットしてみましたに触発され、Ruby/XMPPでCiscoルータとチャットしてみました。
chat1.png

概要

インスタント・メッセンジャープロトコルのXMPPを用いて、Ciscoルータ1台毎にアカウントを作成して、チャットしてみました。環境は下記のとおりです。XMPPサーバ、XMPPクライアント、XMPPボットはローカルホスト上で動作させるため、アカウントのドメイン名は@localhostで統一しています。

構成図.png

  • XMPPサーバ:Openfire in Ubuntu 15.04
  • XMPPクライアント:Empathy(GNOMEのインスタント・メッセンジャー)
  • XMPPボット:自作Rubyスクリプト(xmpp4rとexpect4rライブラリを使用)
  • Ciscoルータ:Cisco1812J 2台

XMPPサーバ

XMPPサーバはDockerコンテナ上に構築しました。Dockerfilesameersbn/openfire:3.10.3-1を利用させていただきました。セットアップ方法については割愛します。利用した機能はUsersとGroupsのみです。今回はGroup Chatは利用していません。

openfire.png

アカウント

アカウントについては下記の通り管理者ユーザのadminと、Ciscoルータを示すr1とr2のアカウントを作成しました。Routersグループを作成し、すべてのアカウントを所属させています。これにより連絡先リストを共有することができます。

  • admin@localhost - XMPPクライアントを起動するためのアカウント
  • r1@localhost/bot - CISCOルータ R1
  • r2@localhost/bot - CISCOルータ R2

XMPPクライアント

XMPPクライアントはUbuntuに標準で付いているインスタント・メッセンジャーアプリのEmpathyを利用しました。下記の通り、adminアカウントでログインすると、2台のルータが連絡先リストに出現します。アカウントのアイコンはEmpathyに手動で登録しました。アイコンはCiscoのアイコンを利用しています。
empathy.png

XMPPボット

XMPPボットはRuby2.2.3で作成しました。ライブラリは下記を使用して実装しています。スクリプトのほとんどは各ライブラリのサンプルを用いて実装しています。

  • xmpp4r:XMPP用ライブラリ
  • expect4r:Ciscoルータ接続用ライブラリ

スクリプト

bot.rbが実行ファイルです。HOSTS変数に配列でアカウント名とルータのIPアドレスを登録しています。USERNAMEPASSWORDENABLE_PASSWORDはCiscoルータにTELNETする際のログイン情報を設定します。BOT_PASSWORDはXMPPサーバに登録されたアカウントのパスワードを示します。

スクリプトの動作は単純です。ルータごとにBotクラスのstartメソッドが実行され、XMPPサーバと接続し、XMPPクライアントからのメッセージを待ち受けします。XMPPクライアントからメッセージを受信するとon_message_callbackメソッドが実行されます。メソッド内でshow、ping、traceから始まるメッセージはコマンドと解釈して、ルータでコマンドを実行し、その実行結果をXMPPクライアントに返信しています。reply_cmdメソッドがルータにTELNETしてコマンドを実行しています。実行した結果はreplyメソッドで、送信元のXMPPクライアントに返信します。

bot.rb
require 'xmpp4r'
require 'expect4r'
require 'logger'

Log = Logger.new(STDOUT)
Log.level = Logger::DEBUG

HOSTS = [
  %w(R1 192.168.88.101),
  %w(R2 192.168.88.102)
]
USERNAME        = 'cisco'
PASSWORD        = 'cisco'
ENABLE_PASSWORD = 'cisco'
BOT_PASSWORD    = 'cisco'

# Bot for Cisco IOS
class Bot
  def initialize(host, ipaddr)
    @host = host
    jid = Jabber::JID.new("#{host}@localhost/bot")
    @client = Jabber::Client.new(jid)
    @ios = Expect4r::Ios.new_telnet(
      host: ipaddr,
      user: USERNAME,
      pwd: PASSWORD,
      enable_password: ENABLE_PASSWORD
    )
  end

  def start
    Log.info "#{@host} starting"
    @client.connect
    @client.auth(BOT_PASSWORD)
    @client.send(Jabber::Presence.new.set_show(:chat).set_type(:available))
    @client.add_message_callback(&method(:on_message_callback))
  end

  def reply(msg, reply_content)
    reply_msg = Jabber::Message.new(msg.from, reply_content)
    reply_msg.type = msg.type
    @client.send(reply_msg)
  end

  def reply_cmd(msg, cmd)
    Thread.new do
      begin
        Log.debug "#{@host} #{msg.from} [#{cmd}]"
        @ios.login
        result = @ios.exec(cmd)
        reply(msg, result.join)
      rescue => e
        reply(msg, "コマンド実行失敗 :'( #{e}")
      end
    end
  end

  def on_message_callback(msg)
    return if msg.body.nil? || msg.type == :error
    case msg.body
    when /^((show|ping|trace).*)/
      cmd = $1
      reply(msg, "『#{cmd}』実行!:-)")
      reply_cmd(msg, cmd)
    else
      reply(msg, 'show|ping|traceから始まるコマンドのみサポート:-(')
    end
  end
end

if __FILE__ == $PROGRAM_NAME
  HOSTS.each do |host, ipaddr|
    Bot.new(host, ipaddr).start
  end
  Thread.stop
end

実行結果

XMPP用のボットスクリプトを実行。R1とR2のアカウントでXMPPサーバに接続し、XMPPクライアントからのメッセージを待ち受けします。メッセージを受け取ると、送信元のアカウント名とコマンドを表示します。

実行結果
$ ruby bot.rb
I, [2015-12-08T23:56:14.884924 #16863]  INFO -- : R1 starting
I, [2015-12-08T23:56:15.224579 #16863]  INFO -- : R2 starting
D, [2015-12-08T23:56:16.813239 #16863] DEBUG -- : R1 admin@localhost/2a20c564 [show ip route]
D, [2015-12-08T23:56:20.036932 #16863] DEBUG -- : R1 admin@localhost/2a20c564 [show int desc]
D, [2015-12-08T23:56:24.352473 #16863] DEBUG -- : R1 admin@localhost/2a20c564 [show ip route]
D, [2015-12-09T00:00:04.743047 #16863] DEBUG -- : R1 admin@localhost/2a20c564 [show vrf]

XMPPクライアントからルータを選択して、コマンドを送信すると下記のように実行結果が返ってきます。
chat2.png

対応しているコマンドはshow、ping、traceのみとなります。copy running-config startup-configコマンドのようにプロンプトが返ってくるコマンドには未対応です。

おわりに

Ciscoルータとチャットできました。ちょっとしたコマンドの実行をしたい場合など、いちいちログインしなくても、コマンドを実行できるので便利です。ただし、補完機能がないため、CLIの恩恵を受けられません。

参考

7
8
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
7
8