From 26883abf78c24c3ebdc373cc6f452d2127c82d83 Mon Sep 17 00:00:00 2001 From: cklewar Date: Sat, 7 Apr 2018 02:48:32 +0200 Subject: [PATCH] - update and fixes --- data/{frt.py => fr.py} | 9 +- data/frft.yml | 20 +++ main.py | 296 ++++++++++++++++++++++---------- readme.md | 5 + template/delete-flow-route.conf | 2 +- template/mod-flow-route.conf | 2 +- template/set-flow-route.conf | 2 +- ui/config.yml | 8 +- ui/index.html | 43 ++++- ui/ui.js | 281 ++++++++++++++++++++---------- utils/__init__.py | 0 utils/testdata.py | 56 ++++++ 12 files changed, 529 insertions(+), 195 deletions(-) rename data/{frt.py => fr.py} (82%) create mode 100644 data/frft.yml create mode 100644 utils/__init__.py create mode 100644 utils/testdata.py diff --git a/data/frt.py b/data/fr.py similarity index 82% rename from data/frt.py rename to data/fr.py index 2e8137e..c2f72f1 100644 --- a/data/frt.py +++ b/data/fr.py @@ -17,7 +17,12 @@ # limitations under the License. # +import os + from jnpr.junos.factory import loadyaml from os.path import splitext -_YAML_ = splitext(__file__)[0] + '.yml' -globals().update(loadyaml(_YAML_)) \ No newline at end of file + +_YAML_ = os.getcwd() + '/data/frt.yml' +globals().update(loadyaml(_YAML_)) +_YAML_ = os.getcwd() + '/data/frft.yml' +globals().update(loadyaml(_YAML_)) diff --git a/data/frft.yml b/data/frft.yml new file mode 100644 index 0000000..660ff60 --- /dev/null +++ b/data/frft.yml @@ -0,0 +1,20 @@ +# $Id$ +# Yaml widgets for BGP flow filter data extraction +# - FlowFilterTable extracts 'show firewall filter __flowspec_default_inet__' +# - FlowFilterView identifies most relevant filter fields +# including counter-name, packet-cpunt and byte-count +--- +FlowFilterTable: + rpc: get-firewall-filter-information + args: + filtername: __flowspec_default_inet__ + args_key: filtername + item: filter-information/counter + key: counter-name + view: FlowFilterView + +FlowFilterView: + fields: + name: counter-name + packet_count: packet-count + byte_count: byte-count \ No newline at end of file diff --git a/main.py b/main.py index f2c5d68..48db8d4 100644 --- a/main.py +++ b/main.py @@ -23,10 +23,13 @@ import hashlib import datetime import yaml +import re +import pprint from jnpr.junos.utils.config import Config from jnpr.junos import Device -from data.frt import FlowRoutesTable +from jnpr.junos.exception import ConfigLoadError +from data.fr import FlowRoutesTable, FlowFilterTable class MyDev(object): @@ -34,109 +37,192 @@ class MyDev(object): def __init__(self): self.dev_user = None - self.dev_ip = None self.dev_pw = None self.age_out_interval = None self.flow_active = dict() self.flow_config = dict() + self.filter_active = dict() + self.routers = list() - def addNewFlowRoute(self, flowData=None): + def addNewFlowRoute(self, flowRouteData=None): # env = Environment(autoescape=False, # loader=FileSystemLoader('./template'), trim_blocks=False, lstrip_blocks=False) # template = env.get_template('set-flow-route.conf') - with Device(host=self.dev_ip, user=self.dev_user, password=self.dev_pw) as dev: - cu = Config(dev) - cu.lock() - cu.load(template_path='template/set-flow-route.conf', template_vars=flowData, merge=True) - cu.commit() - cu.unlock() + with Device(host=self.routers[0]['rt1']['ip'], user=self.dev_user, password=self.dev_pw) as dev: - self.flow_config[flowData['flowRouteName']] = {'dstPrefix': flowData['dstPrefix'], - 'srcPrefix': flowData['srcPrefix'], - 'protocol': flowData['protocol'], 'dstPort': flowData['dstPort'], - 'srcPort': flowData['srcPort'], 'action': flowData['action']} + try: - def modFlowRoute(self, flowData=None): + cu = Config(dev) + cu.lock() - with Device(host=self.dev_ip, user=self.dev_user, password=self.dev_pw) as dev: - cu = Config(dev) - cu.lock() - cu.load(template_path='template/mod-flow-route.conf', template_vars=flowData) - cu.commit() - cu.unlock() + cu.load(template_path='template/set-flow-route.conf', template_vars=flowRouteData, merge=True) + cu.commit() + cu.unlock() - self.flow_config[flowData['flowRouteName']] = {'dstPrefix': flowData['dstPrefix'], - 'srcPrefix': flowData['srcPrefix'], - 'protocol': flowData['protocol'], 'dstPort': flowData['dstPort'], - 'srcPort': flowData['srcPort'], 'action': flowData['action']} + except ConfigLoadError as cle: + return False, cle.message - def delFlowRoute(self, flowRoute=None): + self.flow_config[flowRouteData['flowRouteName']] = {'dstPrefix': flowRouteData['dstPrefix'], + 'srcPrefix': flowRouteData['srcPrefix'], + 'protocol': flowRouteData['protocol'], 'dstPort': flowRouteData['dstPort'], + 'srcPort': flowRouteData['srcPort'], 'action': flowRouteData['action']} + return True, 'Successfully added new flow route' - with Device(host=self.dev_ip, user=self.dev_user, password=self.dev_pw) as dev: + def modFlowRoute(self, flowRouteData=None): + + with Device(host=self.routers[0]['rt1']['ip'], user=self.dev_user, password=self.dev_pw) as dev: cu = Config(dev) cu.lock() - cu.load(template_path='template/delete-flow-route.conf', template_vars=flowRoute, merge=True) + cu.load(template_path='template/mod-flow-route.conf', template_vars=flowRouteData) cu.commit() cu.unlock() - self.flow_config.pop(flowRoute['flowRouteName'], None) + self.flow_config[flowRouteData['flowRouteName']] = {'dstPrefix': flowRouteData['dstPrefix'], + 'srcPrefix': flowRouteData['srcPrefix'], + 'protocol': flowRouteData['protocol'], + 'dstPort': flowRouteData['dstPort'], + 'srcPort': flowRouteData['srcPort'], + 'action': flowRouteData['action']} + + def delFlowRoute(self, flowRouteData=None): + + with Device(host=self.routers[0]['rt1']['ip'], user=self.dev_user, password=self.dev_pw) as dev: + + try: + + cu = Config(dev) + cu.lock() + cu.load(template_path='template/delete-flow-route.conf', template_vars=flowRouteData, merge=True) + cu.commit() + cu.unlock() + + except ConfigLoadError as cle: + return False, cle.message + + self.flow_config.pop(flowRouteData['flowRouteName'], None) + + return True, 'Sucessfully deleted flow route' def getActiveFlowRoutes(self): - with Device(host=self.dev_ip, user=self.dev_user, password=self.dev_pw) as dev: + for router in self.routers: + + for name, value in router.iteritems(): + + with Device(host=value['ip'], user=self.dev_user, password=self.dev_pw) as dev: + + # data = dev.rpc.get_config(filter_xml='routing-options/flow/route/name') + frt = FlowRoutesTable(dev) + frt.get() + + for flow in frt: - # data = dev.rpc.get_config(filter_xml='routing-options/flow/route/name') - frt = FlowRoutesTable(dev) - frt.get() + destination = flow.destination.split(',') - for flow in frt: + for index, item in enumerate(destination): + _item = item.split('=') + destination[index] = _item[1] if len(_item) > 1 else _item[0] - destination = flow.destination.split(',') + hash_object = hashlib.sha512(b'{0}{1}'.format(str(destination), str(value['ip']))) + hex_dig = hash_object.hexdigest() - for index, item in enumerate(destination): - _item = item.split('=') - destination[index] = _item[1] if len(_item) > 1 else _item[0] + _age = dict() - hash_object = hashlib.sha512(b'{0}'.format(str(destination))) - hex_dig = hash_object.hexdigest() + if ':' not in flow.age: + _age['current'] = datetime.datetime.strptime(flow.age, '%S').time() + elif len(flow.age.split(':')) == 2: + _age['current'] = datetime.datetime.strptime(flow.age, '%M:%S').time() + elif len(flow.age.split(':')) == 3: + _age['current'] = datetime.datetime.strptime(flow.age, '%H:%M:%S').time() + else: + 'error in time format' + + pattern = r'([^\s]+)' + regex = re.compile(pattern) + _krt_actions = re.findall(regex, flow.tsi) + + if len(_krt_actions) <= 4: + krt_actions = _krt_actions + else: + krt_actions = _krt_actions[4] + + if isinstance(flow.action, str): + if 'traffic-action' in flow.action: + commAction = flow.action.split(":")[1].lstrip().strip() + else: + commAction = None + + elif isinstance(flow.action, list): + commAction = flow.action[1].split(':')[1].lstrip().strip() + else: + commAction = None + + if hex_dig not in self.flow_active: + + self.flow_active[hex_dig] = {'router': name, 'term': flow.term, 'destination': destination, + 'commAction': commAction, 'krtAction': krt_actions, + 'age': _age['current'].strftime("%H:%M:%S"), + 'hash': hex_dig, 'status': 'new'} + else: - _age = dict() + if 'term:N/A' in flow['term']: + self.flow_active.pop(hex_dig, None) - if ':' not in flow.age: - _age['current'] = datetime.datetime.strptime(flow.age, '%S').time() - elif len(flow.age.split(':')) == 2: - _age['current'] = datetime.datetime.strptime(flow.age, '%M:%S').time() - elif len(flow.age.split(':')) == 3: - _age['current'] = datetime.datetime.strptime(flow.age, '%H:%M:%S').time() - else: - 'error in time format' + if _age['current'] > datetime.datetime.strptime(str(self.age_out_interval), + '%H:%M:%S').time(): + self.flow_active[hex_dig]['status'] = 'old' - if hex_dig not in self.flow_active: + try: + if hex_dig in self.flow_active: + self.flow_active[hex_dig].update({'term': flow.term, 'destination': destination, + 'commAction': commAction, 'krtAction': krt_actions, + 'age': _age['current'].strftime("%H:%M:%S")}) + except KeyError as ke: + return False, ke.message - self.flow_active[hex_dig] = {'term': flow.term, 'destination': destination, - 'action': flow.tsi.split(':')[1].strip() if flow.tsi else flow.action, - 'age': _age['current'].strftime("%H:%M:%S"), - 'status': 'new'} - else: + return True, self.flow_active - if 'term:N/A' in flow['term']: - self.flow_active.pop(hex_dig, None) + def get_flow_route_filter(self): - if _age['current'] > datetime.datetime.strptime(str(self.age_out_interval), '%H:%M:%S').time(): - self.flow_active[hex_dig]['status'] = 'old' + if self.routers: - self.flow_active[hex_dig].update({'term': flow.term, 'destination': destination, - 'action': flow.tsi.split(':')[ - 1].strip() if flow.tsi else flow.action, - 'age': _age['current'].strftime("%H:%M:%S")}) + for router in self.routers: - return self.flow_active + for name, value in router.iteritems(): + self.filter_active[name] = list() + + with Device(host=value['ip'], user=self.dev_user, password=self.dev_pw) as dev: + + frft = FlowFilterTable(dev) + frft.get() + + for filter in frft: + + data = filter.name.split(',') + + for didx, item in enumerate(data): + _item = item.split('=') + data[didx] = _item[1] if len(_item) > 1 else _item[0] + + self.filter_active[name].append({'data': data, 'packet_count': filter.packet_count, + 'byte_count': filter.byte_count}) + + return True, self.filter_active def load_flow_config_data(self): - with Device(host=self.dev_ip, user=self.dev_user, password=self.dev_pw) as dev: + dev_ip = list() + + for router in self.routers: + + for name, value in router.iteritems(): + + if 'rr' in value['type']: + dev_ip.append(value['ip']) + + with Device(host=dev_ip[0], user=self.dev_user, password=self.dev_pw) as dev: data = dev.rpc.get_config(options={'format': 'json'}) if 'route' in data['configuration']['routing-options']['flow']: @@ -156,21 +242,20 @@ def load_flow_config_data(self): 'protocol': route['match']['protocol'], 'dstPort': route['match']['destination-port'], 'srcPort': route['match']['source-port'], 'action': _action} - - return self.flow_config + return True, self.flow_config else: - return None + return False, None - def save_settings(self, dev_user=None, dev_ip=None, dev_pw=None, age_out_interval=None): + def save_settings(self, dev_user=None, dev_pw=None, routers=None, age_out_interval=None): self.dev_user = dev_user - self.dev_ip = dev_ip self.dev_pw = dev_pw self.age_out_interval = age_out_interval + self.routers = routers with open('ui/config.yml', 'w') as fp: - config = {'dev_user': self.dev_user, 'dev_ip': self.dev_ip, 'dev_pw': self.dev_pw, + config = {'dev_user': self.dev_user, 'dev_pw': self.dev_pw, 'routers': self.routers, 'age_out_interval': self.age_out_interval} yaml.safe_dump(config, fp, default_flow_style=False) @@ -180,9 +265,9 @@ def load_settings(self): _config = fp.read() config = yaml.safe_load(_config) self.dev_user = config['dev_user'] - self.dev_ip = config['dev_ip'] self.dev_pw = config['dev_pw'] self.age_out_interval = config['age_out_interval'] + self.routers = config['routers'] class BGPFlow(object): @@ -216,42 +301,65 @@ def POST(self, action=None): if action == 'add': input_json = cherrypy.request.json - self.my_dev.addNewFlowRoute(flowData=input_json) - - return True, 'Added new Flow Route' - - elif action == 'save': + resp = self.my_dev.addNewFlowRoute(flowRouteData=input_json) - input_json = cherrypy.request.json - self.my_dev.save_settings(dev_user=input_json['user'], dev_pw=input_json['password'], - dev_ip=input_json['ip'], age_out_interval=input_json['age_out_interval']) - return True, 'Saved settings' + return resp elif action == 'mod': input_json = cherrypy.request.json - self.my_dev.modFlowRoute(flowData=input_json) + self.my_dev.modFlowRoute(flowRouteData=input_json) return True, 'Modified flow route' elif action == 'del': input_json = cherrypy.request.json - self.my_dev.delFlowRoute(flowRoute=input_json) + resp = self.my_dev.delFlowRoute(flowRouteData=input_json) + return resp + + elif action == 'save': - return True, 'Deleted Flow Route' + input_json = cherrypy.request.json + self.my_dev.save_settings(dev_user=input_json['user'], dev_pw=input_json['password'], + dev_ip=input_json['ip'], age_out_interval=input_json['age_out_interval']) + return True, 'Successfully saved configuration settings' else: return False, 'Action not defined' @cherrypy.expose -class DataTable(object): +class Frt(object): def __init__(self, my_dev=None): self.my_dev = my_dev @cherrypy.tools.json_out() def POST(self): - froutes = self.my_dev.load_flow_config_data() - return True, froutes + resp = self.my_dev.getActiveFlowRoutes() + return resp + + +@cherrypy.expose +class Frtc(object): + + def __init__(self, my_dev=None): + self.my_dev = my_dev + + @cherrypy.tools.json_out() + def POST(self): + resp = self.my_dev.load_flow_config_data() + return resp + + +@cherrypy.expose +class Frft(object): + + def __init__(self, my_dev=None): + self.my_dev = my_dev + + @cherrypy.tools.json_out() + def POST(self): + resp = self.my_dev.get_flow_route_filter() + return resp if __name__ == '__main__': @@ -270,7 +378,17 @@ def POST(self): 'tools.response_headers.on': True, 'tools.response_headers.headers': [('Content-Type', 'text/plain')], }, - '/dt': { + '/api/frt': { + 'request.dispatch': cherrypy.dispatch.MethodDispatcher(), + 'tools.response_headers.on': True, + 'tools.response_headers.headers': [('Content-Type', 'text/plain')], + }, + '/api/frct': { + 'request.dispatch': cherrypy.dispatch.MethodDispatcher(), + 'tools.response_headers.on': True, + 'tools.response_headers.headers': [('Content-Type', 'text/plain')], + }, + '/api/frft': { 'request.dispatch': cherrypy.dispatch.MethodDispatcher(), 'tools.response_headers.on': True, 'tools.response_headers.headers': [('Content-Type', 'text/plain')], @@ -281,5 +399,7 @@ def POST(self): my_dev.load_settings() webapp = BGPFlow() webapp.api = BGPFlowWS(my_dev=my_dev) - webapp.dt = DataTable(my_dev=my_dev) + webapp.api.frt = Frt(my_dev=my_dev) + webapp.api.frct = Frtc(my_dev=my_dev) + webapp.api.frft = Frft(my_dev=my_dev) cherrypy.quickstart(webapp, '/', conf) diff --git a/readme.md b/readme.md index 59f147b..456e227 100644 --- a/readme.md +++ b/readme.md @@ -59,6 +59,11 @@ age_out_interval: 00:01:00 dev_ip: 10.11.111.120 dev_pw: juniper123 dev_user: root +asbrs: + - asbr1: + ip: 10.11.111.121 + - asbr2: + ip: 10.11.111.122 ``` - Start tool + Python binary should be in path if not use `which python2.7` to obtian path info diff --git a/template/delete-flow-route.conf b/template/delete-flow-route.conf index b02fdc5..71f6e6b 100644 --- a/template/delete-flow-route.conf +++ b/template/delete-flow-route.conf @@ -1,6 +1,6 @@ routing-options { flow { delete: - route {{flowRouteName}}; + route {{ flowRouteName }}; } } diff --git a/template/mod-flow-route.conf b/template/mod-flow-route.conf index 7172a52..bc1c7d2 100644 --- a/template/mod-flow-route.conf +++ b/template/mod-flow-route.conf @@ -1,6 +1,6 @@ routing-options { flow { - route {{flowRouteName}} { + route {{ flowRouteName }} { replace: match { destination {{dstPrefix}}; diff --git a/template/set-flow-route.conf b/template/set-flow-route.conf index a817570..59858f8 100644 --- a/template/set-flow-route.conf +++ b/template/set-flow-route.conf @@ -1,6 +1,6 @@ routing-options { flow { - route {{flowRouteName}} { + route {{ flowRouteName }} { match { destination {{dstPrefix}}; {%- if dstPort is defined and dstPort !=None %} diff --git a/ui/config.yml b/ui/config.yml index 9e25f41..54835e2 100644 --- a/ui/config.yml +++ b/ui/config.yml @@ -1,4 +1,10 @@ age_out_interval: 00:01:00 -dev_ip: 10.11.111.120 dev_pw: juniper123 dev_user: root +routers: + - rt1: + type: rr + ip: 10.11.111.120 + - rt2: + type: asbr + ip: 10.11.111.121 \ No newline at end of file diff --git a/ui/index.html b/ui/index.html index 6822867..f533b8a 100644 --- a/ui/index.html +++ b/ui/index.html @@ -33,17 +33,19 @@ -

