blob: 26caa9526d12ed3bc0478efad113426d6c03e5b7 [file] [log] [blame]
Tomáš Pecka98ad18d2020-11-13 15:39:55 +01001/*
Tomáš Pecka43ef7ba2023-04-13 15:56:48 +02002 * Copyright (C) 2020-2023 CESNET, https://photonics.cesnet.cz/
Tomáš Pecka98ad18d2020-11-13 15:39:55 +01003 *
4 * Written by Tomáš Pecka <tomas.pecka@fit.cvut.cz>
5 *
6 */
7
Tomáš Pecka43ef7ba2023-04-13 15:56:48 +02008#include <regex>
9#include <sysrepo-cpp/Connection.hpp>
Tomáš Pecka98ad18d2020-11-13 15:39:55 +010010#include "Sysrepo.h"
Tomáš Pecka2117ce52023-05-12 11:28:34 +020011#include "utils/alarms.h"
Tomáš Pecka98ad18d2020-11-13 15:39:55 +010012#include "utils/log.h"
Tomáš Peckaba2dc312021-01-23 22:29:11 +010013#include "utils/sysrepo.h"
Tomáš Pecka98ad18d2020-11-13 15:39:55 +010014
Tomáš Pecka98ad18d2020-11-13 15:39:55 +010015namespace {
16
Tomáš Pecka2117ce52023-05-12 11:28:34 +020017const auto ALARM_SENSOR_MISSING = "velia-alarms:sensor-missing-alarm";
18const auto ALARM_THRESHOLD_CROSSING_LOW = "velia-alarms:sensor-low-value-alarm";
19const auto ALARM_THRESHOLD_CROSSING_HIGH = "velia-alarms:sensor-high-value-alarm";
20
Tomáš Pecka43ef7ba2023-04-13 15:56:48 +020021/** @brief Extracts component path prefix from an XPath under /ietf-hardware/component node
22 *
23 * Example input: /ietf-hardware:hardware/component[name='ne:psu:child']/oper-state/disabled
24 * Example output: /ietf-hardware:hardware/component[name='ne:psu:child']
25 */
26std::string extractComponentPrefix(const std::string& componentXPath)
27{
28 static const std::regex regex(R"((/ietf-hardware:hardware/component\[name=('|").*?(\2)\]).*)");
29 std::smatch match;
Tomáš Pecka98ad18d2020-11-13 15:39:55 +010030
Tomáš Pecka43ef7ba2023-04-13 15:56:48 +020031 if (std::regex_match(componentXPath, match, regex)) {
32 return match.str(1);
33 }
34
35 throw std::logic_error("Invalid xPath provided ('" + componentXPath + "')");
36}
Tomáš Pecka98ad18d2020-11-13 15:39:55 +010037}
38
Tomáš Pecka43ef7ba2023-04-13 15:56:48 +020039namespace velia::ietf_hardware::sysrepo {
40
41/** @brief The constructor expects the HardwareState instance which will provide the actual hardware state data and the poll interval */
42Sysrepo::Sysrepo(::sysrepo::Session session, std::shared_ptr<IETFHardware> hwState, std::chrono::microseconds pollInterval)
43 : m_log(spdlog::get("hardware"))
44 , m_pollInterval(std::move(pollInterval))
45 , m_session(std::move(session))
46 , m_hwState(std::move(hwState))
47 , m_quit(false)
Tomáš Pecka2117ce52023-05-12 11:28:34 +020048{
49 for (const auto& sensorXPath : m_hwState->sensorsXPaths()) {
50 auto componentXPath = extractComponentPrefix(sensorXPath);
51 utils::addResourceToAlarmInventoryEntry(m_session, ALARM_THRESHOLD_CROSSING_LOW, std::nullopt, componentXPath);
52 utils::addResourceToAlarmInventoryEntry(m_session, ALARM_THRESHOLD_CROSSING_HIGH, std::nullopt, componentXPath);
53 utils::addResourceToAlarmInventoryEntry(m_session, ALARM_SENSOR_MISSING, std::nullopt, componentXPath);
54 }
55
56 m_pollThread = std::thread([&]() {
Tomáš Pecka43ef7ba2023-04-13 15:56:48 +020057 auto conn = m_session.getConnection();
58
59 DataTree prevValues;
60
61 while (!m_quit) {
62 m_log->trace("IetfHardware poll");
63
Tomáš Pecka0d8d8ee2023-05-10 12:22:58 +020064 auto [hwStateValues, thresholds] = m_hwState->process();
Tomáš Pecka43ef7ba2023-04-13 15:56:48 +020065 std::set<std::string> deletedComponents;
66
67 /* Some data readers can stop returning data in some cases (e.g. ejected PSU).
68 * Prune tree components that were removed before updating to avoid having not current data from previous invocations.
69 */
70 for (const auto& [k, v] : prevValues) {
71 if (!hwStateValues.contains(k)) {
72 deletedComponents.emplace(extractComponentPrefix(k));
73 }
74 }
75
Jan Kundrát498c3f82023-05-24 19:25:48 +020076 std::vector<std::string> discards;
77 discards.reserve(deletedComponents.size());
78 std::copy(deletedComponents.begin(), deletedComponents.end(), std::back_inserter(discards));
Tomáš Pecka43ef7ba2023-04-13 15:56:48 +020079
Jan Kundrát498c3f82023-05-24 19:25:48 +020080 utils::valuesPush(hwStateValues, {}, discards, m_session, ::sysrepo::Datastore::Operational);
Tomáš Pecka43ef7ba2023-04-13 15:56:48 +020081
82 prevValues = std::move(hwStateValues);
83 std::this_thread::sleep_for(m_pollInterval);
84 }
Tomáš Pecka2117ce52023-05-12 11:28:34 +020085 });
Tomáš Pecka43ef7ba2023-04-13 15:56:48 +020086}
Václav Kubernát7efd6d52021-11-09 01:31:11 +010087
Tomáš Pecka43ef7ba2023-04-13 15:56:48 +020088Sysrepo::~Sysrepo()
89{
90 m_log->trace("Requesting poll thread stop");
91 m_quit = true;
92 m_pollThread.join();
Tomáš Pecka98ad18d2020-11-13 15:39:55 +010093}
94}