cisco-config-parse 0.0.5
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +29 -0
- data/lib/cisco-config-parse.rb +135 -0
- metadata +65 -0
data/README.md
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
# cisco-config-parse
|
2
|
+
|
3
|
+
## What?
|
4
|
+
|
5
|
+
cisco-config-parse is a gem that given a Cisco configuration file, parses it to provide an easy breakdown of information for manipulation. For example, you can get the list of interfaces as a hash with relevant details, such as the description on the port, the VLAN configuration, etc.
|
6
|
+
|
7
|
+
## How to use
|
8
|
+
|
9
|
+
require 'cisco-config-parse'
|
10
|
+
parser = CiscoConfigParse.new(IO.readlines("/path/to/file"))
|
11
|
+
# Parse the file
|
12
|
+
parser.parse
|
13
|
+
# Get a hash of the interfaces
|
14
|
+
puts parser.get_interfaces
|
15
|
+
|
16
|
+
{"FastEthernet0"=>{}, "GigabitEthernet0/1"=>{:description=>"host0119.ilo", :access_vlan=>"21", :bpduguard=>"enable"}, "GigabitEthernet0/2"=>{:description=>"host0120.ilo", :access_vlan=>"21", :bpduguard=>"enable"}, "GigabitEthernet0/3"=>{:description=>"host0123.ilo", :access_vlan=>"21", :bpduguard=>"enable"}, "GigabitEthernet0/4"=>{:description=>"host0124.ilo", :access_vlan=>"21", :bpduguard=>"enable"}, "GigabitEthernet0/5"=>{:description=>"host0127.ilo", :access_vlan=>"21", :bpduguard=>"enable"}, "GigabitEthernet0/6"=>{:description=>"host0128.ilo", :access_vlan=>"21", :bpduguard=>"enable"}, ...[snip]
|
17
|
+
|
18
|
+
## Methods
|
19
|
+
|
20
|
+
* *parse* - Parses the configuration, required for any other operation
|
21
|
+
* *get\_interfaces* - Returns a hash of all interfaces in config along with their details
|
22
|
+
* *get\_hostname* - Returns the hostname of the switch
|
23
|
+
* *get\_version* - Returns the version of the software running on the switch
|
24
|
+
|
25
|
+
## Bugs? Improvements?
|
26
|
+
Probably; this does the bare minimum right now (in my case, I wanted to compare the VLANs on all interfaces on two switches. Please do let me know if anything is broken, and as always please do submit pull requests with any improvements.
|
27
|
+
|
28
|
+
### Thanks
|
29
|
+
* Half of this code was written by Geoff Garside (https://github.com/geoffgarside), so thanks for letting me take, finish and publish!
|
@@ -0,0 +1,135 @@
|
|
1
|
+
#!/bin/env ruby
|
2
|
+
|
3
|
+
class CiscoConfigParse
|
4
|
+
def initialize(io)
|
5
|
+
@io = io
|
6
|
+
end
|
7
|
+
|
8
|
+
def parse
|
9
|
+
@io.each do |line|
|
10
|
+
if line =~ /^\!$/ or line =~ /^$/ # terminate current block
|
11
|
+
end_config
|
12
|
+
next
|
13
|
+
elsif line =~ /^\!/ # Comment
|
14
|
+
next
|
15
|
+
end
|
16
|
+
parse_config(line)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def get_interfaces
|
21
|
+
return @interfaces
|
22
|
+
end
|
23
|
+
|
24
|
+
def get_vlans
|
25
|
+
return @vlans
|
26
|
+
end
|
27
|
+
|
28
|
+
def get_hostname
|
29
|
+
return @config_hostname
|
30
|
+
end
|
31
|
+
|
32
|
+
def get_version
|
33
|
+
return @software_version
|
34
|
+
end
|
35
|
+
|
36
|
+
private
|
37
|
+
def state
|
38
|
+
@state ||= []
|
39
|
+
end
|
40
|
+
def end_config
|
41
|
+
meth = ['e_config', state].flatten.join('_')
|
42
|
+
send(meth) if respond_to?(meth)
|
43
|
+
state.pop
|
44
|
+
end
|
45
|
+
def parse_config(line)
|
46
|
+
cmd, opts = line.strip.split(' ', 2)
|
47
|
+
meth, opts = meth_and_opts(cmd, opts)
|
48
|
+
send(meth, opts) if respond_to?(meth)
|
49
|
+
end
|
50
|
+
def meth_and_opts(cmd, opts)
|
51
|
+
return negated_meth_and_opts(opts) if cmd =~ /no/
|
52
|
+
[['p_config', state, cmd.gsub('-', '_')].flatten.join('_'), opts]
|
53
|
+
end
|
54
|
+
def negated_meth_and_opts(line)
|
55
|
+
cmd, opts = line.split(' ', 2)
|
56
|
+
[['n_config', state, cmd.gsub('-', '_')].flatten.join('_'), opts]
|
57
|
+
end
|
58
|
+
|
59
|
+
protected
|
60
|
+
def p_config_hostname(str)
|
61
|
+
@config_hostname = str
|
62
|
+
end
|
63
|
+
|
64
|
+
def p_config_version(str)
|
65
|
+
@software_version = str
|
66
|
+
end
|
67
|
+
|
68
|
+
def p_config_vlan(ids)
|
69
|
+
@current_vlan = {:ids => ids}
|
70
|
+
end
|
71
|
+
|
72
|
+
def e_config_vlan
|
73
|
+
@vlans ||= {}
|
74
|
+
@vlans[@current_vlan.delete(:ids)] = @current_vlan
|
75
|
+
end
|
76
|
+
|
77
|
+
def p_config_interface(name)
|
78
|
+
state.push(:interface)
|
79
|
+
@current_interface = {:id => name}
|
80
|
+
end
|
81
|
+
|
82
|
+
def e_config_interface
|
83
|
+
@interfaces ||= {}
|
84
|
+
@interfaces[@current_interface.delete(:id)] = @current_interface
|
85
|
+
end
|
86
|
+
|
87
|
+
def p_config_interface_description(str)
|
88
|
+
@current_interface[:description] = str
|
89
|
+
end
|
90
|
+
|
91
|
+
def p_config_interface_switchport(str)
|
92
|
+
# Parse the switchport string
|
93
|
+
command = str.split(' ', 3)
|
94
|
+
case command[0]
|
95
|
+
when "trunk"
|
96
|
+
# Its a trunk command; continue to figure out what kind
|
97
|
+
if command[1] == "allowed"
|
98
|
+
# allow vlan
|
99
|
+
allowed_type = str.split(' ', 5)
|
100
|
+
# Split up the rest of the string for the list of vlans
|
101
|
+
vlan_list = str.gsub(',',' ').split(' ')
|
102
|
+
if allowed_type[3] == "add" then
|
103
|
+
@current_interface[:added_allowed_vlans] = vlan_list.slice(4, vlan_list.length)
|
104
|
+
else
|
105
|
+
@current_interface[:allowed_vlans] = vlan_list.slice(3, vlan_list.length)
|
106
|
+
end
|
107
|
+
end
|
108
|
+
when "access"
|
109
|
+
@current_interface[:access_vlan] = command[2]
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
def p_config_interface_inherit(str)
|
114
|
+
@current_interface[:inherit] = str
|
115
|
+
end
|
116
|
+
|
117
|
+
def p_config_interface_spanning_tree(str)
|
118
|
+
# Parse the spanning tree config options
|
119
|
+
command = str.split(' ')
|
120
|
+
case command[0]
|
121
|
+
when "port"
|
122
|
+
@current_interface[:spanning_tree_port_type] = command[2]
|
123
|
+
when "guard"
|
124
|
+
@current_interface[:spanning_tree_guard] = command[1]
|
125
|
+
when "bpduguard"
|
126
|
+
@current_interface[:bpduguard] = command[1]
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
def p_config_interface_channel_group(str)
|
131
|
+
# Is the port in a port channel?
|
132
|
+
@current_interface[:channel_group] = str.split(' ')[0]
|
133
|
+
|
134
|
+
end
|
135
|
+
end
|
metadata
ADDED
@@ -0,0 +1,65 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: cisco-config-parse
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
prerelease: false
|
5
|
+
segments:
|
6
|
+
- 0
|
7
|
+
- 0
|
8
|
+
- 5
|
9
|
+
version: 0.0.5
|
10
|
+
platform: ruby
|
11
|
+
authors:
|
12
|
+
- Laurie Denness
|
13
|
+
autorequire:
|
14
|
+
bindir: bin
|
15
|
+
cert_chain: []
|
16
|
+
|
17
|
+
date: 2013-01-28 00:00:00 +00:00
|
18
|
+
default_executable:
|
19
|
+
dependencies: []
|
20
|
+
|
21
|
+
description: "Parses a cisco config file on disk (probably from a tool such as Rancid) and returns simple hashes of parsed data, for example interfaces, VLANs, software version, hostname. "
|
22
|
+
email: laurie@denness.net
|
23
|
+
executables: []
|
24
|
+
|
25
|
+
extensions: []
|
26
|
+
|
27
|
+
extra_rdoc_files:
|
28
|
+
- README.md
|
29
|
+
files:
|
30
|
+
- README.md
|
31
|
+
- lib/cisco-config-parse.rb
|
32
|
+
has_rdoc: true
|
33
|
+
homepage: https://github.com/lozzd/cisco-config-parse
|
34
|
+
licenses: []
|
35
|
+
|
36
|
+
post_install_message:
|
37
|
+
rdoc_options:
|
38
|
+
- --charset=UTF-8
|
39
|
+
require_paths:
|
40
|
+
- lib
|
41
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
42
|
+
none: false
|
43
|
+
requirements:
|
44
|
+
- - ">="
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
segments:
|
47
|
+
- 0
|
48
|
+
version: "0"
|
49
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
50
|
+
none: false
|
51
|
+
requirements:
|
52
|
+
- - ">="
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
segments:
|
55
|
+
- 0
|
56
|
+
version: "0"
|
57
|
+
requirements: []
|
58
|
+
|
59
|
+
rubyforge_project: cisco-config-parse
|
60
|
+
rubygems_version: 1.3.7
|
61
|
+
signing_key:
|
62
|
+
specification_version: 2
|
63
|
+
summary: Parses a Cisco config file on disk for easy manipulation of interfaces, VLANs etc.
|
64
|
+
test_files: []
|
65
|
+
|