feat: software updates plugin system with 8 SOVD endpoints#231
Merged
Conversation
Define OTA scenarios: no-plugin 501, CRUD lifecycle, prepare/execute workflow, automated mode, error cases. All tests expected to fail until implementation is complete.
Define abstract UpdateBackend class with CRUD + async operations, UpdateProgressReporter for optional progress reporting, new requirements REQ_INTEROP_091-094 for async update endpoints, and vendor-specific error codes for update operations.
Stores metadata in memory, simulates prepare/execute with 4 steps (100ms each) and progress reporting. Used as test fixture for integration tests.
Background threads for prepare/execute/automated. Automatic status tracking (Pending->InProgress->Completed/Failed) with optional progress enrichment via UpdateProgressReporter. Uses unique_ptr for PackageState pointer stability.
Uses dlopen/dlsym to load extern C create_update_backend() factory. Returns backend + handle pair for UpdateManager ownership.
HTTP handler class for all SOVD software update REST endpoints:
- GET /updates (list with origin/target-version filters)
- POST /updates (register new package)
- GET /updates/{id} (get package details)
- DELETE /updates/{id} (remove package)
- PUT /updates/{id}/prepare (start prepare phase)
- PUT /updates/{id}/execute (start execute phase)
- PUT /updates/{id}/automated (prepare+execute in one)
- GET /updates/{id}/status (poll async operation status)
Includes check_backend() guard (501 if no plugin loaded) and
status_to_json() converter for UpdateStatusInfo.
Load updates config from parameters (updates.enabled, updates.backend, updates.plugin_path), instantiate UpdateManager with plugin backend (or nullptr for 501 mode), register 8 routes in REST server.
Add update_manager.cpp, plugin_loader.cpp, update_handlers.cpp to gateway_lib. Build test_update_backend.so MODULE for integration tests. Link dl library. Add updates config section to params YAML.
Unit tests cover CRUD, prepare/execute workflow, automated mode, status polling, and error cases (no backend, not prepared, duplicate, delete during operation). Fix deadlock in ~UpdateManager: collect futures under lock, then wait outside lock to avoid blocking async tasks that also need the mutex.
…ception handling Replace string-based error matching with typed UpdateErrorCode enum throughout UpdateManager, handlers, and tests. Fix TOCTOU races by adding Deleting sentinel phase and moving backend validation inside mutex. Wrap async prepare/execute/automated in try-catch for exception safety. Add plugin loader exception safety to prevent dlopen handle leaks. Validate entity IDs in all handlers, fix register response to return JSON body with 201, and change state-conflict errors from 405 to 409. Add 3 new unit tests (backend failure, exception, concurrent reject), integration tests for malformed JSON and target-version filter, and complete REST API docs, changelog, and config reference for software updates.
Contributor
There was a problem hiding this comment.
Pull request overview
This PR implements a comprehensive software updates management system for ros2_medkit with 8 SOVD-compliant REST endpoints, following a plugin-based architecture for maximum extensibility. The implementation adds async update lifecycle management (prepare/execute/automated) with status polling, full error handling, and comprehensive test coverage.
Changes:
- Plugin-based UpdateBackend architecture with runtime loading via dlopen
- 8 REST endpoints: list, register, get, delete, prepare, execute, automated, and status
- Async operation management with thread-safe status tracking and progress reporting
- Full test suite: 14 unit tests + comprehensive integration test scenarios
- Documentation updates: API reference, configuration guide, roadmap, changelog, requirements
Reviewed changes
Copilot reviewed 24 out of 24 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
src/ros2_medkit_gateway/include/ros2_medkit_gateway/updates/update_backend.hpp |
Plugin interface with UpdateBackend base class and progress reporter |
src/ros2_medkit_gateway/include/ros2_medkit_gateway/updates/update_manager.hpp |
Manager orchestrating async lifecycle and state tracking |
src/ros2_medkit_gateway/include/ros2_medkit_gateway/updates/plugin_loader.hpp |
dlopen-based plugin loader with error handling |
src/ros2_medkit_gateway/src/updates/update_manager.cpp |
Thread-safe async operations with deadlock-free destructor |
src/ros2_medkit_gateway/src/updates/plugin_loader.cpp |
Plugin loading implementation with symbol resolution |
src/ros2_medkit_gateway/src/http/handlers/update_handlers.cpp |
HTTP handlers for 8 update endpoints with proper error mapping |
src/ros2_medkit_gateway/src/http/rest_server.cpp |
Route registration with correct ordering (specific before generic) |
src/ros2_medkit_gateway/src/gateway_node.cpp |
Update manager initialization with plugin loading |
src/ros2_medkit_gateway/test/test_update_manager.cpp |
14 unit tests covering CRUD, lifecycle, concurrency, error cases |
src/ros2_medkit_gateway/test/demo_nodes/test_update_backend.cpp |
Demo plugin implementation for integration testing |
src/ros2_medkit_integration_tests/test/features/test_updates.test.py |
Integration tests covering all 8 endpoints with 501 mode and plugin mode |
src/ros2_medkit_gateway/include/ros2_medkit_gateway/http/error_codes.hpp |
5 new vendor-specific error codes with x-medkit- prefix |
src/ros2_medkit_gateway/config/gateway_params.yaml |
Configuration parameters for updates feature |
docs/api/rest.rst |
REST API documentation for all 8 endpoints |
docs/config/server.rst |
Configuration guide for updates plugin system |
docs/requirements/specs/updates.rst |
Requirements tracking with @verifies links |
docs/roadmap.rst |
Roadmap update marking Updates as completed |
docs/changelog.rst |
Changelog entry describing the feature |
README.md |
Features table update showing Updates as Available |
CMakeLists.txt |
Build configuration for UpdateManager, plugin loader, handlers, and test plugin |
GitHub generates line anchors (#L123) dynamically via JavaScript, so Sphinx linkcheck reports them as broken. Use linkcheck_anchors_ignore_for_url to skip anchor checks while still verifying the pages exist.
mfaferek93
reviewed
Feb 22, 2026
Collaborator
mfaferek93
left a comment
There was a problem hiding this comment.
Review
Clean plugin system with good separation of concerns. Found a few thread-safety issues in UpdateManager and a validation ordering bug in the handler. Details in inline comments.
src/ros2_medkit_gateway/include/ros2_medkit_gateway/updates/update_backend.hpp
Outdated
Show resolved
Hide resolved
…lidation Replace string-based backend error matching with typed UpdateBackendError enum and UpdateBackendErrorInfo struct across UpdateBackend interface, UpdateManager, and all mock/test backends. Fix TOCTOU race in delete_update by creating Deleting sentinel when no PackageState exists. Move id validation and entity_id format check before backend call in register handler. Remove dead Deleting phase check in start_execute. Add stopped_ atomic flag to prevent new operations during shutdown. Add execute failure/exception tests with dedicated mock backends. Fix all polling loops to use deadline-based waits with explicit timeout assertions.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Pull Request
Summary
Add a plugin-based software updates subsystem implementing 8 SOVD-compliant REST endpoints for managing software update packages with async prepare/execute lifecycle.
UpdateBackendabstract interface loaded at runtime viadlopen/dlsymfrom.soshared librariesUpdateErrorwithUpdateErrorCodeenum replacing string-based errors, TOCTOU-safe deletion withDeletingsentinel phase, exception safety in async threads, thread-safety documentation@verifiestags before test definitions and generate clickable GitHub links with line numbersIssue
Type
Testing
colcon test --ctest-args -R test_update_manager- 17 tests covering CRUD, prepare/execute workflow, automated mode, status polling, concurrent operations, deadlock-free destruction, backend failure/exception handling, and error codescolcon test --packages-select ros2_medkit_integration_tests --ctest-args -R test_updates- 32 tests against running gateway with and without plugin backendChecklist