Skip to content
GitLab
Projects
Groups
Snippets
Help
Loading...
Help
Help
Support
Community forum
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
U
ulg
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
2
Issues
2
List
Boards
Labels
Service Desk
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Operations
Operations
Incidents
Environments
Analytics
Analytics
CI / CD
Repository
Value Stream
Wiki
Wiki
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
labs
ulg
Commits
a9b79b43
Commit
a9b79b43
authored
Oct 03, 2012
by
Tomas Hlavacek
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Add BGP graph for Cisco.
parent
6cfdc78a
Changes
5
Hide whitespace changes
Inline
Side-by-side
Showing
5 changed files
with
250 additions
and
12 deletions
+250
-12
src/config.py.example
src/config.py.example
+2
-2
src/ulg.py
src/ulg.py
+28
-4
src/ulgcisco.py
src/ulgcisco.py
+120
-6
src/ulggraph.py
src/ulggraph.py
+90
-0
src/ulgmodel.py
src/ulgmodel.py
+10
-0
No files found.
src/config.py.example
View file @
a9b79b43
...
...
@@ -21,7 +21,7 @@ from ulgcisco import *
from
ulgbird
import
*
routers
=
[
CiscoRouter
(
host
=
'testrouter1.core.company.com'
,
user
=
'xyz'
,
password
=
'xyz'
),
CiscoRouter
(
host
=
'testrouter2.core.company.com'
,
user
=
'xyz'
,
password
=
'xyz'
),
CiscoRouter
(
host
=
'testrouter1.core.company.com'
,
user
=
'xyz'
,
password
=
'xyz'
,
asn
=
1234
),
CiscoRouter
(
host
=
'testrouter2.core.company.com'
,
user
=
'xyz'
,
password
=
'xyz'
,
asn
=
2345
),
BirdRouterLocal
(
'/var/run/bird.ctl'
)
]
src/ulg.py
View file @
a9b79b43
...
...
@@ -229,6 +229,9 @@ class Session(object):
self
.
range
=
resrange
self
.
save
()
def
showRange
(
self
):
return
self
.
getCommand
().
showRange
()
def
getMaxRange
(
self
):
return
self
.
resultlines
...
...
@@ -264,6 +267,9 @@ class DecoratorHelper:
def
getErrorURL
(
self
,
parameters
=
{}):
return
self
.
getURL
(
'error'
,
parameters
)
def
getSpecialContentURL
(
self
,
sessionid
,
parameters
=
{}):
return
self
.
getURL
(
'getfile'
,
dict
({
'sessionid'
:
sessionid
},
**
parameters
))
def
getRouterID
(
self
,
router
):
for
ridx
,
r
in
enumerate
(
config
.
routers
):
if
(
r
==
router
):
...
...
@@ -287,6 +293,12 @@ class DecoratorHelper:
def
copy_session
(
self
,
session
):
return
Session
(
copy
=
session
)
def
img
(
self
,
url
,
alternative_text
=
None
):
if
(
alternative_text
):
return
(
'<img src="%s" alt="%s">'
%
(
url
,
alternative_text
))
else
:
return
(
'<img src="%s">'
%
url
)
class
ULGCgi
:
def
__init__
(
self
):
...
...
@@ -297,6 +309,11 @@ class ULGCgi:
self
.
decorator_helper
=
DecoratorHelper
()
def
print_text_html
(
self
):
print
"Content-Type: text/html
\n
"
def
increaseUsage
(
self
):
u
=
0
try
:
...
...
@@ -465,6 +482,9 @@ class ULGCgi:
def
renderULGResult
(
self
,
sessionid
=
None
,
resrange
=
0
):
def
getRangeStepURLs
(
session
,
decorator_helper
):
if
(
not
session
.
showRange
()):
return
None
cur_range
=
session
.
getRange
()
max_range
=
session
.
getMaxRange
()
...
...
@@ -573,28 +593,34 @@ class ULGCgi:
if
(
session
==
None
):
return
self
.
HTTPRedirect
(
self
.
decorator_helper
.
getErrorURL
())
return
session
.
getCommand
().
getSpecialContent
(
session
,
**
params
)
# speciality here: the function is responsible for printing the output itself
session
.
getCommand
().
getSpecialContent
(
session
,
**
params
)
def
index
(
self
,
**
params
):
self
.
print_text_html
()
if
(
'sessionid'
in
params
.
keys
()):
print
self
.
renderULGIndex
(
sessionid
=
params
[
'sessionid'
])
else
:
print
self
.
renderULGIndex
()
def
runcommand
(
self
,
routerid
=
0
,
commandid
=
0
,
sessionid
=
None
,
**
params
):
self
.
print_text_html
()
print
self
.
renderULGAction
(
routerid
,
commandid
,
sessionid
,
**
params
)
def
display
(
self
,
sessionid
=
None
,
**
params
):
self
.
print_text_html
()
print
self
.
renderULGResult
(
sessionid
,
**
params
)
def
getfile
(
self
,
sessionid
=
None
,
**
params
):
print
self
.
getULGSpecialContent
(
sessionid
,
**
params
)
self
.
getULGSpecialContent
(
sessionid
,
**
params
)
def
error
(
self
,
sessionid
=
None
,
**
params
):
self
.
print_text_html
()
print
self
.
renderULGError
(
sessionid
,
**
params
)
def
debug
(
self
,
**
params
):
self
.
print_text_html
()
print
self
.
renderULGDebug
(
**
params
)
# main
...
...
@@ -604,8 +630,6 @@ if __name__=="__main__":
form
=
cgi
.
FieldStorage
()
handler
=
ULGCgi
()
print
"Content-Type: text/html
\n
"
action
=
form
.
getvalue
(
'action'
,
None
)
params
=
dict
([(
k
,
form
.
getvalue
(
k
))
for
k
in
form
.
keys
()
if
k
!=
'action'
])
...
...
src/ulgcisco.py
View file @
a9b79b43
...
...
@@ -28,6 +28,7 @@ import string
import
defaults
import
ulgmodel
import
ulggraph
# module globals
STRING_EXPECT_SSH_NEWKEY
=
'Are you sure you want to continue connecting'
...
...
@@ -54,6 +55,111 @@ MAC_ADDRESS_REGEXP = '^[0-9a-fA-F]{4}\.[0-9a-fA-F]{4}\.[0-9a-fA-F]{4}$'
BGP_RED_STATES
=
[
'Idle'
,
'Active'
,
'(NoNeg)'
]
BGP_YELLOW_STATES
=
[
'Idle (Admin)'
,]
REGEX_SH_BGP_UNI_ASLINE
=
'^\s*([0-9\s]+)(|,.*)\s*$'
regex_sh_bgp_uni_asline
=
re
.
compile
(
REGEX_SH_BGP_UNI_ASLINE
)
REGEX_SH_BGP_UNI_AGGR
=
'\s*\(aggregated by ([0-9]+) [0-9a-fA-F:\.]+\).*'
regex_sh_bgp_uni_aggr
=
re
.
compile
(
REGEX_SH_BGP_UNI_AGGR
)
REGEX_SH_BGP_UNI_RECUSE
=
'\s*\(received & used\).*'
regex_sh_bgp_uni_recuse
=
re
.
compile
(
REGEX_SH_BGP_UNI_RECUSE
)
REGEX_SH_BGP_UNI_RECONLY
=
'\s*\(received-only\).*'
regex_sh_bgp_uni_reconly
=
re
.
compile
(
REGEX_SH_BGP_UNI_RECONLY
)
REGEX_SH_BGP_UNI_TABLE_START
=
'\s*Advertised\s+to\s+update-groups.*'
regex_sh_bgp_uni_table_start
=
re
.
compile
(
REGEX_SH_BGP_UNI_TABLE_START
)
REGEX_SH_BGP_UNI_PEERLINE
=
'\s*([0-9a-fA-F:\.]+)\s.*from\s.*'
regex_sh_bgp_uni_peerline
=
re
.
compile
(
REGEX_SH_BGP_UNI_PEERLINE
)
REGEX_SH_BGP_UNI_ORIGLINE_BEST
=
'\s*Origin\s.*\sbest.*'
regex_sh_bgp_uni_origline_best
=
re
.
compile
(
REGEX_SH_BGP_UNI_ORIGLINE_BEST
)
COMMAND_NAME_GRAPH4
=
'Graph - show bgp ipv4 uni <IP subnet>'
def
cisco_parse_sh_bgp_uni
(
lines
,
prependas
):
def
split_ases
(
ases
):
return
str
.
split
(
ases
)
def
get_info
(
info
):
res
=
{
'recuse'
:
False
,
'reconly'
:
False
,
'aggr'
:
None
}
for
g
in
info
.
split
(
','
):
if
(
regex_sh_bgp_uni_recuse
.
match
(
g
)):
res
[
'recuse'
]
=
True
if
(
regex_sh_bgp_uni_reconly
.
match
(
g
)):
res
[
'reconly'
]
=
True
m
=
regex_sh_bgp_uni_aggr
.
match
(
g
)
if
(
m
):
res
[
'aggr'
]
=
m
.
group
(
1
)
return
res
paths
=
[]
table_started
=
False
start_string
=
False
for
l
in
str
.
splitlines
(
lines
):
if
(
table_started
):
m
=
regex_sh_bgp_uni_asline
.
match
(
l
)
if
(
m
):
ases
=
[
"AS"
+
str
(
asn
)
for
asn
in
[
prependas
]
+
split_ases
(
m
.
group
(
1
))]
infotext
=
m
.
group
(
2
)
if
(
infotext
):
paths
.
append
((
ases
,
get_info
(
infotext
)))
else
:
paths
.
append
((
ases
,{
'recuse'
:
False
,
'reconly'
:
False
,
'aggr'
:
None
}))
continue
m
=
regex_sh_bgp_uni_peerline
.
match
(
l
)
if
(
m
):
paths
[
-
1
][
1
][
'peer'
]
=
m
.
group
(
1
)
continue
m
=
regex_sh_bgp_uni_origline_best
.
match
(
l
)
if
(
m
):
paths
[
-
1
][
1
][
'recuse'
]
=
True
else
:
if
(
start_string
):
table_started
=
True
else
:
if
(
regex_sh_bgp_uni_table_start
.
match
(
l
)):
start_string
=
True
return
paths
def
reduce_bgp_paths
(
paths
):
def
has_valid
(
paths
,
onepath
):
for
p
in
paths
:
if
((
onepath
[
0
]
==
p
[
0
])
and
(
not
p
[
1
][
'reconly'
])):
return
True
return
False
def
has_used
(
paths
,
onepath
):
for
p
in
paths
:
if
((
onepath
[
0
]
==
p
[
0
])
and
(
p
[
1
][
'recuse'
])):
return
True
return
False
def
assign_value
(
path
):
if
(
path
[
1
][
'recuse'
]):
return
1
elif
(
path
[
1
][
'reconly'
]):
return
100
else
:
return
10
newpaths
=
[]
for
p
in
paths
:
if
((
p
[
1
][
'reconly'
])
and
has_valid
(
paths
,
p
)):
pass
elif
(
not
(
p
[
1
][
'recuse'
])
and
has_used
(
paths
,
p
)):
pass
else
:
newpaths
.
append
(
p
)
return
sorted
(
newpaths
,
key
=
assign_value
)
def
matchCiscoBGPLines
(
header
,
lines
):
# Match cisco lines formatted to be aligned to columns. Like:
...
...
@@ -472,16 +578,21 @@ class CiscoCommandGraphShowBgpIPv46Uni(ulgmodel.TextCommand):
def
__init__
(
self
,
peers
,
name
=
None
):
ulgmodel
.
TextCommand
.
__init__
(
self
,
self
.
COMMAND_TEXT
,
param_specs
=
[
ulgmodel
.
TextParameter
(
ulgmodel
.
TextParameter
(
IPV4_SUBNET_REGEXP
,
name
=
defaults
.
STRING_IPSUBNET
)
)],
ulgmodel
.
TextParameter
(
IPV4_SUBNET_REGEXP
,
name
=
defaults
.
STRING_IPSUBNET
)],
name
=
name
)
def
decorateResult
(
self
,
session
,
decorator_helper
=
None
):
# TODO return img src=... to result when finished
# decorator_helper.getSpecialContentURL(session!!!)
pass
return
(
decorator_helper
.
img
(
decorator_helper
.
getSpecialContentURL
(
session
.
getSessionId
()),
"BGP graph"
),
1
)
def
getSpecialContent
(
self
,
session
,
**
params
):
return
''
print
"Content-type: image/png
\n
"
paths
=
cisco_parse_sh_bgp_uni
(
session
.
getResult
(),
str
(
session
.
getRouter
().
getASN
()))
ulggraph
.
bgp_graph_gen
(
reduce_bgp_paths
(
paths
),
start
=
session
.
getRouter
().
getName
(),
end
=
session
.
getParameters
()[
0
])
def
showRange
(
self
):
return
False
class
CiscoCommandGraphShowBgpIPv4Uni
(
CiscoCommandGraphShowBgpIPv46Uni
):
COMMAND_TEXT
=
'show bgp ipv4 unicast %s'
...
...
@@ -497,6 +608,7 @@ class CiscoRouter(ulgmodel.RemoteRouter):
_show_bgp_ipv6_uni_neigh
=
CiscoCommandShowBgpIPv6Neigh
(
self
.
getBGPIPv6Peers
())
_show_bgp_ipv6_uni_neigh_advertised
=
CiscoCommandShowBgpIPv6NeighAdv
(
self
.
getBGPIPv6Peers
())
_show_bgp_ipv6_uni_neigh_received_routes
=
CiscoCommandShowBgpIPv6NeighRecv
(
self
.
getBGPIPv6Peers
())
_graph_show_bgp_ipv4_uni
=
CiscoCommandGraphShowBgpIPv4Uni
(
self
.
getBGPIPv4Peers
(),
COMMAND_NAME_GRAPH4
)
return
[
ulgmodel
.
TextCommand
(
'show version'
),
ulgmodel
.
TextCommand
(
'show interfaces status'
),
...
...
@@ -520,9 +632,10 @@ class CiscoRouter(ulgmodel.RemoteRouter):
ulgmodel
.
TextCommand
(
'show ipv6 neighbors %s'
,[
ulgmodel
.
TextParameter
(
'.*'
,
name
=
defaults
.
STRING_NONEORINTORIPADDRESS
)]),
ulgmodel
.
TextCommand
(
'show mac-address-table address %s'
,[
ulgmodel
.
TextParameter
(
MAC_ADDRESS_REGEXP
,
name
=
defaults
.
STRING_MACADDRESS
)]),
ulgmodel
.
TextCommand
(
'show mac-address-table interface %s'
,[
ulgmodel
.
TextParameter
(
'.*'
,
name
=
defaults
.
STRING_INTERFACE
)]),
_graph_show_bgp_ipv4_uni
,
]
def
__init__
(
self
,
host
,
user
,
password
,
port
=
22
,
commands
=
None
,
enable_bgp
=
True
):
def
__init__
(
self
,
host
,
user
,
password
,
port
=
22
,
commands
=
None
,
enable_bgp
=
True
,
asn
=
'My ASN'
):
self
.
setHost
(
host
)
self
.
setPort
(
port
)
self
.
setUser
(
user
)
...
...
@@ -530,6 +643,7 @@ class CiscoRouter(ulgmodel.RemoteRouter):
self
.
bgp_ipv4_peers
=
[]
self
.
bgp_ipv6_peers
=
[]
self
.
setName
(
host
)
self
.
setASN
(
asn
)
if
enable_bgp
:
if
(
defaults
.
rescan_on_display
):
...
...
src/ulggraph.py
0 → 100755
View file @
a9b79b43
#!/usr/bin/env python
#
# ULG - Universal Looking Glass
# by Tomas Hlavacek (tomas.hlavacek@nic.cz)
# last udate: June 21 2012
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
# Imports
import
defaults
import
gv
from
pygraph.classes.digraph
import
digraph
from
pygraph.readwrite.dot
import
write
USED_FILL_COLOR
=
'#DC738A'
FONT_SIZE
=
10
LABEL_FONT_SIZE
=
8
def
bgp_graph_gen
(
graphdata
,
start
=
None
,
end
=
None
):
gr
=
digraph
()
def
add_edge
(
graph
,
v1
,
v2
,
color
=
'black'
,
style
=
'solid'
,
penwidth
=
1.0
,
fillcolor
=
None
,
label
=
None
):
params
=
[(
'fontsize'
,
FONT_SIZE
)]
if
(
fillcolor
):
params
=
params
+
[(
'style'
,
'filled'
),(
'fillcolor'
,
fillcolor
)]
if
(
not
graph
.
has_node
(
v1
)):
graph
.
add_node
(
v1
,
attrs
=
params
)
if
(
not
graph
.
has_node
(
v2
)):
graph
.
add_node
(
v2
,
attrs
=
params
)
if
(
v1
==
v2
):
return
eparams
=
[(
'color'
,
color
),(
'style'
,
style
),(
'penwidth'
,
penwidth
)]
if
(
label
):
eparams
=
eparams
+
[(
'fontsize'
,
LABEL_FONT_SIZE
),(
'label'
,
' '
+
label
+
' '
)]
if
(
not
graph
.
has_edge
((
v1
,
v2
))):
graph
.
add_edge
((
v1
,
v2
),
attrs
=
eparams
)
for
gd
in
graphdata
:
params
=
{}
if
(
gd
[
1
][
'recuse'
]):
params
[
'color'
]
=
'red'
params
[
'penwidth'
]
=
1.2
params
[
'fillcolor'
]
=
USED_FILL_COLOR
elif
(
gd
[
1
][
'reconly'
]):
params
[
'color'
]
=
'gray'
params
[
'style'
]
=
'dotted'
params
[
'penwidth'
]
=
0.5
else
:
params
[
'penwidth'
]
=
0.5
params
[
'color'
]
=
'blue'
if
(
start
):
if
(
not
gr
.
has_node
(
start
)):
gr
.
add_node
(
start
,
attrs
=
[(
'shape'
,
'box'
),(
'style'
,
'filled'
),(
'fillcolor'
,
USED_FILL_COLOR
),(
'fontsize'
,
FONT_SIZE
)])
add_edge
(
gr
,
start
,
gd
[
0
][
0
],
**
{
'color'
:
'red'
,
'penwidth'
:
1.2
,
'style'
:
'dashed'
,
'fillcolor'
:
USED_FILL_COLOR
})
i
=
0
while
(
i
<
len
(
gd
[
0
])):
if
(
i
+
1
<
len
(
gd
[
0
])):
if
((
i
==
0
)
and
(
'peer'
in
gd
[
1
])):
add_edge
(
gr
,
gd
[
0
][
i
],
gd
[
0
][
i
+
1
],
label
=
gd
[
1
][
'peer'
],
**
params
)
else
:
add_edge
(
gr
,
gd
[
0
][
i
],
gd
[
0
][
i
+
1
],
**
params
)
i
=
i
+
1
if
(
not
gr
.
has_node
(
end
)):
gr
.
add_node
(
end
,
attrs
=
[(
'shape'
,
'box'
),(
'style'
,
'filled'
),(
'fillcolor'
,
USED_FILL_COLOR
),(
'fontsize'
,
FONT_SIZE
)])
add_edge
(
gr
,
gd
[
0
][
-
1
],
end
,
**
{
'color'
:
'red'
,
'penwidth'
:
1.2
,
'style'
:
'dashed'
})
dot
=
write
(
gr
)
gvv
=
gv
.
readstring
(
dot
)
gv
.
layout
(
gvv
,
'dot'
)
gv
.
render
(
gvv
,
'png'
)
src/ulgmodel.py
View file @
a9b79b43
...
...
@@ -262,12 +262,16 @@ class TextCommand(object):
def
getSpecialContent
(
self
,
session
,
**
params
):
raise
Exception
(
"getSpecialContet() is not implemented in ulgmodel.TextCommand."
)
def
showRange
(
self
):
return
True
class
AnyCommand
(
TextCommand
):
def
__init__
(
self
):
self
.
command
=
''
self
.
parameter
=
TextParameter
(
'.+'
,
name
=
defaults
.
STRING_COMMAND
)
self
.
name
=
defaults
.
STRING_ANY
self
.
asn
=
'My ASN'
def
getCommandText
(
self
,
parameters
=
None
):
c
=
''
...
...
@@ -335,6 +339,12 @@ class Router(object):
def
getForkNeeded
(
self
):
return
False
def
setASN
(
self
,
asn
):
self
.
asn
=
asn
def
getASN
(
self
):
return
self
.
asn
class
RemoteRouter
(
Router
):
def
getHost
(
self
):
return
self
.
host
...
...
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
.
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment