mirror of
https://dev.lirent.ru/Vatrog/vm-automation-signaling.git
synced 2026-06-26 04:36:37 +03:00
9bde398b6c
- core: runtime attach/detach of a per-endpoint adapter trio (runtime-safe add_adapter + vmsig_core_detach_endpoint, deferred reap) - roster: VMSIG_EV_ROSTER + CAP_ROSTER, retained per-endpoint and replayed to late subscribers - discovery: inotify trigger dir, vmid/endpoint slot allocator, host probe; vmsigd daemon with config + per-uid admission - input driver and vgpu perception built in-tree; vgpu perception as a separate library - memctx: own the supplied ro_fd (closed at detach) - deb packaging: install rules, systemd unit, tmpfiles, default config
97 lines
4.0 KiB
C
97 lines
4.0 KiB
C
/* test_roster.c — VM roster inventory coherence (WS2): VMSIG_EV_ROSTER publish, CAP_ROSTER
|
|
* gating, endpoint_mask scoping, retained-replay to a late subscriber, and DETACH clearing
|
|
* the retained datum. Publish/replay are synchronous (no fd), so the loop is not run: the
|
|
* inproc deliver fires the subscriber callback inline. */
|
|
#define _GNU_SOURCE
|
|
#include "vmsig.h"
|
|
#include "core_internal.h" /* core_roster_publish */
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <stdint.h>
|
|
|
|
static int g_fail = 0;
|
|
#define CHECK(cond, msg) do { \
|
|
if (!(cond)) { printf(" FAIL: %s\n", (msg)); g_fail = 1; } \
|
|
} while (0)
|
|
|
|
typedef struct {
|
|
int count;
|
|
uint32_t ep, vmid, state, action;
|
|
char name[VMSIG_ROSTER_NAME_MAX];
|
|
} robs;
|
|
|
|
static int rob_on_ev(void* u, const vmsig_event* ev) {
|
|
robs* r = u;
|
|
if (ev->kind != VMSIG_EV_ROSTER) return 0;
|
|
const vmsig_roster* e = (const vmsig_roster*)ev->inln;
|
|
r->count++;
|
|
r->ep = ev->endpoint; r->vmid = e->vmid; r->state = e->state; r->action = e->action;
|
|
memcpy(r->name, e->name, sizeof r->name);
|
|
return 0;
|
|
}
|
|
|
|
static int add_robs(vmsig_core* core, robs* r, uint32_t cap, uint64_t epmask) {
|
|
vmsig_inproc_cfg cfg; memset(&cfg, 0, sizeof cfg);
|
|
cfg.on_event = rob_on_ev; cfg.user = r;
|
|
void* ctl = vmsig_inproc_control_new(&cfg);
|
|
vmsig_grant g; memset(&g, 0, sizeof g);
|
|
g.principal = 9; g.endpoint_mask = epmask; g.source_mask = 0xFFFFFFFFu; g.cap_mask = cap;
|
|
return vmsig_core_add_control(core, vmsig_inproc_control_ops(), ctl, &g);
|
|
}
|
|
|
|
static void publish(vmsig_core* core, uint32_t ep, uint32_t vmid, uint32_t state,
|
|
uint32_t action, const char* name) {
|
|
vmsig_roster e; memset(&e, 0, sizeof e);
|
|
e.vmid = vmid; e.state = state; e.action = action;
|
|
snprintf(e.name, sizeof e.name, "%s", name);
|
|
core_roster_publish(core, ep, &e);
|
|
}
|
|
|
|
static void test_roster(void) {
|
|
printf("test_roster\n");
|
|
vmsig_ctx* ctx = vmsig_ctx_new();
|
|
vmsig_core* core = vmsig_core_new(ctx);
|
|
|
|
robs a, b, cc; memset(&a,0,sizeof a); memset(&b,0,sizeof b); memset(&cc,0,sizeof cc);
|
|
add_robs(core, &a, VMSIG_CAP_ROSTER, ~0ull); /* all endpoints, can see roster */
|
|
add_robs(core, &b, VMSIG_CAP_OBSERVE, ~0ull); /* no CAP_ROSTER -> denied */
|
|
add_robs(core, &cc, VMSIG_CAP_ROSTER, 1ull << 0); /* scoped to ep0 only */
|
|
|
|
/* ATTACH ep0 */
|
|
publish(core, 0, 1001, VMSIG_VM_RUNNING, VMSIG_ROSTER_ATTACH, "win-1001");
|
|
CHECK(a.count == 1 && a.ep == 0 && a.vmid == 1001 && a.action == VMSIG_ROSTER_ATTACH,
|
|
"A (CAP_ROSTER) received ATTACH ep0");
|
|
CHECK(strcmp(a.name, "win-1001") == 0, "A: name carried inline");
|
|
CHECK(b.count == 0, "B without CAP_ROSTER does NOT receive roster");
|
|
CHECK(cc.count == 1, "C scoped to ep0 received ep0 ATTACH");
|
|
|
|
/* ATTACH ep1 */
|
|
publish(core, 1, 1002, VMSIG_VM_RUNNING, VMSIG_ROSTER_ATTACH, "win-1002");
|
|
CHECK(a.count == 2 && a.ep == 1 && a.vmid == 1002, "A received ATTACH ep1");
|
|
CHECK(cc.count == 1, "C scoped to ep0 does NOT receive ep1 (endpoint_mask filter)");
|
|
|
|
/* late subscriber D: replay of the retained roster (ep0 + ep1) on add_control */
|
|
robs d; memset(&d, 0, sizeof d);
|
|
add_robs(core, &d, VMSIG_CAP_ROSTER, ~0ull);
|
|
CHECK(d.count == 2, "late subscriber D replayed BOTH retained roster entries");
|
|
|
|
/* DETACH ep0: current subscribers see it; the retained datum is cleared */
|
|
publish(core, 0, 1001, VMSIG_VM_SHUTDOWN, VMSIG_ROSTER_DETACH, "win-1001");
|
|
CHECK(a.count == 3 && a.ep == 0 && a.action == VMSIG_ROSTER_DETACH, "A received DETACH ep0");
|
|
|
|
/* late subscriber E after DETACH: replay yields ONLY ep1 (ep0 cleared) */
|
|
robs e; memset(&e, 0, sizeof e);
|
|
add_robs(core, &e, VMSIG_CAP_ROSTER, ~0ull);
|
|
CHECK(e.count == 1 && e.ep == 1 && e.vmid == 1002,
|
|
"late subscriber E replayed only the live ep1 (detached ep0 not retained)");
|
|
|
|
vmsig_core_free(core);
|
|
vmsig_ctx_free(ctx);
|
|
}
|
|
|
|
int main(void) {
|
|
test_roster();
|
|
printf("roster tests: %s\n", g_fail ? "FAIL" : "PASS");
|
|
return g_fail ? 1 : 0;
|
|
}
|