はじめに
RubyとRubyGemsのexpect4rを使って、CiscoルータにTelnet/SSHをした上で、
コマンドを実行する方法を紹介します。環境はUbuntu15.04とRuby2.2です。
目的
ルータのコマンドを実行する場合は、Linuxのexpectコマンドを使う場合が多いと思います。
しかしながら、showコマンドの実行結果を見てから、次のコマンド実行を判断するなど、
条件判断や反復などを組み合わせる場合、Linuxのexpectコマンドだけでは難しいです。
そこで、今回はRuby言語を利用して、ルータにアクセスして、コマンドを実行する方法を紹介します。
RubyGemsのexpect4rを利用して、比較的簡単にルータにアクセスすることができます。
概要
expect4rは、ルータにアクセスすることに特化したライブラリです。
名前の通りLinuxのexpectっぽい動作をします。
expect4rはルータへのログイン処理を柔軟に処理しているため、
ユーザ名無しなど、いろいろなログイン設定に対応できると思います。
CLIのenableモードやconfigurationモードなどもうまく取り扱ってくれます。
Cisco IOS以外にもvyatta、juniper、Cisco IOS XRなどにも対応している模様です。
Cisco IOSの場合、下記のようにshow ip route
を実行することができます。
expct4rのREADME.rdocを参考にしています。
ios = Expect4r::Ios.new_telnet :host=> "hostname", :user=> "username", :pwd => "password"
ios.login
ios.show_ip_route
ios.exec 'show ip route'
環境
実行環境はUbuntu15.04が入ったPCと、CiscoルータのCisco1812Jです。
スクリプト
expect4r
のサンプルを参考に、スクリプトを作成しました。
Telnetでshow interface description
を実行し、
SSHでshow running-config
を表示するスクリプトです。
今回はCisco1812JのCisco IOSを対象とするため、Expect4r::Ios
クラスを使用します。
source 'https://rubygems.org'
gem 'expect4r'
require 'expect4r'
HOST = '192.168.88.101'
USERNAME = 'cisco'
PASSWORD = 'cisco'
ENABLE_PASSWORD = 'cisco'
puts '*' * 60
puts 'Telnet access'
puts '*' * 60
ios = Expect4r::Ios.new_telnet(
host: HOST,
user: USERNAME,
pwd: PASSWORD,
enable_password: ENABLE_PASSWORD
)
puts ios.exec 'show int desc' # ここでルータのコマンド実行
puts
puts '*' * 60
puts 'SSH access'
puts '*' * 60
ios = Expect4r::Ios.new_ssh(
host: HOST,
user: USERNAME,
pwd: PASSWORD,
enable_password: ENABLE_PASSWORD
)
puts ios.exec 'show running-config' # ここでルータのコマンド実行
puts
結果
TelnetとSSHでコマンドを実行できました。
% bundle install
Using highline 1.7.8
Using expect4r 0.0.11
Using bundler 1.10.6
Bundle complete! 1 Gemfile dependency, 3 gems now installed.
Use `bundle show [gemname]` to see where a bundled gem is installed.
% ruby sample1.rb
************************************************************
Telnet access
************************************************************
show int desc
Load for five secs: 0%/0%; one minute: 3%; five minutes: 2%
Time source is NTP, 00:33:29.560 JST Mon Nov 23 2015
Interface Status Protocol Description
BR0 admin down down
BR0:1 admin down down
BR0:2 admin down down
Fa0 up up WAN
Fa1 admin down down LAN
Fa2 up down SW1
Fa3 up down SW2
Fa4 up down
Fa5 up down
Fa6 up down
Fa7 up down
Fa8 up down
Fa9 up down
Vl1 up down
R1#
************************************************************
SSH access
************************************************************
show running-config
Load for five secs: 0%/0%; one minute: 3%; five minutes: 2%
Time source is NTP, 00:33:30.616 JST Mon Nov 23 2015
Building configuration...
Current configuration : 1922 bytes
!
! No configuration change since last restart
version 15.1
service timestamps debug datetime msec localtime show-timezone year
service timestamps log datetime msec localtime show-timezone year
no service password-encryption
!
hostname R1
!
boot-start-marker
boot-end-marker
!
!
logging buffered 4096
logging console informational
enable password cisco
!
no aaa new-model
!
clock timezone JST 9 0
crypto pki token default removal timeout 0
!
!
dot11 syslog
ip source-route
!
!
!
!
!
ip cef
no ip domain lookup
ip domain name cisco.com
no ipv6 cef
!
multilink bundle-name authenticated
!
!
!
license udi pid CISCO1812-J/K9 sn ********
username cisco password 0 cisco
!
!
ip ssh version 2
!
!
!
!
!
!
!
interface BRI0
no ip address
encapsulation hdlc
shutdown
!
interface FastEthernet0
description WAN
ip address 192.168.88.101 255.255.255.0
duplex auto
speed auto
!
interface FastEthernet1
description LAN
no ip address
shutdown
duplex auto
speed auto
!
interface FastEthernet2
description SW1
no ip address
!
interface FastEthernet3
description SW2
no ip address
!
interface FastEthernet4
no ip address
!
interface FastEthernet5
no ip address
!
interface FastEthernet6
no ip address
!
interface FastEthernet7
no ip address
!
interface FastEthernet8
no ip address
!
interface FastEthernet9
no ip address
!
interface Vlan1
no ip address
!
ip forward-protocol nd
no ip http server
no ip http secure-server
!
!
ip route 0.0.0.0 0.0.0.0 FastEthernet0 192.168.88.1
!
logging origin-id hostname
!
!
!
!
snmp-server community public RO
snmp-server ifindex persist
snmp-server chassis-id R1
!
!
control-plane
!
!
!
line con 0
line aux 0
line vty 0 4
exec-timeout 5 0
logging synchronous
login local
exec prompt timestamp
transport input telnet ssh
line vty 5 15
exec-timeout 5 0
logging synchronous
login local
exec prompt timestamp
transport input telnet ssh
!
ntp server 133.243.238.244
end
R1#
付録
expect4rに関する参考情報です。
コンフィグ保存の方法
コマンドによっては、確認用のプロンプトが返ってきて標準のexec
メソッドではうまく動きません。
そこで下記を組み合わせることで、ルータのcopyコマンドをうまく動くように細工できます。
-
putline
メソッドでコマンド送信 -
putline
メソッドにno_trim
オプションを付ける。空白行も送信してくれるようになる - プロンプトに合わせた入力内容と改行(
\r
)
ただし、この方法は、予め確認プロンプトの数や
入力内容がわかっている場合に有効です。
ルータのcopyコマンドは保存先ファイル名を確認するプロンプトが1回あるので、
改行(\r
)をコマンドの最後に1個追記しています。
ios.putline("copy running-config startup-config\r", no_trim: true)
require 'expect4r'
HOST = '192.168.88.101'
USERNAME = 'cisco'
PASSWORD = 'cisco'
ENABLE_PASSWORD = 'cisco'
ios = Expect4r::Ios.new_telnet(
host: HOST,
user: USERNAME,
pwd: PASSWORD,
enable_password: ENABLE_PASSWORD
)
ios.login # putlineは自動的なlogin処理をしていないため明示的に指定する
ios.to_exec # copyコマンドはexec状態で実行する必要がある
puts ios.putline("copy running-config startup-config\r", no_trim: true)
% ruby sample2.rb
copy running-config startup-config
Destination filename [startup-config]?
Building configuration...
[OK]
R1#