Permalink
Browse files

- Add all files.

  • Loading branch information...
stass committed Aug 20, 2011
0 parents commit 05998e72f9412bbae988824c96f5cb24d93e2aa3
Showing with 197 additions and 0 deletions.
  1. +118 −0 CiscoConfig.rb
  2. +54 −0 README.markdown
  3. +25 −0 examples/copy_config.rb
@@ -0,0 +1,118 @@
+#
+# A Ruby library to fetch Cisco IOS configuration via SNMP
+#
+# Copyright (C) 2007-2008 Stanislav Sedov <stas@FreeBSD.org>
+#
+# This file is in public domain
+#
+
+#
+# See http://www.cisco.com/en/US/tech/tk648/tk362/technologies_tech_note09186a0080094aa6.shtml
+# for additional info.
+#
+
+require 'snmp'
+
+class CiscoConfig
+
+ #
+ # OIDs from CISCO-CONFIG-COPY-MIB-V1SMI
+ #
+ OIDPrefix = '1.3.6.1.4.1.9.9.96.1.1.1.1' # common prefix
+
+ OIDMap = { # name -> oid mappings
+ :CopyProtocol => 2,
+ :CopySourceFileType => 3,
+ :CopyDestFileType => 4,
+ :CopyServerAddress => 5,
+ :CopyFileName => 6,
+ :CopyState => 10,
+ :CopyFailCause => 13,
+ :CopyEntryRowStatus => 14
+ }
+
+ #
+ # Error codes
+ #
+ REQSTATUS = {
+ 1 => "unknown error",
+ 2 => "access denied",
+ 3 => "TFTP operation timed out",
+ 4 => "out of memory",
+ 5 => "no configuration",
+ }
+
+ #
+ # Default configuration
+ #
+ Defconfig = {
+ :host => 'localhost',
+ :port => 161,
+ :comm => 'public',
+ }
+
+ def initialize(newconf = {})
+ @config = Defconfig.merge(newconf)
+
+ @manager = SNMP::Manager.new(:Host => @config[:host], :Port => @config[:port], \
+ :Community => @config[:comm])
+
+ self
+ end
+
+ def copy_from_cisco(host, file)
+ id = cisco_rand # this will became the new id
+ status = 0
+
+ req = Array.new()
+ req[0] = SNMP::VarBind.new get_oid(:CopyProtocol, id), SNMP::Integer.new(1)
+ req[1] = SNMP::VarBind.new get_oid(:CopySourceFileType, id), SNMP::Integer.new(4)
+ req[2] = SNMP::VarBind.new get_oid(:CopyDestFileType, id), SNMP::Integer.new(1)
+ req[3] = SNMP::VarBind.new get_oid(:CopyServerAddress, id), SNMP::IpAddress.new(host)
+ req[4] = SNMP::VarBind.new get_oid(:CopyFileName, id), SNMP::OctetString.new(file)
+ req[5] = SNMP::VarBind.new get_oid(:CopyEntryRowStatus, id), SNMP::Integer.new(4)
+
+ @manager.set(req)
+
+ id
+ end
+
+ def get_status(id, timeout = 10)
+ status = 0
+ time = 0
+ while (time < 10) do
+ status = @manager.get_value(get_oid(:CopyState, id)).to_i
+ break if status > 2
+ sleep(1)
+ end
+
+ return "timed out" if time == 10
+
+ if (status == 3) then
+ return "OK"
+ end
+
+ err = @manager.get_value(get_oid(:CopyFailCause, id)).to_i
+
+ REQSTATUS[err]
+ end
+
+ #
+ # Return random number suitable to use in Cisco OIDs.
+ # It looks like that only 24 bits are allowed
+ #
+ def cisco_rand
+ rand(1 << 24)
+ end
+
+ private :cisco_rand
+
+ #
+ # Returns full IOS OID according to name provided
+ #
+ def get_oid(name, id)
+ OIDPrefix + '.' + OIDMap[name].to_s + ".#{id}"
+ end
+
+ private :get_oid
+end
@@ -0,0 +1,54 @@
+Cisco_config.rb
+===============
+
+What is it?
+-----------
+
+This library allows one to access Cisco routers and switches configuration via
+SNMP. Using SNMP access it triggers a command on the device that will upload
+the configuration file to the TFTP server specified.
+
+
+How?
+----
+
+```ruby
+require 'CiscoConfig'
+
+cisco = CiscoConfig.new(:host => 'router0.example.org', :comm => 'secretcommunity')
+rnd = cisco.copy_from_cisco('tftpserver.example.com', 'config/cisco0.conf')
+```
+
+This snipplet will tell the device accessible via 'router0.example.com' to upload it's
+configuration to the TFTP sever at 'tftpserver.example.com'. The second argument of
+the `copy_from_cisco` method is the actual filename to save the configuration to.
+You should also specifiy the SNMP community configured on your device via the `:comm`
+keyword argument of the constructor.
+
+
+Interface
+---------
+
+The `CiscoConfig` class provides the following methods:
+
+* `new(config = {})`. The constructor accepts the Hash table containing the device access
+ configuration. Specifically, the following options are supported right now:
+ * :host -- the hostname of the device
+ * :port -- the device SNMP port
+ * :comm -- SNMP community name.
+
+* `copy_from_cisco(tftp_host, tftp_file)`. This method triggers the device upload command.
+ The configuration file will be uploaded to the host identified by `tftp_host` under
+ the `tftp_file` filename. The destination directory of `tftp_file` should already exist.
+ The method will return numerical ID of the command, which can be used to check for the
+ status later.
+
+* `get_status(id, timeout = 10)`. This method returns the status of the previous command
+ identified by 'id'. It will wait up to `timeout` seconds for the operation to complete if
+ it is in progress.
+
+
+Comments
+--------
+
+Send your comments and/or suggestions to <stas@FreeBSD.org>.
@@ -0,0 +1,25 @@
+#!/usr/bin/env ruby18
+#
+# This example shows how to use the CiscoConfig library to download the configuration file
+# from the Cisco router/swiftch and check it into the repository if it has changed. This
+# script can be run from the cron to keep track of configuration changes.
+#
+require 'rubygems'
+require 'CiscoConfig'
+
+begin
+ cisco = CiscoConfig.new(:host => 'router0.example.org', :comm => 'secretcommunity')
+ rnd = cisco.copy_from_cisco('tftpserver.example.com', 'config/cisco0.conf')
+
+ status = cisco.get_status(rnd)
+ if (status != "OK") then
+ puts "Error retrieving config: #{status}"
+ end
+
+ system('sed -i "" -e "/ntp clock-period/d" /mnt/tftpserver/tftproot/config/cisco0.conf')
+
+ lines = `(cd /mnt/tftpserver/tftproot/config && /usr/local/bin/hg diff) 2>/dev/null | wc -l`.to_i
+ exit if (lines == 0)
+
+ system("cd /mnt/tftpserver/tftproot/config && /usr/local/bin/hg ci -m 'cisco0 config autocommit' 2>/dev/null")
+end

0 comments on commit 05998e7

Please sign in to comment.