DevOps against DDoS

+

DevOps against DDoS

Monitoring BGP FlowSpec with Junos PyEZ

-
+
@@ -57,7 +59,7 @@

Monitoring BGP Flow

-

Flow Configuration

+

Route Reflector Static Flow Configuration

+

@@ -220,6 +249,7 @@
@@ -293,6 +323,7 @@
diff --git a/ui/ui.js b/ui/ui.js index 83bf127..af71e88 100644 --- a/ui/ui.js +++ b/ui/ui.js @@ -19,6 +19,8 @@ # */ +var interval = 5000; // 1000 = 1 second, 3000 = 3 seconds + $(document).ready(function () { $('a[data-toggle="tab"]').on('shown.bs.tab', function (e) { @@ -31,38 +33,167 @@ $(document).ready(function () { flowRouteDelBtnEventHandler(); saveSettingsBtnEventHandler(); - var t_active_flow = $('#t_active_flow').DataTable({ + var t_flow_config = $('#t_flow_config').DataTable({ + 'ajax' : { + "type" : "POST", + "url" : "/api/frct", + "contentType": "application/json", + "processData": true, + "dataType": "json", + "dataSrc": function (response) { + + var return_data = new Array(); + + $.each( response[1], function( name, flow ) { + + var action_val = new Array(); + + $.each( flow.action, function( action, value ) { + + if (value['value'] === null){ + action_val.push([action]); + + } else { + action_val.push([action, value]); + } + }); + + return_data.push({ + 'name': name, + 'dstPrefix': flow.dstPrefix, + 'dstPort': flow.dstPort, + 'srcPrefix': flow.srcPrefix, + 'srcPort': flow.srcPort, + 'protocol': flow.protocol, + 'action': action_val + }) + }); + return return_data; + } + }, "columns": [ { + "data": "name", "defaultContent": "" }, { + "data": "dstPrefix", "defaultContent": "" }, { + "data": "srcPrefix", "defaultContent": "" }, { + "data": "protocol", "defaultContent": "" }, { + "data": "dstPort", "defaultContent": "" }, { + "data": "srcPort", "defaultContent": "" }, { + "data": "action", "defaultContent": "" - }, - { - "defaultContent": "" - } ] + }] }); - var t_flow_config = $('#t_flow_config').DataTable({ + var t_active_flow = $('#t_active_flow').DataTable({ + + 'ajax' : { + "type" : "POST", + "url" : "/api/frt", + "contentType": "application/json", + "processData": true, + "dataType": "json", + "dataSrc": function (response) { + + var return_data = new Array(); + + $.each( response[1], function( key, flow ) { + + return_data.push({ + 'router': flow.router, + 'term': flow.term, + 'dstPrefix': flow.destination[0], + 'dstPort': flow.destination[3], + 'srcPrefix': flow.destination[1], + 'srcPort': flow.destination[4], + 'protocol': flow.destination[2], + 'krtAction': flow.krtAction, + 'commAction': flow.commAction, + 'age': flow.age + }) + }); + return return_data; + }, + "complete": function (response) { + getActiveFlowRoutes(interval); + } + }, + "createdRow": function( row, data, dataIndex ) { + //console.log(data.age); + //console.log($('#inputAgeOutInterval').val()); + if (data.age <= $('#inputAgeOutInterval').val()) { + $(row).css( 'color', 'red' ).animate( { color: 'black' }); + //console.log('date.age is <= AgeOutInterval'); + + }else { + //console.log('date.age is > AgeOutInterval'); + } + }, + "columns": [ + { + "data": "router", + "defaultContent": "" + }, + { + "data": "term", + "defaultContent": "" + }, + { + "data": "dstPrefix", + "defaultContent": "" + }, + { + "data": "srcPrefix", + "defaultContent": "" + }, + { + "data": "protocol", + "defaultContent": "" + }, + { + "data": "dstPort", + "defaultContent": "" + }, + { + "data": "srcPort", + "defaultContent": "" + }, + { + "data": "krtAction", + "defaultContent": "" + }, + { + "data": "commAction", + "defaultContent": "" + }, + { + "data": "age", + "defaultContent": "" + }] + }); + + var t_active_filter = $('#t_active_filter').DataTable({ + 'ajax' : { "type" : "POST", - "url" : "/dt", + "url" : "/api/frft", "contentType": "application/json", "processData": true, "dataType": "json", @@ -70,29 +201,20 @@ $(document).ready(function () { var return_data = new Array(); - $.each( response[1], function( name, flow ) { - - var action_val = new Array(); - - $.each( flow.action, function( action, value ) { - - if (value['value'] === null){ - action_val.push([action]); - - } else { - action_val.push([action, value]); - } - }); - - return_data.push({ - 'name': name, - 'dstPrefix': flow.dstPrefix, - 'dstPort': flow.dstPort, - 'srcPrefix': flow.srcPrefix, - 'srcPort': flow.srcPort, - 'protocol': flow.protocol, - 'action': action_val - }) + $.each( response[1], function( rname, router ) { + $.each(router, function( fidx, filter ) { + + return_data.push({ + 'name': rname, + 'dstPrefix': filter.data[0], + 'dstPort': filter.data[3], + 'srcPrefix': filter.data[1], + 'srcPort': filter.data[4], + 'protocol': filter.data[2], + 'packetCount': filter.packet_count, + 'byteCount': filter.byte_count + }) + }); }); return return_data; } @@ -123,9 +245,13 @@ $(document).ready(function () { "defaultContent": "" }, { - "data": "action", + "data": "packetCount", + "defaultContent": "" + }, + { + "data": "byteCount", "defaultContent": "" - } ] + }] }); $("#t_flow_config tbody").on('click', 'tr', function () { @@ -138,10 +264,6 @@ $(document).ready(function () { } }); - - - getActiveFlowRoutes(); - $('#selectProtocol').on('change', function(){ var selected = $(this).find("option:selected").val(); @@ -149,19 +271,18 @@ $(document).ready(function () { if ($('#g_icmp').length){ $('#g_icmp').remove(); - } var html = "
" + - "" + - "
" + - "" + - "
" + - "" + - "
" + - "" + - "
" + - "
"; + "" + + "
" + + "" + + "
" + + "" + + "
" + + "" + + "
" + + "
"; $('#fg_protocol').append(html); @@ -169,11 +290,8 @@ $(document).ready(function () { if ($('#g_icmp').length){ $('#g_icmp').remove(); - } } - - }); $('#selectAction').on('change', function(){ @@ -183,7 +301,6 @@ $(document).ready(function () { if ($('#g_community').length){ $('#g_community').remove(); - } var html = "
" + @@ -285,6 +402,13 @@ function addNewFlowRouteConfig(flowRouteData) { title: 'Successfully added new flow route', message: response[1] }) + } else { + + BootstrapDialog.show({ + type: BootstrapDialog.TYPE_WARNING, + title: 'Error adding new flow route', + message: response[1] + }) } }, error : function (data, errorText) { @@ -341,7 +465,13 @@ function delFlowRouteConfig(flowRouteName){ table.row('.selected').remove().draw( false ); BootstrapDialog.show({ type: BootstrapDialog.TYPE_SUCCESS, - title: 'Successfully deletd flow route', + title: 'Successfully deleted flow route', + message: response[1] + }) + } else { + BootstrapDialog.show({ + type: BootstrapDialog.TYPE_WARNING, + title: 'Failed to delete flow route', message: response[1] }) } @@ -352,52 +482,12 @@ function delFlowRouteConfig(flowRouteName){ }); } - -function addActiveFlowRouteToTable(flowData){ - - var t = $('#t_active_flow').dataTable().api(); - - if ( t.data().any() ) { - t.clear().draw(); - - } else {} - - $.each( flowData, function( key, flow ) { - - var newRow = t.row.add([ - flow.term, - flow.destination[0], - flow.destination[1], - flow.destination[2], - flow.destination[3], - flow.destination[4], - flow.action, - flow.age - ]).draw().node() - - if (flow.status == 'new') { - $(newRow).css( 'color', 'red' ).animate( { color: 'black' }); - } - }); -} - -function getActiveFlowRoutes(){ - var interval = 5000; // 1000 = 1 second, 3000 = 3 seconds +function getActiveFlowRoutes(interval){ function poll() { - $.ajax({ - type: 'GET', - url: '/api?action=active', - dataType: 'json', - contentType: 'application/json', - processData: true, - success: function (response) { - addActiveFlowRouteToTable(response[1]); - }, - complete: function (data) { - setTimeout(poll, interval); - } - }); + var t = $('#t_active_flow').dataTable().api(); + console.log('polling' + interval); + t.ajax.reload() } setTimeout(poll, interval); } @@ -412,6 +502,7 @@ function saveSettingsBtnEventHandler(){ data.password = $('#inputDevPassword').val(); data.ip = $('#inputDevIP').val(); data.age_out_interval = $('#inputAgeOutInterval').val(); + inputPollInterval = $('#inputPollInterval').val(); saveSettings(data); }); diff --git a/utils/__init__.py b/utils/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/utils/testdata.py b/utils/testdata.py new file mode 100644 index 0000000..db1a2bf --- /dev/null +++ b/utils/testdata.py @@ -0,0 +1,56 @@ +import os +import random +import StringIO +import pprint +from tempfile import NamedTemporaryFile +from jinja2 import Template, Environment, FileSystemLoader +from jnpr.junos.utils.config import Config +from jnpr.junos import Device +from jnpr.junos.exception import ConfigLoadError + +if __name__ == '__main__': + + print 'Generate static BGP Flow Spec test data on RR device' + + with Device(host='10.11.111.120', user='root', password='juniper123') as dev: + + testdata = dict() + start = 1 + stop = 2 + step = 1 + protocol = ['tcp', 'udp'] + action = ['accept', 'discard', 'sample'] + + for idx in range(start, stop, step): + testdata['flowRoute' + str(idx)] = { + 'dstPrefix': '10.{0}.{1}.{2}/32'.format(random.randint(1, 100), random.randint(1, 100), + random.randint(1, 100)), + 'srcPrefix': '10.{0}.{1}.{2}/32'.format(random.randint(1, 100), random.randint(1, 100), + random.randint(1, 100)), + 'protocol': protocol[random.randint(0, 1)], 'dstPort': '{0}'.format(random.randint(1, 9999)), + 'srcPort': '{0}'.format(random.randint(1, 9999)), 'action': action[random.randint(0, 2)]} + + # pprint.pprint(testdata) + + env = Environment(autoescape=False, + loader=FileSystemLoader('../template'), trim_blocks=False, lstrip_blocks=False) + template = env.get_template('set-flow-route.conf') + + _template = StringIO.StringIO() + + for key, flow in testdata.iteritems(): + _template.write(template.render(flowRouteName=key, **flow)) + + try: + + cu = Config(dev) + cu.lock() + + cu.load(_template.getvalue(), format='text', merge=True) + cu.commit() + cu.unlock() + + except ConfigLoadError as cle: + print cle.message + + _template.close() \ No newline at end of file