This patch adds a cisco only specialized facter system that leverage
the cisco device instance.

Signed-off-by: Brice Figureau <[email protected]>
---
 lib/puppet/util/network_device/cisco/device.rb     |   10 ++
 lib/puppet/util/network_device/cisco/facts.rb      |   72 ++++++++++
 spec/unit/util/network_device/cisco/device_spec.rb |  137 ++------------------
 spec/unit/util/network_device/cisco/facts_spec.rb  |   63 +++++++++
 4 files changed, 157 insertions(+), 125 deletions(-)
 create mode 100644 lib/puppet/util/network_device/cisco/facts.rb
 create mode 100644 spec/unit/util/network_device/cisco/facts_spec.rb

diff --git a/lib/puppet/util/network_device/cisco/device.rb 
b/lib/puppet/util/network_device/cisco/device.rb
index 1f35099..005470e 100644
--- a/lib/puppet/util/network_device/cisco/device.rb
+++ b/lib/puppet/util/network_device/cisco/device.rb
@@ -3,6 +3,7 @@ require 'puppet/util'
 require 'puppet/util/network_device/base'
 require 'puppet/util/network_device/ipcalc'
 require 'puppet/util/network_device/cisco/interface'
+require 'puppet/util/network_device/cisco/facts'
 require 'ipaddr'
 
 class Puppet::Util::NetworkDevice::Cisco::Device < 
Puppet::Util::NetworkDevice::Base
@@ -91,6 +92,15 @@ class Puppet::Util::NetworkDevice::Cisco::Device < 
Puppet::Util::NetworkDevice::
     interface
   end
 
+  def facts
+    @facts ||= Puppet::Util::NetworkDevice::Cisco::Facts.new(transport)
+    facts = {}
+    command do |ng|
+      facts = @facts.retrieve
+    end
+    facts
+  end
+
   def interface(name)
     ifname = canonalize_ifname(name)
     interface = parse_interface(ifname)
