Skip to content

Commit 95de116

Browse files
committed
fix(db_sqlite): per_second_deltas survives schema mismatch
When a plugin's cumulative-counter cache table schema does not match what the current plugin version expects, the internal insert() call hits an OperationalError. With the default delete_db_on_operational_error=True it then runs rm_db(conn) - which closes the connection - and the explicit drop_table(conn) + recreate path right below blew up with sqlite3.ProgrammingError: Cannot operate on a closed database Hit on production by mysql-aria. Fix: per_second_deltas calls insert() with delete_db_on_operational_error=False so the connection stays alive across the schema-mismatch error, and the plugin-level drop+recreate path can do its work as intended.
1 parent 08c2f65 commit 95de116

2 files changed

Lines changed: 8 additions & 3 deletions

File tree

CHANGELOG.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
2424

2525
### Fixed
2626

27+
* db_sqlite.py: `per_second_deltas()` no longer crashes with `sqlite3.ProgrammingError: Cannot operate on a closed database` when the cache table schema mismatches an earlier plugin version. The internal `insert()` call now uses `delete_db_on_operational_error=False` so the connection survives the schema-mismatch error; the explicit drop/recreate path below operates on a live connection as intended
2728
* base.py: `oao()` now properly HTML-escapes `&`, `<` and `>` into `&amp;`, `&lt;` and `&gt;` instead of replacing `<` and `>` with apostrophes. The previous implementation destroyed legitimate threshold descriptions like `<= 10` and shell snippets like `echo 1 > /proc/sys/...`, turning them into `'= 10` and `echo 1 ' /proc/sys/...` in plugin output. HTML-based web UIs (Icinga Web, Naemon-Adagios) render the entities back to the original characters; terminal viewers see the literal entities, which preserves the information. The XSS-protection goal of the original change is still met
2829
* url.py: `fetch()` with HTTP digest authentication and `insecure=True` now actually disables certificate verification. Previously the digest auth path silently lost the SSL context
2930
* url.py: `fetch()` with `no_proxy=True` now applies the `timeout` parameter. Previously the no-proxy path called `opener.open(request)` without a timeout, so hangs were only caught by the outer plugin wrapper

db_sqlite.py

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@
2828
"""
2929

3030
__author__ = 'Linuxfabrik GmbH, Zurich/Switzerland'
31-
__version__ = '2026051101'
31+
__version__ = '2026051102'
3232

3333
import csv
3434
import hashlib
@@ -921,7 +921,11 @@ def per_second_deltas(filename, name, counters):
921921

922922
row = {'name': name, 'timestamp': time.now()}
923923
row.update(counters)
924-
ok, _ = insert(conn, row)
924+
# Pass `delete_db_on_operational_error=False` so a schema mismatch leaves
925+
# the connection open. We then drop+recreate the table ourselves below;
926+
# the default `True` would `rm_db(conn)` (close + delete) and break the
927+
# subsequent drop_table() with "Cannot operate on a closed database".
928+
ok, _ = insert(conn, row, delete_db_on_operational_error=False)
925929
if not ok:
926930
# Schema mismatch from a previous plugin version (different counter
927931
# columns or NOT NULL constraints). Rebuild the table from the
@@ -933,7 +937,7 @@ def per_second_deltas(filename, name, counters):
933937
close(conn)
934938
return None
935939
create_index(conn, 'name')
936-
ok, _ = insert(conn, row)
940+
ok, _ = insert(conn, row, delete_db_on_operational_error=False)
937941
if not ok:
938942
close(conn)
939943
return None

0 commit comments

Comments
 (0)