Skip to content

Commit

Permalink
Added acknowledge field to lastseen DB
Browse files Browse the repository at this point in the history
This field can be used to acknowledge an update to an incoming or
outgoing host entry in the lastseen DB. The field is set to `false` when
a key-value pair is updated. `cf-hub` may at any time acknowledge that
the update has been observed by setting the field to `true`.

Ticket: ENT-11838
Changelog: Title
Signed-off-by: Lars Erik Wik <[email protected]>
  • Loading branch information
larsewi committed Oct 14, 2024
1 parent 3534477 commit 5d148d3
Show file tree
Hide file tree
Showing 6 changed files with 104 additions and 1 deletion.
1 change: 1 addition & 0 deletions cf-check/db_structs.h
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
// Struct used for quality entries in /var/cfengine/state/cf_lastseen.lmdb:
typedef struct
{
bool acknowledged;
time_t lastseen;
QPoint Q;
} KeyHostSeen; // Keep in sync with lastseen.h
Expand Down
2 changes: 2 additions & 0 deletions cf-check/dump.c
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,7 @@ static void print_struct_lastseen_quality(
memcpy(&quality, value.mv_data, sizeof(quality));
const time_t lastseen = quality.lastseen;
const QPoint Q = quality.Q;
bool acknowledged = quality.acknowledged;

JsonElement *q_json = JsonObjectCreate(4);
JsonObjectAppendReal(q_json, "q", Q.q);
Expand All @@ -115,6 +116,7 @@ static void print_struct_lastseen_quality(
JsonObjectAppendReal(q_json, "dq", Q.dq);

JsonElement *top_json = JsonObjectCreate(2);
JsonObjectAppendBool(top_json, "acknowledged", acknowledged);
JsonObjectAppendInteger(top_json, "lastseen", lastseen);
JsonObjectAppendObject(top_json, "Q", q_json);

Expand Down
94 changes: 94 additions & 0 deletions libpromises/dbm_migration_lastseen.c
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,12 @@ typedef struct
double var;
} QPoint0;

typedef struct
{
time_t lastseen;
QPoint Q; // Average time between connections (rolling weighted average)
} KeyHostSeen1;

#define QPOINT0_OFFSET 128

/*
Expand Down Expand Up @@ -182,8 +188,96 @@ static bool LastseenMigrationVersion0(DBHandle *db)
return !errors;
}

static bool LastseenMigrationVersion1(DBHandle *db)
{
DBCursor *cursor;
if (!NewDBCursor(db, &cursor))
{
Log(LOG_LEVEL_ERR,
"Unable to create database cursor during lastseen migration");
return false;
}

char *key;
void *value;
int key_size, value_size;

// Iterate through all key-value pairs
while (NextDB(cursor, &key, &key_size, &value, &value_size))
{
if (key_size == 0)
{
Log(LOG_LEVEL_WARNING,
"Found zero-length key during lastseen migration");
continue;
}

// Only look for old KeyHostSeen entries
if (key[0] != 'q')
{
// Warn about completely unexpected keys
if ((key[0] != 'k') && (key[0] != 'a'))
{
Log(LOG_LEVEL_WARNING,
"Found unexpected key '%s' during lastseen migration",
key);
}
continue;
}

KeyHostSeen1 *old_value = value;
KeyHostSeen new_value = {
.acknowledged = true, // We don't know, assume yes
.lastseen = old_value->lastseen,
.Q = old_value->Q,
};

if (!DBCursorDeleteEntry(cursor))
{
Log(LOG_LEVEL_ERR,
"Unable to delete version 1 of entry for key '%s' during lastseen migration",
key);
if (DeleteDBCursor(cursor) == false)
{
Log(LOG_LEVEL_ERR,
"Unable to close cursor during lastseen migration");
}
return false;
}

if (!WriteDB(db, key, &new_value, sizeof(new_value)))
{
Log(LOG_LEVEL_INFO,
"Unable to write version 2 of entry for key '%s' during lastseen migration",
key);
if (DeleteDBCursor(cursor) == false)
{
Log(LOG_LEVEL_ERR,
"Unable to close cursor during lastseen migration");
}
return false;
}
}

if (DeleteDBCursor(cursor) == false)
{
Log(LOG_LEVEL_ERR, "Unable to close cursor during lastseen migration");
return false;
}

if (!WriteDB(db, "version", "2", sizeof("2")))
{
Log(LOG_LEVEL_ERR, "Failed to update version number durling lastseen migration");
return false;
}

Log(LOG_LEVEL_INFO, "Migrated lastseen database from version 1 to 2");
return true;
}

const DBMigrationFunction dbm_migration_plan_lastseen[] =
{
LastseenMigrationVersion0,
LastseenMigrationVersion1,
NULL
};
5 changes: 4 additions & 1 deletion libpromises/lastseen.c
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,10 @@ void UpdateLastSawHost(const char *hostkey, const char *address,
char quality_key[CF_BUFSIZE];
snprintf(quality_key, CF_BUFSIZE, "q%c%s", incoming ? 'i' : 'o', hostkey);

KeyHostSeen newq = { .lastseen = timestamp };
KeyHostSeen newq = {
.acknowledged = false,
.lastseen = timestamp,
};

KeyHostSeen q;
if (ReadDB(db, quality_key, &q, sizeof(q)))
Expand Down
1 change: 1 addition & 0 deletions libpromises/lastseen.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@

typedef struct
{
bool acknowledged; // True when acknowledged by cf-hub, false when updated
time_t lastseen;
QPoint Q; // Average time between connections (rolling weighted average)
} KeyHostSeen;
Expand Down
2 changes: 2 additions & 0 deletions tests/unit/lastseen_test.c
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,7 @@ static void test_newentry(void)
KeyHostSeen q;
assert_int_equal(ReadDB(db, "qiSHA-12345", &q, sizeof(q)), true);

assert_false(q.acknowledged);
assert_int_equal(q.lastseen, 666);
assert_double_close(q.Q.q, 0.0);
assert_double_close(q.Q.dq, 0.0);
Expand Down Expand Up @@ -102,6 +103,7 @@ static void test_update(void)
KeyHostSeen q;
assert_int_equal(ReadDB(db, "qiSHA-12345", &q, sizeof(q)), true);

assert_false(q.acknowledged);
assert_int_equal(q.lastseen, 1110);
assert_double_close(q.Q.q, 555.0);
assert_double_close(q.Q.dq, 555.0);
Expand Down

0 comments on commit 5d148d3

Please sign in to comment.