diff --git a/lib/puppet/util/network_device/cisco/facts.rb 
b/lib/puppet/util/network_device/cisco/facts.rb
new file mode 100644
index 0000000..40e2b37
--- /dev/null
+++ b/lib/puppet/util/network_device/cisco/facts.rb
@@ -0,0 +1,72 @@
+
+require 'puppet/util/network_device/cisco'
+require 'puppet/util/network_device/ipcalc'
+
+# this retrieves facts from a cisco device
+class Puppet::Util::NetworkDevice::Cisco::Facts
+
+  attr_reader :transport
+
+  def initialize(transport)
+    @transport = transport
+  end
+
+  def retrieve
+    facts = {}
+    facts.merge(parse_show_ver)
+  end
+
+  def parse_show_ver
+    facts = {}
+    out = @transport.command("sh ver")
+    lines = out.split("\n")
+    lines.shift; lines.pop
+    lines.each do |l|
+      case l
+      # cisco WS-C2924C-XL (PowerPC403GA) processor (revision 0x11) with 
8192K/1024K bytes of memory.
+      # Cisco 1841 (revision 5.0) with 355328K/37888K bytes of memory.
+      # Cisco 877 (MPC8272) processor (revision 0x200) with 118784K/12288K 
bytes of memory.
+      # cisco WS-C2960G-48TC-L (PowerPC405) processor (revision C0) with 
61440K/4088K bytes of memory.
+      # cisco WS-C2950T-24 (RC32300) processor (revision R0) with 19959K bytes 
of memory.
+      when /[cC]isco ([\w-]+) (?:\(([\w-]+)\) processor )?\(revision (.+)\) 
with (\d+[KMG])(?:\/(\d+[KMG]))? bytes of memory\./
+        facts[:hardwaremodel] = $1
+        facts[:processor] = $2 if $2
+        facts[:hardwarerevision] = $3
+        facts[:memorysize] = $4
+      # uptime
+      # Switch uptime is 1 year, 12 weeks, 6 days, 22 hours, 32 minutes
+      # c2950 uptime is 3 weeks, 1 day, 23 hours, 36 minutes
+      # c2960 uptime is 2 years, 27 weeks, 5 days, 21 hours, 30 minutes
+      # router uptime is 5 weeks, 1 day, 3 hours, 30 minutes
+      when /^\s*([\w-]+)\s+uptime is (.*?)$/
+        facts[:hostname] = $1
+        facts[:uptime] = $2
+        facts[:uptime_seconds] = uptime_to_seconds($2)
+        facts[:uptime_days] = facts[:uptime_seconds] / 86400
+      # "IOS (tm) C2900XL Software (C2900XL-C3H2S-M), Version 12.0(5)WC10, 
RELEASE SOFTWARE (fc1)"=> { :operatingsystem => "IOS", :operatingsystemrelease 
=> "12.0(5)WC10", :operatingsystemmajrelease => "12.0", :operatingsystemfeature 
=> "C3H2S"},
+      # "IOS (tm) C2950 Software (C2950-I6K2L2Q4-M), Version 12.1(22)EA8a, 
RELEASE SOFTWARE (fc1)"=> { :operatingsystem => "IOS", :operatingsystemrelease 
=> "12.1(22)EA8a", :operatingsystemmajrelease => "12.1", 
:operatingsystemfeature => "I6K2L2Q4"},
+      # "Cisco IOS Software, C2960 Software (C2960-LANBASEK9-M), Version 
12.2(44)SE, RELEASE SOFTWARE (fc1)"=>{ :operatingsystem => "IOS", 
:operatingsystemrelease => "12.2(44)SE", :operatingsystemmajrelease => "12.2", 
:operatingsystemfeature => "LANBASEK9"},
+      # "Cisco IOS Software, C870 Software (C870-ADVIPSERVICESK9-M), Version 
12.4(11)XJ4, RELEASE SOFTWARE (fc2)"=>{ :operatingsystem => "IOS", 
:operatingsystemrelease => "12.4(11)XJ40", :operatingsystemmajrelease => 
"12.4XJ", :operatingsystemfeature => "ADVIPSERVICESK9"},
+      # "Cisco IOS Software, 1841 Software (C1841-ADVSECURITYK9-M), Version 
12.4(24)T4, RELEASE SOFTWARE (fc2)" =>{ :operatingsystem => "IOS", 
:operatingsystemrelease => "12.4(24)T4", :operatingsystemmajrelease => "12.4T", 
:operatingsystemfeature => "ADVSECURITYK9"},
+      when /(?:Cisco )?(IOS)\s*(?:\(tm\) |Software, 
)?(?:\w+)\s+Software\s+\(\w+-(\w+)-\w+\), Version ([0-9.()A-Za-z]+),/
+        facts[:operatingsystem] = $1
+        facts[:operatingsystemrelease] = $3
+        facts[:operatingsystemmajrelease] = 
ios_major_version(facts[:operatingsystemrelease])
+        facts[:operatingsystemfeature] = $2
+      end
+    end
+    facts
+  end
+
+  def ios_major_version(version)
+    version.gsub(/^(\d+)\.(\d+)\(.+\)([A-Z]+)([\da-z]+)?/, '\1.\2\3')
+  end
+
+  def uptime_to_seconds(uptime)
+    captures = (uptime.match /^(?:(?:(?:(?:(\d+) years?,)?\s*(\d+) 
weeks?,)?\s*(\d+) days?,)?\s*(\d+) hours?,)?\s*(\d+) minutes?$/).captures
+    seconds = captures.zip([31536000, 604800, 86400, 3600, 60]).inject(0) do 
|total, (x,y)|
+      total + (x.nil? ? 0 : x.to_i * y)
+    end
+  end
+
+end
\ No newline at end of file
diff --git a/spec/unit/util/network_device/cisco/device_spec.rb 
b/spec/unit/util/network_device/cisco/device_spec.rb
index 82b0666..33242a1 100755
--- a/spec/unit/util/network_device/cisco/device_spec.rb
+++ b/spec/unit/util/network_device/cisco/device_spec.rb
@@ -392,130 +392,17 @@ eos
       @cisco.parse_interface_config("Gi0/17").should == {:etherchannel=>"1"}
     end
   end
