CKN plugin: replace oracle plugin and fix event streaming to Patra via CKN broker#65
CKN plugin: replace oracle plugin and fix event streaming to Patra via CKN broker#65nee1k wants to merge 35 commits into
Conversation
…s and allow image_generating to read in ground truth bounding boxes if available
… to determine when to shutdown
- Updated Makefile to replace oracle_plugin with ckn_plugin in build and clean targets. - Modified README to reflect changes in plugin names and environment variables. - Introduced ckn_plugin.py and Dockerfile for the new CKN plugin functionality. - Adjusted installer files to support CKN plugin deployment and configuration. - Updated related scripts and documentation to ensure consistency with the new plugin integration.
# Conflicts: # releases/0.3.3/docker-compose.yml
Fix condition check in Docker workflow for test execution
Provide a built-in PowerProcessor fallback so the CKN plugin can wait for and publish power_summary_report.json even when the standalone module isn't packaged.
Fix CKN power logging
- Fix ENABLE_POWER_MONITORING check to use case-insensitive comparison (.lower() != 'false') - Merge metrics computation from ckn_daemon into ckn_plugin (IoU, mAP, precision, recall, F1) - Add file watching capability for compatibility with oracle_plugin - Create power_processor module for reusable power summary processing - Include running experiment metrics in all Kafka events - Support both ZMQ event mode and file watching mode
Fix power monitoring streaming and merge daemon metrics into ckn_plugin
- Remove dependency on image_mapping_final.json file watching - Use in-memory dictionaries to track image events via ZMQ - Align Kafka event structure with Neo4j Sink Connector schema - Add broker validation and connection testing before streaming - Add test utilities for publishing/consuming Kafka events - Simplify Dockerfile to use standard Python image
…ry shutdown ordering
The JDBC sink connectors on cknkafkaconnect run with
value.converter.schemas.enable=true, so bare-JSON records failed value
conversion and were silently dropped (errors.tolerance=all). Wrap both the
per-image oracle events and the power summary event in Kafka Connect
{"schema": ..., "payload": ...} envelopes, typed to match the patradb
events/power_summary tables (note: Connect's JsonConverter expects "double",
not "float64").
Also fix the shutdown ordering deadlock that prevented the power summary from
ever streaming: the power monitor only writes power_summary_report.json after
receiving PluginTerminate, but the plugin waited for the file before sending
it. Send PluginTerminate first, then wait for and stream the summary.
Verified end-to-end on a Jetstream host: 12 oracle events and the power
summary landed in patradb (events, power_summary, and normalized experiments
tables) via cknbroker.
Automates the PR #65 runbook (build images from this branch, render the install, run a full experiment, verify oracle events + power summary streamed to patradb) so anyone can reproduce the test on their own host without needing access to the VM it was originally verified on. SYNTHETIC_POWER=1 swaps in a fake powerjoular for hosts without RAPL, so the power_summary/experiments rows carry nonzero (synthetic) wattage instead of the 0 W a cloud VM would otherwise report. Verified: ran this exact script from a fresh clone of this branch end to end (SYNTHETIC_POWER=1) -- 12/12 oracle events plus the power summary streamed with zero errors, confirmed independently in patradb.
|
Update: fixed the MODEL_ID issue Samuel hit. Root cause: Fixed in Verified end-to-end with @samuel — both forms of |
Summary
This branch replaces the
oracle_plugin+ external ckn-daemon pair with a single consolidatedckn_plugin, and fixes the event-streaming path so camera-traps experiments actually land in the Patra database (PostgreSQL) via the CKN broker and Kafka Connect JDBC sinks.CKN plugin consolidation
external_plugins/ckn_plugin/combining the oracle plugin's event tracking with the ckn-daemon's Kafka streaming (in-memory state, running experiment metrics: TP/FP/FN, precision/recall/F1, IoU, mAP)ckn_plugininstead oforacle_pluginStreaming fixes (verified end-to-end)
value.converter.schemas.enable=true, so bare-JSON records failed conversion and were silently dropped (errors.tolerance=all). Oracle events and power summaries are now wrapped in{"schema": ..., "payload": ...}envelopes typed to match the patradbevents/power_summarytables. (Note: Connect's JsonConverter expects"double", not"float64".)power_summary_report.jsonafter receivingPluginTerminate, but the plugin previously waited for the file before sending it — so the power event never streamed. Now: terminate first, then wait for and stream the summary, then quit.Testing runbook
Reproduces the end-to-end verification: a full camera-traps experiment on a Linux host streaming per-image oracle events and the shutdown power-summary event through
cknbroker→ Kafka Connect JDBC sinks → the Patra PostgreSQL database (patradb).Quick start:
run_e2e_test.shexternal_plugins/ckn_plugin/run_e2e_test.shautomates everything below (build → render → run → verify → teardown). On any Linux host with Docker + Compose v2 and ~25 GB free disk:It prints the
psqlqueries to run against patradb at the end (you'll need patradb credentials — see prerequisites below) and a pass/fail summary based on the ckn_plugin log (expects 12 oracle events + 1 power summary + 0 errors). Verified independently on a fresh clone withSYNTHETIC_POWER=1: 12/12 events + power summary streamed, 0 errors, confirmed in patradb.Override identities/version with env vars if the defaults (
example_user/example_device/ model2) don't fit your patradb:USER_ID,DEVICE_ID,MODEL_ID,TRAPS_REL,EXPERIMENT_ID,WORKDIR.The manual steps below are the same thing spelled out, useful if you want to inspect or modify part of the flow.
0. Prerequisites
psql(or any Postgres client) somewhere with the patradb credentials — get them from the Tapispatradbpod definition or a project maintainer. Never commit them.user_idinusers.username,device_idinedge_devices.device_id. The examples below useexample_user/example_device, which exist today.MODEL_IDaccepts two forms (as of patra-knowledge-base@e72413a): either the numeric patradbmodels.id(e.g.2), or camera-traps' own native model_id — a Patra model-card UUID, optionally suffixed-model(e.g.ea991e85-feaa-4781-a297-4d7bec1a69b1-model, the form the installer's own defaults andimage_generating_pluginactually produce). Either way the model must already exist in patradb (models/model_cards) — this doesn't auto-register new models.1. Build images from this branch
The published
tapis/ckn_plugin:0.6.0andtapis/camera-traps-installer:0.6.0images predate this branch (the released installer still renders the old oracle_plugin/ckn-daemon stack with a broken broker URL), so build both locally:The locally built
tapis/ckn_plugin:0.6.0shadows the Docker Hub image when compose starts.2. Create the experiment workspace
Why
inference_server: false+local_model_path: the default megadetector-server downloads its model from the legacypatraserverendpoint at startup, and that service's Neo4j backend is retired (returns 500) — the container crashloops. Thelocal_model_pathbranch skips all model downloads and mounts a local weights file instead.3. Render the install and provide the model file
Sanity-check the render:
grep -n 'CKN_KAFKA_BROKER\|EXPERIMENT_ID\|image: tapis/ckn_plugin' ~/ct-e2e/e2e_test/docker-compose.ymlshould showcknbroker.pods.icicleai.tapis.io:443, your experiment UUID, andtapis/ckn_plugin:0.6.0.Note: the installer refuses to render into an existing
install_dir— to rerun, move the.ptfile out,rm -rf ~/ct-e2e/e2e_test, and repeat this step (with a freshexperiment_id).4. Run the experiment
The stack processes the 12 bundled example images (~2 minutes on CPU). Expected in the ckn_plugin log, in order:
Successfully connected to Kafka broker!(SSL tocknbroker...:443)KAFKA EVENT - Publishing to topic 'oracle-events'…Successfully streamed event to Kafka for UUID: …All images processed. Initiating shutdown...→Sent PluginTerminate * eventKAFKA POWER EVENT - Publishing to topic 'cameratraps-power-summary'→Power summary successfully streamed to Kafka.(the power monitor writes its summary within ~1 s of the terminate — this ordering is exactly what this branch fixes)Exited (0)).5. Verify rows landed in patradb
Expected: 12
eventsrows; 1power_summaryrow; 1experimentsrow (total_images=12, nonzero metrics). Theexperimentsrow updates live during the run, so you can poll it mid-experiment. Also confirm the Connect worker logged no converter/DB errors for your records.6. Teardown
Known caveats
errors.tolerance=all), so nothing lands. Register the entities and replay, or use the pre-registered examples.RUNNINGdoes not imply records are landing — per-record failures are swallowed byerrors.tolerance=all. Always verify with the SQL queries above and the Connect worker logs.Optional: synthetic power readings on hosts without RAPL (test-only)
To verify the power path carries nonzero values on a VM, swap the powerjoular measurement container for a synthetic stand-in — no camera-traps code changes; the backend reads the image name from the
POWER_JOULAR_IMAGEenv var at runtime. The stand-in must honor the same CLI (-tp <pid> -f <output_path>) and emit the 5-column CSV (Date,CPU Utilization,Total Power,CPU Power,GPU Power) one row per second.The
power_summaryrow (andexperiments.total_cpu_power_w/total_gpu_power_w) for that experiment will then carry the synthetic nonzero wattage. Label such experiments clearly — the power numbers are fabricated for pipeline testing, not measurements.Reference runs
2026-07-15, Jetstream Ubuntu 22.04 x86_64 host, zero Connect errors in both:
027de96a-f744-48c2-b933-373be3956e65(real powerjoular): 12/12 oracle events + power summary landed (events=12,power_summary=1,experimentsrow with precision 0.075 / recall 1.0 / F1 0.14 over 80 predictions); wattage 0 W since the VM exposes no RAPL.060009f9-6a0f-40f3-b6f1-3e3a2eaecfce(synthetic powerjoular stand-in): 12/12 oracle events + power summary with nonzero wattage (total CPU 11.90 W, total GPU 0.56 W across the three monitored plugins), propagated intoexperiments.total_cpu_power_w/total_gpu_power_w. Power values are synthetic, for pipeline verification only.