diff --git a/flowspec/snmpstats.py b/flowspec/snmpstats.py index ea05b73b46cb1403570e33c9d1c5a66a8a76ac4b..0fe7c639ee3aba203c4b0684da7ff6c83bc56bca 100644 --- a/flowspec/snmpstats.py +++ b/flowspec/snmpstats.py @@ -23,6 +23,7 @@ from django.conf import settings from datetime import datetime, timedelta import json import os +import time from flowspec.models import Route from flowspec.junos import create_junos_name @@ -131,6 +132,36 @@ def get_snmp_stats(): return results +def lock_history_file(wait=1): + first=1 + success=0 + while first or wait: + first=0 + try: + os.mkdir(settings.SNMP_TEMP_FILE+".lock") # TODO use regular file than dir + logger.info("lock_history_file(): creating lock dir succeeded") + success=1 + return success + except OSError, e: + logger.error("lock_history_file(): creating lock dir failed: OSError: "+str(e)) + success=0 + except Exception as e: + logger.error("lock_history_file(): lock already exists") + logger.error("lock_history_file(): creating lock dir failed: "+str(e)) + success=0 + if not success and wait: + time.sleep(1) + return success; + +def unlock_history_file(): + try: + os.rmdir(settings.SNMP_TEMP_FILE+".lock") # TODO use regular file than dir + logger.info("unlock_history_file(): succeeded") + return 1 + except Exception as e: + logger.info("unlock_history_file(): failed "+str(e)) + return 0 + def load_history(): history = {} try: @@ -165,15 +196,29 @@ def helper_rule_ts_parse(ts_string): return ts def poll_snmp_statistics(): - logger.info("Polling SNMP statistics.") - - # load history - history = load_history() + logger.info("poll_snmp_statistics(): Polling SNMP statistics.") - # get new data + # first, determine current ts, before calling get_snmp_stats now = datetime.now() nowstr = now.isoformat() + # get new data + try: + logger.info("poll_snmp_statistics(): snmpstats: nowstr="+str(nowstr)) + newdata = get_snmp_stats() + except Exception as e: + logger.info("poll_snmp_statistics(): get_snmp_stats failed: "+str(e)) + return False + + # lock history file access + success = lock_history_file(1) + if not success: + logger.error("poll_snmp_statistics(): locking history file failed, aborting"); + return False + + # load history + history = load_history() + zero_measurement = { "bytes" : 0, "packets" : 0 } null_measurement = 0 null_measurement_missing = 1 @@ -181,20 +226,22 @@ def poll_snmp_statistics(): try: last_poll_no_time = history['_last_poll_no_time'] except Exception as e: - logger.info("got exception while trying to access history[_last_poll_time]: "+str(e)) + logger.info("poll_snmp_statistics(): got exception while trying to access history[_last_poll_time]: "+str(e)) last_poll_no_time=None + logger.info("poll_snmp_statistics(): snmpstats: last_poll_no_time="+str(last_poll_no_time)) history['_last_poll_no_time']=nowstr try: history_per_rule = history['_per_rule'] except Exception as e: history_per_rule = {} - + + # do actual update try: - logger.info("snmpstats: nowstr="+str(nowstr)+", last_poll_no_time="+str(last_poll_no_time)) - newdata = get_snmp_stats() + logger.info("poll_snmp_statistics(): before store: snmpstats: nowstr="+str(nowstr)+", last_poll_no_time="+str(last_poll_no_time)) + #newdata = get_snmp_stats() - # update history + # proper update history samplecount = settings.SNMP_MAX_SAMPLECOUNT for rule in newdata: counter = {"ts": nowstr, "value": newdata[rule]} @@ -214,7 +261,7 @@ def poll_snmp_statistics(): if ts!=None and (now - ts).total_seconds() >= settings.SNMP_REMOVE_RULES_AFTER: toremove.append(rule) except Exception as e: - logger.info("snmpstats: old rules remove loop: rule="+str(rule)+" got exception "+str(e)) + logger.info("poll_snmp_statistics(): old rules remove loop: rule="+str(rule)+" got exception "+str(e)) for rule in toremove: history.pop(rule, None) @@ -251,7 +298,7 @@ def poll_snmp_statistics(): counter = {"ts": nowstr, "value": newdata[flowspec_params_str]} counter_is_null = False except Exception as e: - logger.info("snmpstats: STATISTICS_PER_RULE: exception: rule_id="+str(rule_id)+" : "+str(e)) + logger.info("poll_snmp_statistics(): STATISTICS_PER_RULE: exception: rule_id="+str(rule_id)+" : "+str(e)) counter = {"ts": nowstr, "value": null_measurement_missing } counter_is_null = True else: @@ -261,10 +308,10 @@ def poll_snmp_statistics(): try: if not rule_id in history_per_rule: if rule_status!="ACTIVE": - logger.info("snmpstats: STATISTICS_PER_RULE: rule_id="+str(rule_id)+" case notexisting inactive") + logger.info("poll_snmp_statistics(): STATISTICS_PER_RULE: rule_id="+str(rule_id)+" case notexisting inactive") #history_per_rule[rule_id] = [counter] else: - logger.info("snmpstats: STATISTICS_PER_RULE: rule_id="+str(rule_id)+" case notexisting active") + logger.info("poll_snmp_statistics(): STATISTICS_PER_RULE: rule_id="+str(rule_id)+" case notexisting active") if counter_is_null: history_per_rule[rule_id] = [counter_zero] else: @@ -272,7 +319,7 @@ def poll_snmp_statistics(): else: rec = history_per_rule[rule_id] if rule_status!="ACTIVE": - logger.info("snmpstats: STATISTICS_PER_RULE: rule_id="+str(rule_id)+" case existing inactive") + logger.info("poll_snmp_statistics(): STATISTICS_PER_RULE: rule_id="+str(rule_id)+" case existing inactive") rec.insert(0, counter) else: last_value = rec[0] @@ -282,20 +329,20 @@ def poll_snmp_statistics(): else: last_ts = helper_stats_store_parse_ts(last_value['ts']) rule_newer_than_last = last_ts==None or rule_last_updated > last_ts - logger.info("snmpstats: STATISTICS_PER_RULE: rule_id="+str(rule_id)+" rule_last_updated="+str(rule_last_updated)+", last_value="+str(last_value)) + logger.info("poll_snmp_statistics(): STATISTICS_PER_RULE: rule_id="+str(rule_id)+" rule_last_updated="+str(rule_last_updated)+", last_value="+str(last_value)) if last_is_null and rule_newer_than_last: - logger.info("snmpstats: STATISTICS_PER_RULE: rule_id="+str(rule_id)+" case existing active 11") + logger.info("poll_snmp_statistics(): STATISTICS_PER_RULE: rule_id="+str(rule_id)+" case existing active 11") if counter_is_null: rec.insert(0, counter_zero) else: rec.insert(0, counter_zero) rec.insert(0, counter) elif last_is_null and not rule_newer_than_last: - logger.info("snmpstats: STATISTICS_PER_RULE: rule_id="+str(rule_id)+" case existing active 10") + logger.info("poll_snmp_statistics(): STATISTICS_PER_RULE: rule_id="+str(rule_id)+" case existing active 10") rec.insert(0, counter_zero) rec.insert(0, counter) elif not last_is_null and rule_newer_than_last: - logger.info("snmpstats: STATISTICS_PER_RULE: rule_id="+str(rule_id)+" case existing active 01") + logger.info("poll_snmp_statistics(): STATISTICS_PER_RULE: rule_id="+str(rule_id)+" case existing active 01") if counter_is_null: rec.insert(0, counter_null) rec.insert(0, counter_zero) @@ -304,10 +351,10 @@ def poll_snmp_statistics(): rec.insert(0, counter_zero) rec.insert(0, counter) elif not last_is_null and not rule_newer_than_last: - logger.info("snmpstats: STATISTICS_PER_RULE: rule_id="+str(rule_id)+" case existing active 00") + logger.info("poll_snmp_statistics(): STATISTICS_PER_RULE: rule_id="+str(rule_id)+" case existing active 00") rec.insert(0, counter) - rec = rec[:samplecount] + history_per_rule[rule_id] = rec[:samplecount] except Exception as e: logger.info("snmpstats: 2 STATISTICS_PER_RULE: exception: "+str(e)) @@ -315,16 +362,28 @@ def poll_snmp_statistics(): # store updated history save_history(history, nowstr) + logger.info("poll_snmp_statistics(): Polling finished.") - logger.info("Polling finished.") except Exception as e: logger.error(e) - logger.error("Polling failed.") - logger.info("Polling end: last_poll_no_time="+str(last_poll_no_time)) + logger.error("poll_snmp_statistics(): Polling failed. exception: "+str(e)) + + unlock_history_file() + logger.info("poll_snmp_statistics(): Polling end: last_poll_no_time="+str(last_poll_no_time)) def add_initial_zero_value(rule_id, zero_or_null=True): logger.info("add_initial_zero_value(): rule_id="+str(rule_id)) + # get new data + now = datetime.now() + nowstr = now.isoformat() + + # lock history file access + success = lock_history_file(1) + if not success: + logger.error("add_initial_zero_value(): locking history file failed, aborting"); + return False + # load history history = load_history() @@ -333,9 +392,6 @@ def add_initial_zero_value(rule_id, zero_or_null=True): except Exception as e: history_per_rule = {} - # get new data - now = datetime.now() - nowstr = now.isoformat() if zero_or_null: zero_measurement = { "bytes" : 0, "packets" : 0 } @@ -346,19 +402,24 @@ def add_initial_zero_value(rule_id, zero_or_null=True): samplecount = settings.SNMP_MAX_SAMPLECOUNT - # TODO: check and if needed remove previous null_measurement try: if rule_id in history_per_rule: - history_per_rule[rule_id].insert(0, counter) - history_per_rule[rule_id] = history_per_rule[rule_id][:samplecount] + rec = history_per_rule[rule_id] + last_rec = rec[0] + if last_rec==None or (zero_or_null and last_rec['value']==0) or ((not zero_or_null) and last_rec['value']!=0): + rec.insert(0, counter) + history_per_rule[rule_id] = rec[:samplecount] else: - history_per_rule[rule_id] = [counter] - except Exception as e: - logger.info("add_initial_zero_value(): 2 STATISTICS_PER_RULE: exception: "+str(e)) + if zero_or_null: + history_per_rule[rule_id] = [counter] - history['_per_rule'] = history_per_rule + history['_per_rule'] = history_per_rule - # store updated history - save_history(history, nowstr) + # store updated history + save_history(history, nowstr) + + except Exception as e: + logger.info("add_initial_zero_value(): failure: exception: "+str(e)) + unlock_history_file() diff --git a/flowspec/tasks.py b/flowspec/tasks.py index 234dc09ac5b9f6f659982934b09577421122fb17..bd9da9c3813eda80d7f0ae686e31a885cb4478e6 100644 --- a/flowspec/tasks.py +++ b/flowspec/tasks.py @@ -86,10 +86,10 @@ def edit(route, callback=None): commit, response = applier.apply(operation="replace") if commit: status = "ACTIVE" - #try: - # snmp_add_initial_zero_value.delay(str(route.id), True) - #except Exception as e: - # logger.error("edit(): route="+str(route)+", ACTIVE, add_initial_zero_value failed: "+str(e)) + try: + snmp_add_initial_zero_value.delay(str(route.id), True) + except Exception as e: + logger.error("edit(): route="+str(route)+", ACTIVE, add_initial_zero_value failed: "+str(e)) else: status = "ERROR" route.status = status @@ -124,10 +124,10 @@ def delete(route, **kwargs): if "reason" in kwargs and kwargs['reason'] == 'EXPIRED': status = 'EXPIRED' reason_text = " Reason: %s " % status - #try: - # snmp_add_initial_zero_value.delay(str(route.id), False) - #except Exception as e: - # logger.error("edit(): route="+str(route)+", INACTIVE, add_null_value failed: "+str(e)) + try: + snmp_add_initial_zero_value.delay(str(route.id), False) + except Exception as e: + logger.error("edit(): route="+str(route)+", INACTIVE, add_null_value failed: "+str(e)) else: status = "ERROR" route.status = status @@ -350,13 +350,11 @@ def snmp_add_initial_zero_value(rule_id, zero_or_null=True): else: logger.info("snmp_add_initial_zero_value(): in child process (pid="+str(pid)+", npid="+str(npid)+")") - if snmp_lock_create(1): - try: - snmpstats.add_initial_zero_value(rule_id, zero_or_null) - logger.info("snmp_add_initial_zero_value(): rule_id="+str(rule_id)+" sucesss") - except Exception as e: - logger.error("snmp_add_initial_zero_value(): rule_id="+str(rule_id)+" failed: "+str(e)) - snmp_lock_remove() + try: + snmpstats.add_initial_zero_value(rule_id, zero_or_null) + logger.info("snmp_add_initial_zero_value(): rule_id="+str(rule_id)+" sucesss") + except Exception as e: + logger.error("snmp_add_initial_zero_value(): rule_id="+str(rule_id)+" failed: "+str(e)) #exit_process() logger.info("exit_process(): before exit in child process (pid="+str(pid)+", npid="+str(npid)+")") diff --git a/templates/flowspy/route_details.html b/templates/flowspy/route_details.html index 6a1bd8e8880e526079052a3534aa85ba61bcc2d8..dc24a79203a14de1cc9c2767631e73c051130b1b 100644 --- a/templates/flowspy/route_details.html +++ b/templates/flowspy/route_details.html @@ -13,6 +13,8 @@ function myreloadPage() { <div class="row"> <div class="col-lg-12"> <h1 class="page-header">{{ route.name }}</h1> + <div>(all times are in {{ tz }}; current System time: {{ mytime|date:'Y-m-d H:i' }})</div> + <br> </div> </div> <div class="row">