+
+  describe "when finding device facts" do
+    it "should delegate to the cisco facts entity" do
+      facts = stub 'facts'
+      Puppet::Util::NetworkDevice::Cisco::Facts.expects(:new).returns(facts)
+
+      facts.expects(:retrieve).returns(:facts)
+
+      @cisco.facts.should == :facts
+    end
+  end
+
 end
 
-# static access
-# Switch#sh interfaces FastEthernet 0/1 switchport  
-# Name: Fa0/1
-# Switchport: Enabled
-# Administrative mode: static access
-# Operational Mode: static access
-# Administrative Trunking Encapsulation: isl
-# Operational Trunking Encapsulation: isl
-# Negotiation of Trunking: Disabled
-# Access Mode VLAN: 100 (SHDSL)
-# Trunking Native Mode VLAN: 1 (default)
-# Trunking VLANs Enabled: NONE
-# Pruning VLANs Enabled: NONE
-# 
-# Priority for untagged frames: 0
-# Override vlan tag priority: FALSE
-# Voice VLAN: none
-# Appliance trust: none
-# Self Loopback: No
-# Switch#
-
-# c2960#sh interfaces GigabitEthernet 0/1 switchport 
-# Name: Gi0/1
-# Switchport: Enabled
-# Administrative Mode: trunk
-# Operational Mode: trunk
-# Administrative Trunking Encapsulation: dot1q
-# Operational Trunking Encapsulation: dot1q
-# Negotiation of Trunking: On
-# Access Mode VLAN: 1 (default)
-# Trunking Native Mode VLAN: 1 (default)
-# Administrative Native VLAN tagging: enabled
-# Voice VLAN: none
-# Administrative private-vlan host-association: none 
-# Administrative private-vlan mapping: none 
-# Administrative private-vlan trunk native VLAN: none
-# Administrative private-vlan trunk Native VLAN tagging: enabled
-# Administrative private-vlan trunk encapsulation: dot1q
-# Administrative private-vlan trunk normal VLANs: none
-# Administrative private-vlan trunk associations: none
-# Administrative private-vlan trunk mappings: none
-# Operational private-vlan: none
-# Trunking VLANs Enabled: 1,99
-# Pruning VLANs Enabled: 2-1001
-# Capture Mode Disabled
-# Capture VLANs Allowed: ALL
-# 
-# Protected: false
-# Unknown unicast blocked: disabled
-# Unknown multicast blocked: disabled
-# Appliance trust: none
-# c2960#
-
-# c2960#sh interfaces GigabitEthernet 0/2 switchport 
-# Name: Gi0/2
-# Switchport: Enabled
-# Administrative Mode: static access
-# Operational Mode: static access
-# Administrative Trunking Encapsulation: dot1q
-# Operational Trunking Encapsulation: native
-# Negotiation of Trunking: Off
-# Access Mode VLAN: 99 (MGMT)
-# Trunking Native Mode VLAN: 1 (default)
-# Administrative Native VLAN tagging: enabled
-# Voice VLAN: none
-# Administrative private-vlan host-association: none 
-# Administrative private-vlan mapping: none 
-# Administrative private-vlan trunk native VLAN: none
-# Administrative private-vlan trunk Native VLAN tagging: enabled
-# Administrative private-vlan trunk encapsulation: dot1q
-# Administrative private-vlan trunk normal VLANs: none
-# Administrative private-vlan trunk associations: none
-# Administrative private-vlan trunk mappings: none
-# Operational private-vlan: none
-# Trunking VLANs Enabled: ALL
-# Pruning VLANs Enabled: 2-1001
-# Capture Mode Disabled
-# Capture VLANs Allowed: ALL
-# 
-# Protected: false
-# Unknown unicast blocked: disabled
-# Unknown multicast blocked: disabled
-# Appliance trust: none
-# c2960#
-
-# c877#sh interfaces FastEthernet 1 switchport 
-# Name: Fa1
-# Switchport: Enabled
-# Administrative Mode: trunk
-# Operational Mode: trunk
-# Administrative Trunking Encapsulation: dot1q
-# Operational Trunking Encapsulation: dot1q
-# Negotiation of Trunking: Disabled
-# Access Mode VLAN: 0 ((Inactive))
-# Trunking Native Mode VLAN: 1 (default)
-# Trunking VLANs Enabled: ALL
-# Trunking VLANs Active: 1
-# Protected: false
-# Priority for untagged frames: 0
-# Override vlan tag priority: FALSE
-# Voice VLAN: none 
-# Appliance trust: none
-
-
-# c2960#sh etherchannel summary 
-# Flags:  D - down        P - bundled in port-channel
-#         I - stand-alone s - suspended
-#         H - Hot-standby (LACP only)
-#         R - Layer3      S - Layer2
-#         U - in use      f - failed to allocate aggregator
-# 
-#         M - not in use, minimum links not met
-#         u - unsuitable for bundling
-#         w - waiting to be aggregated
-#         d - default port
-# 
-# 
-# Number of channel-groups in use: 1
-# Number of aggregators:           1
-# 
-# Group  Port-channel  Protocol    Ports
-# 
------+-------------+-----------+-----------------------------------------------
-# 1      Po1(SU)         LACP      Gi0/17(P)   Gi0/18(P)   
-# 
-# c2960#
diff --git a/spec/unit/util/network_device/cisco/facts_spec.rb 
b/spec/unit/util/network_device/cisco/facts_spec.rb
new file mode 100644
index 0000000..bb29ac2
--- /dev/null
+++ b/spec/unit/util/network_device/cisco/facts_spec.rb
@@ -0,0 +1,63 @@
+#!/usr/bin/env ruby
+
+require File.dirname(__FILE__) + '/../../../../spec_helper'
+
+require 'puppet/util/network_device'
+require 'puppet/util/network_device/cisco/facts'
+
+describe Puppet::Util::NetworkDevice::Cisco::Facts do
+  before(:each) do
+    @transport = stub_everything 'transport'
+    @facts = Puppet::Util::NetworkDevice::Cisco::Facts.new(@transport)
+  end
+
+  {
+    "cisco WS-C2924C-XL (PowerPC403GA) processor (revision 0x11) with 
8192K/1024K bytes of memory." => {:hardwaremodel => "WS-C2924C-XL", :memorysize 
=> "8192K", :processor => "PowerPC403GA", :hardwarerevision => "0x11" },
+    "Cisco 1841 (revision 5.0) with 355328K/37888K bytes of memory." => 
{:hardwaremodel=>"1841", :memorysize => "355328K", :hardwarerevision => "5.0" },
+    "Cisco 877 (MPC8272) processor (revision 0x200) with 118784K/12288K bytes 
of memory." => {:hardwaremodel=>"877", :memorysize => "118784K", :processor => 
"MPC8272", :hardwarerevision => "0x200" },
+    "cisco WS-C2960G-48TC-L (PowerPC405) processor (revision C0) with 
61440K/4088K bytes of memory." => {:hardwaremodel=>"WS-C2960G-48TC-L", 
:memorysize => "61440K", :processor => "PowerPC405", :hardwarerevision => "C0" 
},
+    "cisco WS-C2950T-24 (RC32300) processor (revision R0) with 19959K bytes of 
memory." => {:hardwaremodel=>"WS-C2950T-24", :memorysize => "19959K", 
:processor => "RC32300", :hardwarerevision => "R0" }
+  }.each do |ver, expected|
+    it "should parse show ver output for hardware device facts" do
+      @transport.stubs(:command).with("sh ver").returns(<<eos)
+Switch>sh ver
+#{ver}
+Switch>
+eos
+      @facts.parse_show_ver.should == expected
+    end
+  end
+
+  {
+"Switch uptime is 1 year, 12 weeks, 6 days, 22 hours, 32 minutes" => { 
:hostname => "Switch", :uptime => "1 year, 12 weeks, 6 days, 22 hours, 32 
minutes", :uptime_seconds => 39393120, :uptime_days => 455 },
+"c2950 uptime is 3 weeks, 1 day, 23 hours, 36 minutes" => { :hostname => 
"c2950", :uptime => "3 weeks, 1 day, 23 hours, 36 minutes", :uptime_days => 22, 
:uptime_seconds =>  1985760},
+"router uptime is 5 weeks, 1 day, 3 hours, 30 minutes" => { :hostname => 
"router", :uptime => "5 weeks, 1 day, 3 hours, 30 minutes", :uptime_days => 36, 
:uptime_seconds => 3123000 },
+"c2950 uptime is 1 minute" => { :hostname => "c2950", :uptime => "1 minute", 
:uptime_days => 0, :uptime_seconds => 60 }
+  }.each do |ver, expected|
+    it "should parse show ver output for device uptime facts" do
+      @transport.stubs(:command).with("sh ver").returns(<<eos)
+Switch>sh ver
+#{ver}
+Switch>
+eos
+      @facts.parse_show_ver.should == expected
+    end
+  end
+
+  {
+"IOS (tm) C2900XL Software (C2900XL-C3H2S-M), Version 12.0(5)WC10, RELEASE 
SOFTWARE (fc1)"=> { :operatingsystem => "IOS", :operatingsystemrelease => 
"12.0(5)WC10", :operatingsystemmajrelease => "12.0WC", :operatingsystemfeature 
=> "C3H2S"},
+"IOS (tm) C2950 Software (C2950-I6K2L2Q4-M), Version 12.1(22)EA8a, RELEASE 
SOFTWARE (fc1)"=> { :operatingsystem => "IOS", :operatingsystemrelease => 
"12.1(22)EA8a", :operatingsystemmajrelease => "12.1EA", :operatingsystemfeature 
=> "I6K2L2Q4"},
+"Cisco IOS Software, C2960 Software (C2960-LANBASEK9-M), Version 12.2(44)SE, 
RELEASE SOFTWARE (fc1)"=>{ :operatingsystem => "IOS", :operatingsystemrelease 
=> "12.2(44)SE", :operatingsystemmajrelease => "12.2SE", 
:operatingsystemfeature => "LANBASEK9"},
+"Cisco IOS Software, C870 Software (C870-ADVIPSERVICESK9-M), Version 
12.4(11)XJ4, RELEASE SOFTWARE (fc2)"=>{ :operatingsystem => "IOS", 
:operatingsystemrelease => "12.4(11)XJ4", :operatingsystemmajrelease => 
"12.4XJ", :operatingsystemfeature => "ADVIPSERVICESK9"},
+"Cisco IOS Software, 1841 Software (C1841-ADVSECURITYK9-M), Version 
12.4(24)T4, RELEASE SOFTWARE (fc2)" =>{ :operatingsystem => "IOS", 
:operatingsystemrelease => "12.4(24)T4", :operatingsystemmajrelease => "12.4T", 
:operatingsystemfeature => "ADVSECURITYK9"},
+  }.each do |ver, expected|
+    it "should parse show ver output for device software version facts" do
+      @transport.stubs(:command).with("sh ver").returns(<<eos)
+Switch>sh ver
+#{ver}
+Switch>
+eos
+      @facts.parse_show_ver.should == expected
+    end
+  end
+end
-- 
1.7.2.1

-- 
You received this message because you are subscribed to the Google Groups 
"Puppet Developers" group.
To post to this group, send email to [email protected].
To unsubscribe from this group, send email to 
[email protected].
For more options, visit this group at 
http://groups.google.com/group/puppet-dev?hl=en.

Reply via email to