From 07673a0c31c26da87a35156355d7c51d34768dce Mon Sep 17 00:00:00 2001 From: Lars Vierbergen Date: Tue, 20 Jul 2021 14:04:31 +0200 Subject: [PATCH] Set poolInfo expired to `false` when the expression is `NULL`. In case that the volume is freshly created and is being written to currently, `lastwritten` is `NULL`, which propagates through the expiry calculation formula, resulting in a boolean field being `NULL`. This causes an error to be raised, which results in a log line: Jun 30 23:29:24 backup1 bareos_exporter[21509]: time="2021-06-30T23:29:24Z" level=error msg="sql: Scan error on column index 4, name \"expired\": sql/driver: couldn't convert () into type bool" method=PoolInfo When an error occurs while fetching pool info, statistics about pools are not exported to prometheus at all, which may result in missing data. Fixes #9 --- dataaccess.go | 4 ++-- development/mysql/03-issue-9.sql | 5 +++++ development/postgres/03-issue-9.sql | 5 +++++ 3 files changed, 12 insertions(+), 2 deletions(-) create mode 100644 development/mysql/03-issue-9.sql create mode 100644 development/postgres/03-issue-9.sql diff --git a/dataaccess.go b/dataaccess.go index 86bf746..494f1bc 100644 --- a/dataaccess.go +++ b/dataaccess.go @@ -30,7 +30,7 @@ var queries map[string]*sqlQueries = map[string]*sqlQueries{ LastJob: "SELECT JobStatus,JobBytes,JobFiles,JobErrors,StartTime,COALESCE(EndTime, NOW()) FROM Job WHERE Name = ? AND ClientId = ? AND FileSetId = ? ORDER BY StartTime DESC LIMIT 1", LastSuccessfulJob: "SELECT JobStatus,JobBytes,JobFiles,JobErrors,StartTime,COALESCE(EndTime, NOW()) FROM Job WHERE Name = ? AND ClientId = ? AND FileSetId = ? AND JobStatus IN('T', 'W') ORDER BY StartTime DESC LIMIT 1", LastSuccessfulFullJob: "SELECT JobStatus,JobBytes,JobFiles,JobErrors,StartTime,COALESCE(EndTime, NOW()) FROM Job WHERE Name = ? AND ClientId = ? AND FileSetId = ? AND JobStatus IN('T', 'W') AND Level = 'F' ORDER BY StartTime DESC LIMIT 1", - PoolInfo: "SELECT p.name, sum(m.volbytes) AS bytes, count(*) AS volumes, (not exists(select * from JobMedia jm where jm.mediaid = m.mediaid)) AS prunable, TIMESTAMPADD(SECOND, m.volretention, m.lastwritten) < NOW() AS expired FROM Media m LEFT JOIN Pool p ON m.poolid = p.poolid GROUP BY p.name, prunable, expired", + PoolInfo: "SELECT p.name, sum(m.volbytes) AS bytes, count(*) AS volumes, (not exists(select * from JobMedia jm where jm.mediaid = m.mediaid)) AS prunable, COALESCE(TIMESTAMPADD(SECOND, m.volretention, m.lastwritten) < NOW(), false) AS expired FROM Media m LEFT JOIN Pool p ON m.poolid = p.poolid GROUP BY p.name, prunable, expired", JobStates: "SELECT JobStatus FROM Status", }, "postgres": &sqlQueries{ @@ -38,7 +38,7 @@ var queries map[string]*sqlQueries = map[string]*sqlQueries{ LastJob: "SELECT JobStatus,JobBytes,JobFiles,JobErrors,StartTime::timestamptz,COALESCE(EndTime::timestamptz, NOW()) FROM job WHERE Name = $1 AND ClientId = $2 AND FileSetId = $3 ORDER BY StartTime DESC LIMIT 1", LastSuccessfulJob: "SELECT JobStatus,JobBytes,JobFiles,JobErrors,StartTime::timestamptz,COALESCE(EndTime::timestamptz, NOW()) FROM job WHERE Name = $1 AND ClientId = $2 AND FileSetId = $3 AND JobStatus IN('T', 'W') ORDER BY StartTime DESC LIMIT 1", LastSuccessfulFullJob: "SELECT JobStatus,JobBytes,JobFiles,JobErrors,StartTime::timestamptz,COALESCE(EndTime::timestamptz, NOW()) FROM job WHERE Name = $1 AND ClientId = $2 AND FileSetId = $3 AND JobStatus IN('T', 'W') AND Level = 'F' ORDER BY StartTime DESC LIMIT 1", - PoolInfo: "SELECT p.name, sum(m.volbytes) AS bytes, count(m) AS volumes, (not exists(select * from jobmedia jm where jm.mediaid = m.mediaid)) AS prunable, (m.lastwritten + (m.volretention * interval '1s')) < NOW() as expired FROM media m LEFT JOIN pool p ON m.poolid = p.poolid GROUP BY p.name, prunable, expired", + PoolInfo: "SELECT p.name, sum(m.volbytes) AS bytes, count(m) AS volumes, (not exists(select * from jobmedia jm where jm.mediaid = m.mediaid)) AS prunable, COALESCE((m.lastwritten + (m.volretention * interval '1s')) < NOW(), false) as expired FROM media m LEFT JOIN pool p ON m.poolid = p.poolid GROUP BY p.name, prunable, expired", JobStates: "SELECT JobStatus FROM status", }, } diff --git a/development/mysql/03-issue-9.sql b/development/mysql/03-issue-9.sql new file mode 100644 index 0000000..ed4b679 --- /dev/null +++ b/development/mysql/03-issue-9.sql @@ -0,0 +1,5 @@ +-- Reproduction of https://github.com/vierbergenlars/bareos_exporter/issues/9 + +INSERT INTO Media (volumename, mediatype, firstwritten, lastwritten, labeldate, volstatus, poolid) + VALUES + ('Pool1-0100', 'NULL', NOW() - interval 1 day + interval 30 second, NULL, NOW() - interval 1 day, 'Full', (SELECT poolid from Pool WHERE name = 'Pool1')); diff --git a/development/postgres/03-issue-9.sql b/development/postgres/03-issue-9.sql new file mode 100644 index 0000000..ab7bab5 --- /dev/null +++ b/development/postgres/03-issue-9.sql @@ -0,0 +1,5 @@ +-- Reproduction of https://github.com/vierbergenlars/bareos_exporter/issues/9 + +INSERT INTO public.media (volumename, mediatype, firstwritten, lastwritten, labeldate, volstatus, poolid) + VALUES + ('Pool1-0100', 'NULL', NOW() - interval '1 day' + interval '30s', NULL, NOW() - interval '1 day', 'Full', (SELECT poolid from pool WHERE name = 'Pool1'));