Skip to content

Commit 0ab6dcb

Browse files
committed
Add event table, fix defects
Signed-off-by: Matthias Büchse <matthias.buechse@alasca.cloud>
1 parent c017e51 commit 0ab6dcb

2 files changed

Lines changed: 54 additions & 9 deletions

File tree

compliance-monitor/monitor.py

Lines changed: 13 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@
4242
db_get_keys, db_insert_report, db_get_recent_results2, db_patch_approval2, db_get_report,
4343
db_ensure_schema, db_get_apikeys, db_update_apikey, db_filter_apikeys, db_clear_delegates,
4444
db_find_subjects, db_insert_result2, db_get_relevant_results2, db_add_delegate, db_get_group,
45-
db_get_relevant_compliance_results, db_insert_compliance_result,
45+
db_get_relevant_compliance_results, db_insert_compliance_result, db_insert_event,
4646
)
4747

4848

@@ -495,19 +495,19 @@ async def post_report(
495495
result = rdata['result']
496496
approval = 1 == result # pre-approve good result
497497
db_insert_result2(cur, checked_at, subject, scopeuuid, version, check, result, approval, reportid)
498-
conn.commit()
499498

500-
checked_at = datetime.now()
501-
for approved_only in (False, True):
502-
with conn.cursor() as cur:
499+
checked_at = datetime.now()
500+
# add new compliance result if existing compliance result is not newer than `threshold`
501+
threshold = checked_at - timedelta(hours=12)
502+
for approved_only in (False, True):
503503
# fetch latest compliance results before new report
504504
rows = db_get_relevant_compliance_results(cur, approved_only=approved_only)
505505
results0 = defaultdict(lambda: defaultdict(dict))
506506
for row in rows:
507-
subj, scope_uuid, version, result, _, _ = row
507+
subj, scope_uuid, version, result, _, ch_at = row
508508
if subj not in reported_subjects:
509509
continue
510-
results0[subj][scope_uuid][version] = result
510+
results0[subj][scope_uuid][version] = (result, ch_at)
511511
# compute latest compliance results after new report
512512
rows2 = db_get_relevant_results2(cur, approved_only=approved_only)
513513
results = convert_result_rows_to_dict2(rows2, get_scopes())
@@ -517,11 +517,15 @@ async def post_report(
517517
continue
518518
for scope_uuid, scope_results in subj_results.items():
519519
for version, version_results in scope_results['versions'].items():
520-
result = results0[subj][scope_uuid].get(version, 0)
520+
result, ch_at = results0[subj][scope_uuid].get(version, (0, threshold))
521521
new_result = version_results['result']
522-
db_insert_compliance_result(cur, checked_at, subj, scope_uuid, version, new_result, approval)
522+
if new_result != result or ch_at <= threshold:
523+
print(ch_at, threshold)
524+
db_insert_compliance_result(cur, checked_at, subj, scope_uuid, version, new_result, approved_only)
523525
if new_result != result:
526+
db_insert_event(cur, checked_at, subj, scope_uuid, version, result, new_result, approved_only)
524527
print(f"{subj} {scope_uuid} {version}: {result} -> {new_result}")
528+
conn.commit()
525529

526530

527531
def convert_result_rows_to_dict2(

compliance-monitor/sql.py

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -157,6 +157,16 @@ def db_ensure_schema_v5(cur: cursor):
157157
result int,
158158
approval boolean
159159
);
160+
CREATE TABLE IF NOT EXISTS event (
161+
eventid SERIAL PRIMARY KEY,
162+
eventdate timestamp NOT NULL,
163+
subject text NOT NULL,
164+
scopeuuid text NOT NULL,
165+
version text NOT NULL,
166+
old_result int,
167+
new_result int,
168+
approval boolean
169+
);
160170
''')
161171

162172

@@ -481,3 +491,34 @@ def db_get_relevant_compliance_results(
481491
),
482492
), {"subject": subject, "scopeuuid": scopeuuid, "version": version})
483493
return cur.fetchall()
494+
495+
496+
def db_insert_event(
497+
cur: cursor, eventdate, subject, scopeuuid, version, old_result, new_result, approval
498+
):
499+
# this is an exception in that we don't use a record parameter (it's just not as practical here)
500+
cur.execute('''
501+
INSERT INTO event (eventdate, subject, scopeuuid, version, old_result, new_result, approval)
502+
VALUES (%s, %s, %s, %s, %s, %s, %s)
503+
RETURNING eventid;''', (eventdate, subject, scopeuuid, version, old_result, new_result, approval))
504+
resultid, = cur.fetchone()
505+
return resultid
506+
507+
508+
def db_get_recent_events(cur: cursor, approved, limit, skip, max_age_days=None):
509+
"""list recent events without grouping by scope/version/check"""
510+
columns = ('date', 'subject', 'scopeuuid', 'version', 'old_result', 'new_result', 'approval')
511+
cur.execute(sql.SQL('''
512+
SELECT eventdate, subject, scopeuuid, version, old_result, new_result, approval
513+
FROM event
514+
{where_clause}
515+
ORDER BY eventdate
516+
LIMIT %(limit)s OFFSET %(skip)s;''').format(
517+
where_clause=make_where_clause(
518+
None if max_age_days is None else sql.SQL(
519+
f"eventdate > NOW() - interval '{max_age_days:d} days'"
520+
),
521+
None if approved is None else sql.SQL('approval = %(approved)s'),
522+
),
523+
), {"limit": limit, "skip": skip, "approved": approved})
524+
return [{col: val for col, val in zip(columns, row)} for row in cur.fetchall()]

0 commit comments

Comments
 (0)