system: Installation progress notifications
Implement installation progress notifications as defined in
czechlight-system model
(/czechlight-system:firmware/installation/update).
The RAUC D-Bus API invokes PropertyChanged signal on its Progress [1]
property whenever the installation progresses. We capture those signals
and use them to generate Sysrepo notifications to clients.
The update contains current progress (in percents) and a message
containing current installation stage.
[1] https://rauc.readthedocs.io/en/v1.4/reference.html#gdbus-property-de-pengutronix-rauc-installer-progress
Change-Id: I310752919dde523a93943a2a1d7af79f073aedfe
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 2b7db0d..a862dc3 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -305,6 +305,7 @@
sysrepo_fixture_env(sysrepo-czechlight-system YANG ${CMAKE_CURRENT_SOURCE_DIR}/yang/czechlight-system@2021-01-13.yang)
velia_test(sysrepo_system-czechlightsystem velia-system DbusTesting)
+ target_link_libraries(test-sysrepo_system-czechlightsystem SysrepoTesting)
set_tests_properties(
test-sysrepo_system-czechlightsystem
PROPERTIES FIXTURES_REQUIRED sysrepo:env:sysrepo-czechlight-system
diff --git a/src/system/CzechlightSystem.cpp b/src/system/CzechlightSystem.cpp
index 49479f2..4256015 100644
--- a/src/system/CzechlightSystem.cpp
+++ b/src/system/CzechlightSystem.cpp
@@ -35,7 +35,18 @@
utils::valuesPush(data, std::make_shared<::sysrepo::Session>(m_srConn, SR_DS_OPERATIONAL));
}
},
- []([[maybe_unused]] int32_t perc, [[maybe_unused]] const std::string& msg) { /* TODO notifications */ },
+ [this](int32_t perc, const std::string& msg) {
+ std::map<std::string, std::string> data = {
+ {CZECHLIGHT_SYSTEM_FIRMWARE_MODULE_PREFIX + "installation/update/message", msg},
+ {CZECHLIGHT_SYSTEM_FIRMWARE_MODULE_PREFIX + "installation/update/progress", std::to_string(perc)},
+ };
+
+ libyang::S_Data_Node dataNode;
+ auto session = std::make_shared<::sysrepo::Session>(m_srConn);
+
+ utils::valuesToYang(data, session, dataNode);
+ session->event_notif_send(dataNode);
+ },
[this](int32_t retVal, const std::string& lastError) {
std::map<std::string, std::string> data {
{CZECHLIGHT_SYSTEM_FIRMWARE_MODULE_PREFIX + "installation/message", lastError},
diff --git a/tests/sysrepo_system-czechlightsystem.cpp b/tests/sysrepo_system-czechlightsystem.cpp
index 07dc575..fe0f2a2 100644
--- a/tests/sysrepo_system-czechlightsystem.cpp
+++ b/tests/sysrepo_system-czechlightsystem.cpp
@@ -5,6 +5,7 @@
#include "test_log_setup.h"
#include "test_sysrepo_helpers.h"
#include "tests/configure.cmake.h"
+#include "tests/mock/sysrepo/events.h"
using namespace std::literals;
@@ -109,6 +110,12 @@
{"/installation/message", ""},
{"/installation/status", "in-progress"},
};
+ size_t expectedNotificationsCount;
+ std::string expectedLastNotificationMsg;
+
+ // subscribe to notifications
+ EventWatcher events;
+ subscription->event_notif_subscribe("czechlight-system", events, "/czechlight-system:firmware/installation/update");
SECTION("Successfull install")
{
@@ -118,6 +125,8 @@
{"/installation/message", ""},
{"/installation/status", "succeeded"},
};
+ expectedNotificationsCount = 22;
+ expectedLastNotificationMsg = "Installing done.";
}
SECTION("Unsuccessfull install")
@@ -128,6 +137,8 @@
{"/installation/message", "Failed to download bundle https://10.88.3.11:8000/update.raucb: Transfer failed: error:1408F10B:SSL routines:ssl3_get_record:wrong version number"},
{"/installation/status", "failed"},
};
+ expectedNotificationsCount = 6;
+ expectedLastNotificationMsg = "Installing failed.";
}
raucServer.installBundleBehaviour(installType);
@@ -139,6 +150,20 @@
std::this_thread::sleep_for(2s); // lets wait a while, so the installation can finish
REQUIRE(dataFromSysrepo(client, "/czechlight-system:firmware", SR_DS_OPERATIONAL) == expectedFinished);
+
+ // check updates notification count and that at least some of them are reasonable
+ REQUIRE(events.count() == expectedNotificationsCount);
+ REQUIRE(events.peek(0).data["/czechlight-system:firmware/installation/update/message"] == "Installing");
+ REQUIRE(events.peek(0).data["/czechlight-system:firmware/installation/update/progress"] == "0");
+ REQUIRE(events.peek(events.count() - 1).data["/czechlight-system:firmware/installation/update/message"] == expectedLastNotificationMsg);
+ REQUIRE(events.peek(events.count() - 1).data["/czechlight-system:firmware/installation/update/progress"] == "100");
+
+ // check updates notification progress is an increasing sequence
+ for (size_t i = 1; i < events.count(); i++) {
+ auto prevProgress = std::stoi(events.peek(i - 1).data["/czechlight-system:firmware/installation/update/progress"]);
+ auto currProgress = std::stoi(events.peek(i).data["/czechlight-system:firmware/installation/update/progress"]);
+ REQUIRE(prevProgress <= currProgress);
+ }
}
SECTION("Invoke another installation before the first finishes")
diff --git a/tests/test_sysrepo_helpers.h b/tests/test_sysrepo_helpers.h
index bf8bf5f..54d2d71 100644
--- a/tests/test_sysrepo_helpers.h
+++ b/tests/test_sysrepo_helpers.h
@@ -44,6 +44,7 @@
auto srSess = std::make_shared<sysrepo::Session>(srConn); \
auto srSubs = std::make_shared<sysrepo::Subscribe>(srSess);
-#define TEST_SYSREPO_INIT_CLIENT \
- auto clientConn = std::make_shared<sysrepo::Connection>(); \
- auto client = std::make_shared<sysrepo::Session>(clientConn);
+#define TEST_SYSREPO_INIT_CLIENT \
+ auto clientConn = std::make_shared<sysrepo::Connection>(); \
+ auto client = std::make_shared<sysrepo::Session>(clientConn); \
+ auto subscription = std::make_shared<sysrepo::Subscribe>(client);