system: Work around RAUC not providing some properties

We encountered an issue where RAUC did not provide bundle.version and
installed.timestamp properties. It turns out that it was because of
missing /slot.raucs file.
However we expected that RAUC always provide all the required
properties and this issue then led to map::at throwing an exception.

This patch implements 'more defensive behaviour' when working with the
contents returned by RAUC by checking whether the properties are present
in the map.

Change-Id: Iefed40c6cef410103fe583bd4dbd08dc39f069da
diff --git a/src/system/Firmware.cpp b/src/system/Firmware.cpp
index 10d34a1..d1f8d29 100644
--- a/src/system/Firmware.cpp
+++ b/src/system/Firmware.cpp
@@ -133,12 +133,23 @@
     for (const auto& slotName : FIRMWARE_SLOTS) {
         if (auto it = slotStatus.find(slotName); it != slotStatus.end()) { // if there is an update for the slot "slotName"
             const auto& props = it->second;
-            auto xpathPrefix = CZECHLIGHT_SYSTEM_FIRMWARE_MODULE_PREFIX + "firmware-slot[name='" + std::get<std::string>(props.at("bootname")) + "']/";
+            std::string xpathPrefix;
 
-            m_slotStatusCache[xpathPrefix + "state"] = std::get<std::string>(props.at("state"));
-            m_slotStatusCache[xpathPrefix + "version"] = std::get<std::string>(props.at("bundle.version"));
-            m_slotStatusCache[xpathPrefix + "installed"] = std::get<std::string>(props.at("installed.timestamp"));
-            m_slotStatusCache[xpathPrefix + "boot-status"] = std::get<std::string>(props.at("boot-status"));
+            // Better be defensive about provided properties. If somebody removes /slot.raucs, RAUC doesn't provide all the data (at least bundle.version and installed.timestamp).
+            if (auto pit = props.find("bootname"); pit != props.end()) {
+                xpathPrefix = CZECHLIGHT_SYSTEM_FIRMWARE_MODULE_PREFIX + "firmware-slot[name='" + std::get<std::string>(pit->second) + "']/";
+            } else {
+                m_log->error("RAUC didn't provide 'bootname' property for slot '{}'. Skipping update for that slot.");
+                continue;
+            }
+
+            for (const auto& [yangKey, raucKey] : {std::pair{"state", "state"}, {"boot-status", "boot-status"}, {"version", "bundle.version"}, {"installed", "installed.timestamp"}}) {
+                if (auto pit = props.find(raucKey); pit != props.end()) {
+                    m_slotStatusCache[xpathPrefix + yangKey] = std::get<std::string>(pit->second);
+                } else {
+                    m_log->warn("RAUC didn't provide '{}' property for slot '{}'.", raucKey, slotName);
+                }
+            }
         }
     }