diff --git a/flowspec/models.py b/flowspec/models.py index a81a9655281727826bf953458404d90ed781985e..19fc67bf09789a7a704be1d6cc3f8b1f75054bfa 100644 --- a/flowspec/models.py +++ b/flowspec/models.py @@ -213,6 +213,13 @@ class Route(models.Model): else: return None + def then_action1_string(self): + ret="" + for then_action in self.then.all(): + ret=str(then_action) + return ret + return ret + def ip_version(self): route_obj = self @@ -328,6 +335,31 @@ class Route(models.Model): def commit_edit(self, *args, **kwargs): peers = self.applier.userprofile.peers.all() + try: + last_then_str = kwargs['last__then_action__string'] + except: + last_then_str = "" + logger.info('last_then_str=%s' % last_then_str) + + new_then_str = self.then_action1_string() + logger.info('new_then_str=%s' % new_then_str) + + ## + + str_prefix="rate-limit:" + + last__rate_limit="" + if last_then_str[0:len(str_prefix)]==str_prefix: + last__rate_limit=last_then_str[len(str_prefix):] + logger.info('last__rate_limit=%s' % last__rate_limit) + + new__rate_limit="" + if new_then_str[0:len(str_prefix)]==str_prefix: + new__rate_limit=new_then_str[len(str_prefix):] + logger.info('new__rate_limit=%s' % new__rate_limit) + + rate_limit_changed = last__rate_limit != new__rate_limit + #username = None #for peer in peers: # if username: @@ -345,7 +377,7 @@ class Route(models.Model): peer = None send_message('[%s] Editing rule %s. Please wait...' % (self.applier_username_nice, self.name_visible), peer, self) - response = edit.delay(self.pk) + response = edit.delay(self.pk, rate_limit_changed=rate_limit_changed) logger.info('Got edit job id: %s' % response) if not settings.DISABLE_EMAIL_NOTIFICATION: fqdn = Site.objects.get_current().domain diff --git a/flowspec/snmpstats.py b/flowspec/snmpstats.py index ed8b7c2ffd35b047901b28b4262120c1985dcb42..a702a09213a21d8113ebdac5ba8ea0ecf9d088c5 100644 --- a/flowspec/snmpstats.py +++ b/flowspec/snmpstats.py @@ -632,7 +632,7 @@ def remember_oldmatched__for_changed_ratelimitrules_whileactive(rule_id, route_o key_remember_oldmatched = str(rule_id)+".remember_oldmatched_offset" # lock history file access - success = lock_history_file(wait=1, reason="remember_oldmatched__for_changed_ratelimitrules_whileactive("+str(rule_id)+","+str(zero_or_null)+")") + success = lock_history_file(wait=1, reason="remember_oldmatched__for_changed_ratelimitrules_whileactive("+str(rule_id)+")") if not success: logger.error("remember_oldmatched__for_changed_ratelimitrules_whileactive(): locking history file failed, aborting"); return False @@ -647,19 +647,28 @@ def remember_oldmatched__for_changed_ratelimitrules_whileactive(rule_id, route_o try: last_matched__measurement_value = history_per_rule[key_last_measurement]["value_matched"] + last_matched__measurement_value__pkts = last_matched__measurement_value__pkts["packets"] + last_matched__measurement_value__bytes = last_matched__measurement_value__pkts["bytes"] except: - last_matched__measurement_value = 0 + last_matched__measurement_value__pkts = 0 + last_matched__measurement_value__bytes = 0 try: last_matched__remember_offset_value = history_per_rule[key_remember_oldmatched]["value_matched"] + last_matched__remember_offset_value__pkts = last_matched__remember_offset_value["packets"] + last_matched__remember_offset_value__bytes = last_matched__remember_offset_value["bytes"] except: - last_matched__remember_offset_value = 0 + last_matched__remember_offset_value__pkts = 0 + last_matched__remember_offset_value__bytes = 0 # + + #logger.info("remember_oldmatched__for_changed_ratelimitrules_whileactive(): last_matched__measurement_value="+str(last_matched__measurement_value)+" last_matched__remember_offset_value="+str(last_matched__remember_offset_value)); - last_matched__remember_offset_value = last_matched__remember_offset_value + last_matched__measurement_value + last_matched__remember_offset_value__pkts = last_matched__remember_offset_value__pkts + last_matched__measurement_value__pkts + last_matched__remember_offset_value__bytes = last_matched__remember_offset_value__bytes + last_matched__measurement_value__bytes - counter = { "ts": nowstr, "value_matched": last_matched__remember_offset_value } + counter = { "ts": nowstr, "value_matched": { "packets" : last_matched__remember_offset_value__pkts, "bytes" : last_matched__remember_offset_value__bytes } } try: history_per_rule[key_remember_oldmatched] = counter diff --git a/flowspec/tasks.py b/flowspec/tasks.py index 2d35de444c698542f09c9245485c474692cad77a..030108771f607895327e5bc41293c0eaf89bdf71 100644 --- a/flowspec/tasks.py +++ b/flowspec/tasks.py @@ -55,7 +55,7 @@ def add(routepk, callback=None): route.response = response route.save() #snmp_add_initial_zero_value.delay(str(route.id), True) - snmp_add_initial_zero_value(routepk, route.id, add_initial_zero_value=True, zero_or_null=True, reset_remember_last_value=True, update_remember_last_value=False) # route must exist, so that snmp_add_initial_zero_value can find it in DB + snmp_add_initial_zero_value(routepk, route.id, add_initial_value=True, zero_or_null=True, reset_remember_last_value=True, update_remember_last_value=False) # route must exist, so that snmp_add_initial_zero_value can find it in DB elif response=="Task timeout": if deactivate_route.request.retries < settings.NETCONF_MAX_RETRY_BEFORE_ERROR: # repeat the action @@ -71,11 +71,14 @@ def add(routepk, callback=None): @shared_task(ignore_result=True, autoretry_for=(TimeLimitExceeded, SoftTimeLimitExceeded), retry_backoff=True, retry_kwargs={'max_retries': settings.NETCONF_MAX_RETRY_BEFORE_ERROR}) -def edit(routepk, callback=None): +def edit(routepk, rate_limit_changed=False, callback=None): from flowspec.models import Route route = Route.objects.get(pk=routepk) status_pre = route.status logger.info("tasks::edit(): routepk="+str(routepk)+" => route="+str(route)+", status_pre="+str(status_pre)) + + logger.info("tasks::edit(): rate_limit_changed="+str(rate_limit_changed)) + applier = PR.Applier(route_object=route) commit, response = applier.apply(operation="replace") if commit: @@ -83,14 +86,14 @@ def edit(routepk, callback=None): route.response = response route.save() # save() has to be called before snmp_add_initial_zero_value, as last_updated DB filed is updated now on every call of save() and last db_measurement time must become >= this new last_updated value - update_remember_last_value = False; # TODO check whether rate-limit changed ... + update_remember_last_value = rate_limit_changed if update_remember_last_value: # actually wrong to use add_initial_zero_value=True for an edited active rule, as the stats values do not drop to zero on the JUNOS router try: #snmp_add_initial_zero_value.delay(str(route.id), True) #snmp_add_initial_zero_value(routepk, route.id, True, True, True) - snmp_add_initial_zero_value(routepk, route.id, add_initial_zero_value=False, zero_or_null=True, reset_remember_last_value=False, update_remember_last_value=True) + snmp_add_initial_zero_value(routepk, route.id, add_initial_value=False, zero_or_null=True, reset_remember_last_value=False, update_remember_last_value=True) except Exception as e: logger.error("tasks::edit(): route="+str(route)+", ACTIVE, add_initial_zero_value failed: "+str(e)) elif response=="Task timeout": @@ -136,7 +139,7 @@ def deactivate_route(routepk, **kwargs): if commit: route.status="INACTIVE" try: - snmp_add_initial_zero_value(routepk, route.id, add_initial_zero_value=True, zero_or_null=False, reset_remember_last_value=True, update_remember_last_value=False) + snmp_add_initial_zero_value(routepk, route.id, add_initial_value=True, zero_or_null=False, reset_remember_last_value=True, update_remember_last_value=False) except Exception as e: logger.error("tasks::deactivate_route(): route="+str(route)+", INACTIVE, add_null_value failed: "+str(e)) @@ -450,7 +453,7 @@ def poll_snmp_statistics(): @shared_task(ignore_result=True, max_retries=0) def snmp_add_initial_zero_value(routepk, route_id, add_initial_value=True, zero_or_null=True, reset_remember_last_value=True, update_remember_last_value=False): from flowspec import snmpstats - logger.info("snmp_add_initial_zero_value(): routepk="+str(routepk)+" route_id="+str(route_id)) + logger.info("snmp_add_initial_zero_value(): routepk="+str(routepk)+" route_id="+str(route_id)+" add_initial_value="+str(add_initial_value)+" zero_or_null="+str(zero_or_null)+" reset_remember_last_value="+str(reset_remember_last_value)+" update_remember_last_value="+str(update_remember_last_value)) route = None if route==None: @@ -464,7 +467,31 @@ def snmp_add_initial_zero_value(routepk, route_id, add_initial_value=True, zero_ use_fork = False if not use_fork: - snmpstats.add_initial_zero_value(route_id, route, zero_or_null) + + logger.info("snmp_add_initial_zero_value(): (2) routepk="+str(routepk)+" route_id="+str(route_id)+" add_initial_value="+str(add_initial_value)+" zero_or_null="+str(zero_or_null)+" reset_remember_last_value="+str(reset_remember_last_value)+" update_remember_last_value="+str(update_remember_last_value)) + + if add_initial_value: + try: + snmpstats.add_initial_zero_value(route_id, route, zero_or_null) + logger.debug("snmp_add_initial_zero_value(): routepk="+str(routepk)+","+str(zero_or_null)+" add_initial_zero_value sucesss") + except Exception as e: + logger.error("snmp_add_initial_zero_value(): routepk="+str(routepk)+","+str(zero_or_null)+" add_initial_zero_value failed: "+str(e)) + + if reset_remember_last_value: + try: + snmpstats.clean_oldmatched__for_changed_ratelimitrules_whileactive(route_id, route) + logger.debug("snmp_add_initial_zero_value(): routepk="+str(routepk)+","+str(zero_or_null)+" clean_oldmatched__for_changed_ratelimitrules_whileactive sucesss") + except Exception as e: + logger.error("snmp_add_initial_zero_value(): routepk="+str(routepk)+","+str(zero_or_null)+" clean_oldmatched__for_changed_ratelimitrules_whileactive failed: "+str(e)) + + elif update_remember_last_value: + try: + logger.info("snmp_add_initial_zero_value(): (3) routepk="+str(routepk)+" route_id="+str(route_id)+" add_initial_value="+str(add_initial_value)+" zero_or_null="+str(zero_or_null)+" reset_remember_last_value="+str(reset_remember_last_value)+" update_remember_last_value="+str(update_remember_last_value)) + snmpstats.remember_oldmatched__for_changed_ratelimitrules_whileactive(route_id, route) + logger.debug("snmp_add_initial_zero_value(): routepk="+str(routepk)+","+str(zero_or_null)+" remember_oldmatched__for_changed_ratelimitrules_whileactive sucesss") + except Exception as e: + logger.error("snmp_add_initial_zero_value(): routepk="+str(routepk)+","+str(zero_or_null)+" remember_oldmatched__for_changed_ratelimitrules_whileactive failed: "+str(e)) + else: signal.signal(signal.SIGCHLD, handleSIGCHLD) @@ -480,7 +507,7 @@ def snmp_add_initial_zero_value(routepk, route_id, add_initial_value=True, zero_ pid = os.getpid() logger.info("snmp_add_initial_zero_value(): in child process (pid="+str(pid)+", ppid="+str(ppid)+")") - if add_initial_zero_value: + if add_initial_value: try: snmpstats.add_initial_zero_value(route_id, route, zero_or_null) logger.debug("snmp_add_initial_zero_value(): routepk="+str(routepk)+","+str(zero_or_null)+" add_initial_zero_value sucesss") @@ -494,7 +521,7 @@ def snmp_add_initial_zero_value(routepk, route_id, add_initial_value=True, zero_ except Exception as e: logger.error("snmp_add_initial_zero_value(): routepk="+str(routepk)+","+str(zero_or_null)+" clean_oldmatched__for_changed_ratelimitrules_whileactive failed: "+str(e)) - else if update_remember_last_value: + elif update_remember_last_value: try: snmpstats.remember_oldmatched__for_changed_ratelimitrules_whileactive(route_id, route) logger.debug("snmp_add_initial_zero_value(): routepk="+str(routepk)+","+str(zero_or_null)+" remember_oldmatched__for_changed_ratelimitrules_whileactive sucesss") diff --git a/flowspec/views.py b/flowspec/views.py index 9482dac9512b9b47c697e0a87e0649c27e2a102b..20c4a5e227761fa7c1c94305cd56f6a8e57de386 100644 --- a/flowspec/views.py +++ b/flowspec/views.py @@ -482,6 +482,10 @@ def edit_route(request, route_slug): ) return HttpResponseRedirect(reverse("group-routes")) route_original = deepcopy(route_edit) + + last__then_action__string = route_original.then_action1_string() + logger.info("views::edit(): debug: pre pre route.then1="+last__then_action__string) + if request.POST: request_data = request.POST.copy() if request.user.is_superuser: @@ -569,7 +573,22 @@ def edit_route(request, route_slug): route.save() if bool(set(changed_data) & set(critical_changed_values)) or (not route_original.status == 'ACTIVE'): form.save_m2m() - route.commit_edit() + + #logger.info("views::edit(): debug: pre route.then.all()="+str(route_original.then.all())) + #str_prefix="rate-limit:" + #rate_limit="" + #for then_action in route_original.then.all(): + # logger.info("views::edit(): pre debug: str="+str(then_action)) + # logger.info("views::edit(): pre debug: str="+str(then_action)[0:len(str_prefix)]) + # if str(then_action)[0:len(str_prefix)]==str_prefix: + # logger.info("views::edit(): pre debug: rate-limit") + # rate_limit=str(then_action)[len(str_prefix)+1:] + #logger.info("views::edit(): debug: pre after loop") + #last__then_action__string = route_original.then_action1_string() + logger.info("views::edit(): debug: pre pre route.then1="+last__then_action__string) + + route.commit_edit(last__then_action__string=last__then_action__string) + return HttpResponseRedirect(reverse("group-routes")) else: if not request.user.is_superuser: