Network equipments such as switches know which equipments are connected to them using MAC address tables associated to ports. This can be used to locate those equipments and it enables also to check that the switch configuration is the one required (VLAN, PoE, speed,...). Unfortunately, such tables have to be automatically purged in the network equipments. Luckily, there are network equipments with firmwares allowing to interact with them with a REST API using JSON.
The Data Worker has to periodically collect MAC tables using the REST API then transform and send the resulting data to another Data Worker acting as an HTTP server. The second Data Worker can then propose a dedicated dashboard.
for $i in 1 to 10000
let $step := (
let $pcs := doc('collect.json')?*
let $switches := doc('switches.json')?*
let $login := doc('login.json')
let $result := map {
for $switch in $switches
let $m := fn:doc('http://' || xs:string($switch?ip) ||
':80/rest/v3/login-sessions',
map {'method': 'json', 'http-verb': 'POST',
'timeout': '3000'},
map {'userName': xs:string($login?user),
'password': xs:string($login?password)})
return (if ($m?cookie) then (
let $sessionId := map {'method': 'json', 'http-verb': 'GET',
'http-cookie': xs:string($m?cookie)}
let $vps := doc('http://' || xs:string($switch?ip) ||
':80/rest/v3/vlans-ports', $sessionId)?vlan_port_element?*
let $macs := doc('http://' || xs:string($switch?ip) ||
':80/rest/v3/mac-table', $sessionId)?mac_table_entry_element?*
let $trk := $vps[?port_mode eq 'POM_TAGGED_STATIC' and ?vlan_id ne 5] !
xs:string(?port_id)
for $port in $vps[not(?port_id = $trk)] ! ?port_id
for $vlanid in $vps[?port_id eq $port] ! ?vlan_id
let $portmacs := $macs[?port_id eq $port] ! ietf:mac(?mac_address)
return if (not(empty($portmacs))) then (
for $portmac in $portmacs
let $pcname := local-name(head($pcs[ietf:mac(?mac) eq $portmac]))
let $ename := (if ($pcname) then $pcname else '#' || xs:string($portmac))
return entry {$ename} {map{'switch': local-name($switch),
'port': xs:string($port), 'vlan': xs:string($vlanid)} }
) else ()) else
trace((), local-name($switch) || ': Connection refused. '))
}
let $t := (if (exists($result?*)) then (
trace((),
xs:string(current-dateTime()) || ' ' ||
count(http:send-request(<http:request method='post'/>,
'http://switchmanager:5000/batchcollect.xqy', $result)[2]/node()?*) ||
' MAC entries found. ')
) else
trace((), xs:string(current-dateTime()) ||
' ' || 'No entry. '))
let $pause := prof:sleep(1000 * 60 * 3)
return ()
)
return ()declare %updating function local:mergejsonfile($path, $batch) {
let $doc := doc($path)
let $m := $doc/map()
let $update := (
for $item in $batch?*
return (if ($m?(local-name($item))) then
replace node $m?(local-name($item))/node() with
map:merge(($item/node(), $m?(local-name($item))/node()))
else
insert node entry {local-name($item)} {$item/node()} into $m))
let $write := file:write($path, $doc, map {"indent" : "yes"})
return $batch
};
let $filename := 'collect.json'
let $batch := request:body-doc()
let $tstamp := xs:string(current-dateTime())
let $addstamp :=
(for $item in $batch?*
return (insert node entry btimestamp {$tstamp} into $item/node(), ()))
return local:mergejsonfile($filename, $batch)