ios_parser 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gitignore +37 -0
- data/.rubocop.yml +19 -0
- data/.travis.yml +6 -0
- data/CHANGELOG.md +14 -0
- data/CODE_OF_CONDUCT.md +49 -0
- data/Gemfile +2 -0
- data/Guardfile +10 -0
- data/LICENSE.txt +675 -0
- data/README.md +90 -0
- data/Rakefile +16 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/doc/state_machine.graphviz +41 -0
- data/doc/state_machine.png +0 -0
- data/ext/ios_parser/c_lexer/extconf.rb +4 -0
- data/ext/ios_parser/c_lexer/lexer.c +462 -0
- data/ios_parser.gemspec +24 -0
- data/lib/ios_parser/ios/command.rb +90 -0
- data/lib/ios_parser/ios/document.rb +53 -0
- data/lib/ios_parser/ios/queryable.rb +218 -0
- data/lib/ios_parser/ios.rb +70 -0
- data/lib/ios_parser/lexer.rb +278 -0
- data/lib/ios_parser/pure.rb +2 -0
- data/lib/ios_parser/version.rb +7 -0
- data/lib/ios_parser.rb +32 -0
- data/spec/lib/ios_parser/ios/queryable_spec.rb +153 -0
- data/spec/lib/ios_parser/ios_spec.rb +339 -0
- data/spec/lib/ios_parser/lexer_spec.rb +231 -0
- data/spec/lib/ios_parser_spec.rb +101 -0
- data/spec/spec_helper.rb +5 -0
- metadata +164 -0
@@ -0,0 +1,231 @@
|
|
1
|
+
require_relative '../../spec_helper'
|
2
|
+
require 'ios_parser'
|
3
|
+
require 'ios_parser/lexer'
|
4
|
+
|
5
|
+
module IOSParser
|
6
|
+
describe Lexer do
|
7
|
+
describe '#call' do
|
8
|
+
subject { klass.new.call(input) }
|
9
|
+
|
10
|
+
let(:subject_pure) do
|
11
|
+
IOSParser::PureLexer.new.call(input)
|
12
|
+
end
|
13
|
+
|
14
|
+
context 'indented region' do
|
15
|
+
let(:input) { <<-END }
|
16
|
+
policy-map mypolicy_in
|
17
|
+
class myservice_service
|
18
|
+
police 300000000 1000000 exceed-action policed-dscp-transmit
|
19
|
+
set dscp cs1
|
20
|
+
class other_service
|
21
|
+
police 600000000 1000000 exceed-action policed-dscp-transmit
|
22
|
+
set dscp cs2
|
23
|
+
END
|
24
|
+
|
25
|
+
let(:output) do
|
26
|
+
['policy-map', 'mypolicy_in', :EOL,
|
27
|
+
:INDENT,
|
28
|
+
'class', 'myservice_service', :EOL,
|
29
|
+
:INDENT,
|
30
|
+
'police', 300_000_000, 1_000_000, 'exceed-action',
|
31
|
+
'policed-dscp-transmit', :EOL,
|
32
|
+
:INDENT,
|
33
|
+
'set', 'dscp', 'cs1', :EOL,
|
34
|
+
:DEDENT, :DEDENT,
|
35
|
+
'class', 'other_service', :EOL,
|
36
|
+
:INDENT,
|
37
|
+
'police', 600_000_000, 1_000_000, 'exceed-action',
|
38
|
+
'policed-dscp-transmit', :EOL,
|
39
|
+
:INDENT,
|
40
|
+
'set', 'dscp', 'cs2', :EOL, :DEDENT, :DEDENT, :DEDENT
|
41
|
+
]
|
42
|
+
end
|
43
|
+
|
44
|
+
subject { klass.new.call(input).map(&:last) }
|
45
|
+
it('enclosed in symbols') { should == output }
|
46
|
+
|
47
|
+
it('enclosed in symbols (using the pure ruby lexer)') do
|
48
|
+
expect(subject_pure.map(&:last)).to eq output
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
context 'ASR indented regions' do
|
53
|
+
context 'indented region' do
|
54
|
+
let(:input) { <<-END }
|
55
|
+
router static
|
56
|
+
vrf MGMT
|
57
|
+
address-family ipv4 unicast
|
58
|
+
0.0.0.0/0 1.2.3.4
|
59
|
+
!
|
60
|
+
!
|
61
|
+
!
|
62
|
+
router ospf 12345
|
63
|
+
nsr
|
64
|
+
END
|
65
|
+
|
66
|
+
let(:expectation) do
|
67
|
+
['router', 'static', :EOL,
|
68
|
+
:INDENT, 'vrf', 'MGMT', :EOL,
|
69
|
+
:INDENT, 'address-family', 'ipv4', 'unicast', :EOL,
|
70
|
+
:INDENT, '0.0.0.0/0', '1.2.3.4', :EOL,
|
71
|
+
:DEDENT, :DEDENT, :DEDENT,
|
72
|
+
'router', 'ospf', 12_345, :EOL,
|
73
|
+
:INDENT, 'nsr', :EOL,
|
74
|
+
:DEDENT
|
75
|
+
]
|
76
|
+
end
|
77
|
+
|
78
|
+
it 'pure' do
|
79
|
+
tokens = IOSParser::PureLexer.new.call(input)
|
80
|
+
expect(tokens.map(&:last)).to eq expectation
|
81
|
+
end # it 'pure' do
|
82
|
+
|
83
|
+
it 'c' do
|
84
|
+
tokens = IOSParser::CLexer.new.call(input)
|
85
|
+
expect(tokens.map(&:last)).to eq expectation
|
86
|
+
end # it 'c' do
|
87
|
+
end # context 'indented region' do
|
88
|
+
end # context 'ASR indented regions' do
|
89
|
+
|
90
|
+
context 'banners' do
|
91
|
+
let(:input) do
|
92
|
+
<<-END
|
93
|
+
banner foobar ^
|
94
|
+
asdf 1234 9786 asdf
|
95
|
+
line 2
|
96
|
+
line 3
|
97
|
+
^
|
98
|
+
END
|
99
|
+
end
|
100
|
+
|
101
|
+
let(:output) do
|
102
|
+
[[0, 'banner'], [7, 'foobar'], [14, :BANNER_BEGIN],
|
103
|
+
[16, "asdf 1234 9786 asdf\nline 2\nline 3\n "],
|
104
|
+
[52, :BANNER_END], [53, :EOL]]
|
105
|
+
end
|
106
|
+
|
107
|
+
it('tokenized and enclosed in symbols') { should == output }
|
108
|
+
|
109
|
+
it('tokenized and enclodes in symbols (using the pure ruby lexer)') do
|
110
|
+
expect(subject_pure).to eq output
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
context 'decimal number' do
|
115
|
+
let(:input) { 'boson levels at 93.2' }
|
116
|
+
let(:output) { ['boson', 'levels', 'at', 93.2] }
|
117
|
+
subject { klass.new.call(input).map(&:last) }
|
118
|
+
it('converts to Float') { should == output }
|
119
|
+
end
|
120
|
+
|
121
|
+
context 'cryptographic certificate' do
|
122
|
+
let(:input) do
|
123
|
+
<<END
|
124
|
+
crypto pki certificate chain TP-self-signed-0123456789
|
125
|
+
certificate self-signed 01
|
126
|
+
FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF
|
127
|
+
EEEEEEEE EEEEEEEE EEEEEEEE EEEEEEEE EEEEEEEE EEEEEEEE EEEEEEEE EEEEEEEE
|
128
|
+
DDDDDDDD DDDDDDDD DDDDDDDD DDDDDDDD DDDDDDDD DDDDDDDD DDDDDDDD DDDDDDDD AAAA
|
129
|
+
quit
|
130
|
+
!
|
131
|
+
END
|
132
|
+
end
|
133
|
+
|
134
|
+
let(:output) do
|
135
|
+
[[0, 'crypto'],
|
136
|
+
[7, 'pki'],
|
137
|
+
[11, 'certificate'],
|
138
|
+
[23, 'chain'],
|
139
|
+
[29, 'TP-self-signed-0123456789'],
|
140
|
+
[54, :EOL],
|
141
|
+
[56, :INDENT],
|
142
|
+
[56, 'certificate'],
|
143
|
+
[68, 'self-signed'],
|
144
|
+
[80, '01'],
|
145
|
+
[85, :CERTIFICATE_BEGIN],
|
146
|
+
[85,
|
147
|
+
'FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF FFFFFFFF '\
|
148
|
+
'FFFFFFFF EEEEEEEE EEEEEEEE EEEEEEEE EEEEEEEE EEEEEEEE EEEEEEEE '\
|
149
|
+
'EEEEEEEE EEEEEEEE DDDDDDDD DDDDDDDD DDDDDDDD DDDDDDDD DDDDDDDD '\
|
150
|
+
'DDDDDDDD DDDDDDDD DDDDDDDD AAAA'],
|
151
|
+
[323, :CERTIFICATE_END],
|
152
|
+
[323, :EOL],
|
153
|
+
[323, :DEDENT]
|
154
|
+
]
|
155
|
+
end
|
156
|
+
|
157
|
+
subject { klass.new.call(input) }
|
158
|
+
it('tokenized') { expect(subject).to eq output }
|
159
|
+
|
160
|
+
it('tokenized (using the pure ruby lexer)') do
|
161
|
+
expect(subject_pure).to eq output
|
162
|
+
end
|
163
|
+
end
|
164
|
+
|
165
|
+
context 'comments' do
|
166
|
+
let(:input) { 'ip addr 127.0.0.0.1 ! asdfsdf' }
|
167
|
+
let(:output) { ['ip', 'addr', '127.0.0.0.1'] }
|
168
|
+
subject { klass.new.call(input).map(&:last) }
|
169
|
+
it('dropped') { should == output }
|
170
|
+
end
|
171
|
+
|
172
|
+
context 'quoted octothorpe' do
|
173
|
+
let(:input) { <<-EOS }
|
174
|
+
vlan 1
|
175
|
+
name "a #"
|
176
|
+
vlan 2
|
177
|
+
name d
|
178
|
+
EOS
|
179
|
+
|
180
|
+
let(:output) do
|
181
|
+
[
|
182
|
+
'vlan', 1, :EOL,
|
183
|
+
:INDENT, 'name', '"a #"', :EOL,
|
184
|
+
:DEDENT,
|
185
|
+
'vlan', 2, :EOL,
|
186
|
+
:INDENT, 'name', 'd', :EOL,
|
187
|
+
:DEDENT
|
188
|
+
]
|
189
|
+
end
|
190
|
+
|
191
|
+
it { expect(subject_pure.map(&:last)).to eq output }
|
192
|
+
it { expect(subject.map(&:last)).to eq output }
|
193
|
+
end # context 'quoted octothorpe' do
|
194
|
+
|
195
|
+
context 'vlan range' do
|
196
|
+
let(:input) { 'switchport trunk allowed vlan 50-90' }
|
197
|
+
let(:output) do
|
198
|
+
[
|
199
|
+
[0, 'switchport'],
|
200
|
+
[11, 'trunk'],
|
201
|
+
[17, 'allowed'],
|
202
|
+
[25, 'vlan'],
|
203
|
+
[30, '50-90']
|
204
|
+
]
|
205
|
+
end
|
206
|
+
it { should == output }
|
207
|
+
end # context 'vlan range' do
|
208
|
+
|
209
|
+
context 'partial dedent' do
|
210
|
+
let(:input) do
|
211
|
+
<<END
|
212
|
+
class-map match-any foobar
|
213
|
+
description blahblahblah
|
214
|
+
match access-group fred
|
215
|
+
END
|
216
|
+
end
|
217
|
+
|
218
|
+
let(:output) do
|
219
|
+
[
|
220
|
+
'class-map', 'match-any', 'foobar', :EOL,
|
221
|
+
:INDENT, 'description', 'blahblahblah', :EOL,
|
222
|
+
'match', 'access-group', 'fred', :EOL,
|
223
|
+
:DEDENT
|
224
|
+
]
|
225
|
+
end
|
226
|
+
|
227
|
+
it { expect(subject_pure.map(&:last)).to eq output }
|
228
|
+
end
|
229
|
+
end
|
230
|
+
end
|
231
|
+
end
|
@@ -0,0 +1,101 @@
|
|
1
|
+
require_relative '../spec_helper'
|
2
|
+
require 'ios_parser'
|
3
|
+
|
4
|
+
describe IOSParser do
|
5
|
+
describe '.parse' do
|
6
|
+
context 'indented region' do
|
7
|
+
let(:input) { <<-END }
|
8
|
+
policy-map mypolicy_in
|
9
|
+
class myservice_service
|
10
|
+
police 300000000 1000000 exceed-action policed-dscp-transmit
|
11
|
+
set dscp cs1
|
12
|
+
class other_service
|
13
|
+
police 600000000 1000000 exceed-action policed-dscp-transmit
|
14
|
+
set dscp cs2
|
15
|
+
command_with_no_args
|
16
|
+
END
|
17
|
+
|
18
|
+
let(:output) do
|
19
|
+
{
|
20
|
+
commands:
|
21
|
+
[{ args: ['policy-map', 'mypolicy_in'],
|
22
|
+
commands:
|
23
|
+
[{ args: %w(class myservice_service),
|
24
|
+
commands: [{ args: ['police', 300_000_000, 1_000_000,
|
25
|
+
'exceed-action',
|
26
|
+
'policed-dscp-transmit'],
|
27
|
+
commands: [{ args: %w(set dscp cs1),
|
28
|
+
commands: [], pos: 114 }],
|
29
|
+
pos: 50
|
30
|
+
}],
|
31
|
+
pos: 24
|
32
|
+
},
|
33
|
+
|
34
|
+
{ args: %w(class other_service),
|
35
|
+
commands: [{ args: ['police', 600_000_000, 1_000_000,
|
36
|
+
'exceed-action',
|
37
|
+
'policed-dscp-transmit'],
|
38
|
+
commands: [{ args: %w(set dscp cs2),
|
39
|
+
commands: [], pos: 214 },
|
40
|
+
{ args: ['command_with_no_args'],
|
41
|
+
commands: [], pos: 230 }],
|
42
|
+
pos: 150
|
43
|
+
}],
|
44
|
+
pos: 128
|
45
|
+
}],
|
46
|
+
pos: 0
|
47
|
+
}]
|
48
|
+
}
|
49
|
+
end
|
50
|
+
|
51
|
+
subject { described_class.parse(input) }
|
52
|
+
|
53
|
+
it('constructs the right AST') do
|
54
|
+
should be_a IOSParser::IOS::Document
|
55
|
+
expect(subject.to_hash).to eq output
|
56
|
+
end
|
57
|
+
end # context 'indented region'
|
58
|
+
|
59
|
+
context 'partial outdent' do
|
60
|
+
let(:input) do
|
61
|
+
<<END
|
62
|
+
class-map match-any foobar
|
63
|
+
description blah blah blah
|
64
|
+
match access-group fred
|
65
|
+
END
|
66
|
+
end
|
67
|
+
|
68
|
+
let(:output) do
|
69
|
+
{
|
70
|
+
commands:
|
71
|
+
[
|
72
|
+
{
|
73
|
+
args: ['class-map', 'match-any', 'foobar'],
|
74
|
+
commands: [
|
75
|
+
{
|
76
|
+
args: %w(description blah blah blah),
|
77
|
+
commands: [],
|
78
|
+
pos: 29
|
79
|
+
},
|
80
|
+
{
|
81
|
+
args: ['match', 'access-group', 'fred'],
|
82
|
+
commands: [],
|
83
|
+
pos: 57
|
84
|
+
}
|
85
|
+
],
|
86
|
+
pos: 0
|
87
|
+
}
|
88
|
+
]
|
89
|
+
}
|
90
|
+
end
|
91
|
+
|
92
|
+
subject { described_class.parse(input) }
|
93
|
+
|
94
|
+
it 'constructs the right AST' do
|
95
|
+
should be_a IOSParser::IOS::Document
|
96
|
+
actual = subject.to_hash
|
97
|
+
expect(actual).to eq(output)
|
98
|
+
end
|
99
|
+
end # context "partial outdent" do
|
100
|
+
end # describe '.parse'
|
101
|
+
end # describe IOSParser
|
data/spec/spec_helper.rb
ADDED
metadata
ADDED
@@ -0,0 +1,164 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: ios_parser
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.3.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Ben Miller
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2016-03-05 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: rspec
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '3.2'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '3.2'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rubocop
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '0.37'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '0.37'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: guard
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '2.0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '2.0'
|
55
|
+
- !ruby/object:Gem::Dependency
|
56
|
+
name: guard-rspec
|
57
|
+
requirement: !ruby/object:Gem::Requirement
|
58
|
+
requirements:
|
59
|
+
- - "~>"
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
version: '4.5'
|
62
|
+
type: :development
|
63
|
+
prerelease: false
|
64
|
+
version_requirements: !ruby/object:Gem::Requirement
|
65
|
+
requirements:
|
66
|
+
- - "~>"
|
67
|
+
- !ruby/object:Gem::Version
|
68
|
+
version: '4.5'
|
69
|
+
- !ruby/object:Gem::Dependency
|
70
|
+
name: guard-rubocop
|
71
|
+
requirement: !ruby/object:Gem::Requirement
|
72
|
+
requirements:
|
73
|
+
- - "~>"
|
74
|
+
- !ruby/object:Gem::Version
|
75
|
+
version: '1.2'
|
76
|
+
type: :development
|
77
|
+
prerelease: false
|
78
|
+
version_requirements: !ruby/object:Gem::Requirement
|
79
|
+
requirements:
|
80
|
+
- - "~>"
|
81
|
+
- !ruby/object:Gem::Version
|
82
|
+
version: '1.2'
|
83
|
+
- !ruby/object:Gem::Dependency
|
84
|
+
name: rake-compiler
|
85
|
+
requirement: !ruby/object:Gem::Requirement
|
86
|
+
requirements:
|
87
|
+
- - "~>"
|
88
|
+
- !ruby/object:Gem::Version
|
89
|
+
version: '0.9'
|
90
|
+
type: :development
|
91
|
+
prerelease: false
|
92
|
+
version_requirements: !ruby/object:Gem::Requirement
|
93
|
+
requirements:
|
94
|
+
- - "~>"
|
95
|
+
- !ruby/object:Gem::Version
|
96
|
+
version: '0.9'
|
97
|
+
description:
|
98
|
+
email: bjmllr@gmail.com
|
99
|
+
executables: []
|
100
|
+
extensions:
|
101
|
+
- ext/ios_parser/c_lexer/extconf.rb
|
102
|
+
extra_rdoc_files: []
|
103
|
+
files:
|
104
|
+
- ".gitignore"
|
105
|
+
- ".rubocop.yml"
|
106
|
+
- ".travis.yml"
|
107
|
+
- CHANGELOG.md
|
108
|
+
- CODE_OF_CONDUCT.md
|
109
|
+
- Gemfile
|
110
|
+
- Guardfile
|
111
|
+
- LICENSE.txt
|
112
|
+
- README.md
|
113
|
+
- Rakefile
|
114
|
+
- bin/console
|
115
|
+
- bin/setup
|
116
|
+
- doc/state_machine.graphviz
|
117
|
+
- doc/state_machine.png
|
118
|
+
- ext/ios_parser/c_lexer/extconf.rb
|
119
|
+
- ext/ios_parser/c_lexer/lexer.c
|
120
|
+
- ios_parser.gemspec
|
121
|
+
- lib/ios_parser.rb
|
122
|
+
- lib/ios_parser/ios.rb
|
123
|
+
- lib/ios_parser/ios/command.rb
|
124
|
+
- lib/ios_parser/ios/document.rb
|
125
|
+
- lib/ios_parser/ios/queryable.rb
|
126
|
+
- lib/ios_parser/lexer.rb
|
127
|
+
- lib/ios_parser/pure.rb
|
128
|
+
- lib/ios_parser/version.rb
|
129
|
+
- spec/lib/ios_parser/ios/queryable_spec.rb
|
130
|
+
- spec/lib/ios_parser/ios_spec.rb
|
131
|
+
- spec/lib/ios_parser/lexer_spec.rb
|
132
|
+
- spec/lib/ios_parser_spec.rb
|
133
|
+
- spec/spec_helper.rb
|
134
|
+
homepage: https://github.com/bjmllr/ios_parser
|
135
|
+
licenses:
|
136
|
+
- GPL-3.0
|
137
|
+
metadata: {}
|
138
|
+
post_install_message:
|
139
|
+
rdoc_options: []
|
140
|
+
require_paths:
|
141
|
+
- lib
|
142
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
143
|
+
requirements:
|
144
|
+
- - ">="
|
145
|
+
- !ruby/object:Gem::Version
|
146
|
+
version: '0'
|
147
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
148
|
+
requirements:
|
149
|
+
- - ">="
|
150
|
+
- !ruby/object:Gem::Version
|
151
|
+
version: '0'
|
152
|
+
requirements: []
|
153
|
+
rubyforge_project:
|
154
|
+
rubygems_version: 2.5.1
|
155
|
+
signing_key:
|
156
|
+
specification_version: 4
|
157
|
+
summary: convert network switch and router config files to structured data
|
158
|
+
test_files:
|
159
|
+
- spec/lib/ios_parser/ios/queryable_spec.rb
|
160
|
+
- spec/lib/ios_parser/ios_spec.rb
|
161
|
+
- spec/lib/ios_parser/lexer_spec.rb
|
162
|
+
- spec/lib/ios_parser_spec.rb
|
163
|
+
- spec/spec_helper.rb
|
164
|
+
has_rdoc:
|