From 0284c689c32ce3ca77e2014535a4fb74a3c4486a Mon Sep 17 00:00:00 2001 From: pv2b Date: Mon, 24 Apr 2023 16:18:48 +0200 Subject: [PATCH] Fix per-link stats in extractstats There was a bug where traffic would be attributed to the wrong links. The root cause was that "values %knownlinks" was used to get a list of keys corresponding to database columns, that was then used to insert values into the database, in the same order. The problem is that there's no guarantee that "values %knownlinks" will always generate the tags in the same order. Indeed on my system, it generates different order every time. To make sure the order the column names is generated in is stable, from now on, it will sort the column names. Also, it will check the database schema to see if the column names are in the expected order, and if required re-create the database if the column order has changed. --- bin/rrd-extractstats.pl | 21 ++++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/bin/rrd-extractstats.pl b/bin/rrd-extractstats.pl index 538d72f..22b15be 100755 --- a/bin/rrd-extractstats.pl +++ b/bin/rrd-extractstats.pl @@ -38,7 +38,7 @@ my %knownlinks; read_knownlinks(); -my @links = values %knownlinks; +my @links = sort values %knownlinks; # If the DB has it, get latest check timestamp for every ASN we are aware of my $db_version = 1; @@ -50,8 +50,23 @@ try { } $db = DBI->connect("dbi:SQLite:dbname=$statsfile.tmp", '', ''); + # Check if table has expected schema + my $sth = $db->prepare("SELECT name FROM PRAGMA_TABLE_INFO('stats')") or die ("can't check stats table schema"); + $sth->execute(); + ($sth->fetchrow_array eq 'asn') or die('schema mismatch'); + ($sth->fetchrow_array eq 'checked_at') or die('schema mismatch'); + + foreach my $link (@links) { + ($sth->fetchrow_array eq "${link}_in") or die('schema mismatch'); + ($sth->fetchrow_array eq "${link}_out") or die('schema mismatch'); + ($sth->fetchrow_array eq "${link}_v6_in") or die('schema mismatch'); + ($sth->fetchrow_array eq "${link}_v6_out") or die('schema mismatch'); + } + # Make sure there are no more unexpected fields + !defined $sth->fetchrow_array or die('schema mismatch'); + # Get last check timestamps - my $sth = $db->prepare("SELECT asn, checked_at FROM stats") or die('field missing'); + $sth = $db->prepare("SELECT asn, checked_at FROM stats") or die('field missing'); $sth->execute(); while(my($item, $data) = $sth->fetchrow_array()) { $as_list->{$item} = $data; @@ -59,7 +74,7 @@ try { $db_version = 2; } catch ($e) { - print("Previously generated database not found or checked_at field is missing, proceed with all RRD files. ($e)\n"); + print("Previously generated database not found or database schema mismatch, proceed with all RRD files. ($e)\n"); } # walk through all RRD files in the given path and extract stats for all links