/** * @RDE_HEADER@ * Handler for CheckmkHandlerScheduleCheck * $Id$ * $HeadURL$ * $Author$ * Created by Norbert Thoden, 2022-11-30 */ #include "checkmk_handler_schedule_check.h" #include #include #include namespace ComponentMonitor { CheckmkHandlerScheduleCheck::CheckmkHandlerScheduleCheck(const std::shared_ptr &ddsHandler) : QObject() , TriggerUpdateRequestHandler(ddsHandler->fts()) , m_socket(new QTcpSocket(this)) , m_ddsHandler(ddsHandler) , m_logger(getLogger("CheckmkHandlerScheduleCheck")) { TRACE_LOG(m_logger) << LOGFUNCTION << " START"; TRACE_LOG(m_logger) << LOGFUNCTION << " END"; } CheckmkHandlerScheduleCheck::~CheckmkHandlerScheduleCheck() { TRACE_LOG(m_logger) << LOGFUNCTION << " START"; if (m_timer) m_timer->stop(); delete m_socket; TRACE_LOG(m_logger) << LOGFUNCTION << " END"; } bool CheckmkHandlerScheduleCheck::initialize(const QString &checkMkServerHostname, int checkMkServerPort) { NOTICE_LOG(m_logger) << LOGFUNCTION << " START" << " , hostname=" << checkMkServerHostname << " , port=" << checkMkServerPort; DEBUG_LOG(m_logger) << LOGFUNCTION << " ddsHandler referenced"; m_checkMkHost = checkMkServerHostname; m_checkMkPort = checkMkServerPort; if (!m_timer) { m_timer = new QTimer(this); m_timer->setSingleShot(true); connect(m_timer, &QTimer::timeout, this, &CheckmkHandlerScheduleCheck::onTimeout); } connect(m_socket, &QTcpSocket::stateChanged, this, &CheckmkHandlerScheduleCheck::onStateChanged); connect(m_socket, QOverload::of(&QAbstractSocket::error), this, &CheckmkHandlerScheduleCheck::onSocketError); connect(m_socket, &QTcpSocket::connected, this, &CheckmkHandlerScheduleCheck::onConnected); INFO_LOG(m_logger) << LOGFUNCTION << " END"; return true; } void CheckmkHandlerScheduleCheck::run(int timoutMsec) { INFO_LOG(m_logger) << LOGFUNCTION << " START, timoutMsec=" << timoutMsec; m_timer->start(timoutMsec); INFO_LOG(m_logger) << LOGFUNCTION << " END"; } void CheckmkHandlerScheduleCheck::stop() { INFO_LOG(m_logger) << LOGFUNCTION << " START"; m_timer->stop(); INFO_LOG(m_logger) << LOGFUNCTION << " END"; } void CheckmkHandlerScheduleCheck::onTimeout() { if (m_socket->state() == QAbstractSocket::SocketState::ConnectedState) { writeScheduleUpdateRequest(); } else { doConnect(); } } bool CheckmkHandlerScheduleCheck::doConnect() { INFO_LOG(m_logger) << LOGFUNCTION << " START, (int)m_socket->state()=" << (int)m_socket->state(); // (for 'COMMAND [%1] SCHEDULE_FORCED_HOST_CHECK...' the socket connection should not be closed) // But maybe the CheckMk-Server ist restarted: m_socket->connectToHost(m_checkMkHost, m_checkMkPort); if (!m_socket->waitForConnected(5000)) { ERROR_LOG(m_logger) << LOGFUNCTION << " Could not (re)open tcp destination " << m_checkMkHost << ":" << m_checkMkPort << ", error: " << m_socket->errorString(); return false; } INFO_LOG(m_logger) << LOGFUNCTION << " (Re)openend tcp destination " << m_checkMkHost << ":" << m_checkMkPort; INFO_LOG(m_logger) << LOGFUNCTION << " END"; return true; } void CheckmkHandlerScheduleCheck::addScheduleCheckHostnames(const QStringList &hostnames) { INFO_LOG(m_logger) << LOGFUNCTION << " hostnames: " << hostnames.join(QStringLiteral(";")); m_scheduleCheckHostnames += hostnames; } bool CheckmkHandlerScheduleCheck::writeScheduleUpdateRequest() { DEBUG_LOG(m_logger) << LOGFUNCTION << " state " << (int)m_socket->state() << ", isOpen " << m_socket->isOpen(); if (!m_socket->isOpen() || (m_socket->state() != QAbstractSocket::SocketState::ConnectedState)) { ERROR_LOG(m_logger) << LOGFUNCTION << " socket not open or connected " << " host/port: " << m_checkMkHost << ":" << m_checkMkPort; return false; } if (m_scheduleCheckHostnames.isEmpty()) return false; // avoid duplicates: #if QT_VERSION < QT_VERSION_CHECK(5, 14, 0) const QSet hosts = QSet::fromList(m_scheduleCheckHostnames); #else const QSet hosts(m_scheduleCheckHostnames.begin(), m_scheduleCheckHostnames.end()); #endif // QT_VERSION int bWrittenAll = 0; for (const QString &hostname : qAsConst(hosts)) { qint64 now = QDateTime::currentSecsSinceEpoch(); // CheckMK is is configured with -> toUpper() const QString cmd = QString(QStringLiteral("COMMAND [%1] SCHEDULE_FORCED_HOST_CHECK;%2;%3")).arg(now).arg(hostname.toUpper()).arg(now); DEBUG_LOG(m_logger) << LOGFUNCTION << " cmd= '" << cmd << "'"; int bWritten = m_socket->write(cmd.toUtf8()) + m_socket->write("\n\n"); DEBUG_LOG(m_logger) << LOGFUNCTION << " bWritten= " << bWritten; bWrittenAll += bWritten; } // for INFO_LOG(m_logger) << LOGFUNCTION << " bWrittenAll= " << bWrittenAll; // avoid scheduling more than once -> clear m_scheduleCheckHostnames.clear(); // // avoid hanging application, since slot (CheckmkHandler::onImmediateGetStateRequested // most likely has to reconnect... QTimer::singleShot(100, this, [this](){ emit newCheckScheduled(); }); return true; } void CheckmkHandlerScheduleCheck::onConnected() { writeScheduleUpdateRequest(); } void CheckmkHandlerScheduleCheck::onStateChanged(const QAbstractSocket::SocketState &newState) { DEBUG_LOG(m_logger) << LOGFUNCTION << " SocketState changed to: " << newState; qInfo() << " CheckmkHandlerScheduleCheck: SocketState changed to: " << newState; } void CheckmkHandlerScheduleCheck::onSocketError(const QAbstractSocket::SocketError &socketError) { qCritical() << "CheckmkHandlerScheduleCheck: Error occured: " << socketError; } void CheckmkHandlerScheduleCheck::onTriggerUpdateRequest(const rti::core::SampleIdentity &cookie, const TriggerUpdate &request) { INFO_LOG(m_logger) << LOGFUNCTION << " request=" << request; DEBUG_LOG(m_logger) << LOGFUNCTION << " m_socket->state=" << (int)m_socket->state(); // if ((m_socket->state() != QAbstractSocket::SocketState::ConnectedState)) // { // ERROR_LOG(m_logger) << LOGFUNCTION << " not connected"; // Core::FunctionReplyObject ret(0); // no request.id() // ret.setId(-1); // ret.setStr(tr_lts("dds", "No Connection to CheckMK")); // if (m_ddsHandler && m_ddsHandler->fts()) // m_ddsHandler->fts()->triggerUpdateReply(cookie, ret); // return; // } const std::vector< std::string >& hostnames = request.hostnames(); QStringList sl; sl.reserve(hostnames.size()); QString temp; for (const std::string &str : qAsConst(hostnames)) { temp = QString::fromStdString(str); if (!sl.contains(temp)) sl.push_back(temp); } // for // add to list addScheduleCheckHostnames(sl); // updateLastCheckTimeDirect : // BEFORE writeScheduleUpdateRequest to avoid race condition! const qint64 now = QDateTime::currentSecsSinceEpoch(); emit updateLastCheckTimeDirect(sl, now); // : updateLastCheckTimeDirect Core::FunctionReplyObject ret(0); // no request.id() const bool connected = m_socket->state() == QAbstractSocket::SocketState::ConnectedState; if (connected) { bool writeOk = writeScheduleUpdateRequest(); if (!writeOk) { ret.setId(-1); ret.setStr(tr_lts("dds", "WriteError on CheckMk")); } } else { // GUEZE-1653 MsgBox 'cmd queued due to lost connection to CheckMk' vermeiden WARNING_LOG(m_logger) << LOGFUNCTION << " socket not connected" << ", (int)m_socket->state()=" << (int)m_socket->state() << ", destination " << m_checkMkHost << ":" << m_checkMkPort << ", -> queued cmd/request: " << request; // ret.setId(-1); // ret.setStr(tr_lts("dds", "cmd queued due to lost connection to CheckMk")); } INFO_LOG(m_logger) << LOGFUNCTION << " m_ddsHandler = " << m_ddsHandler; INFO_LOG(m_logger) << LOGFUNCTION << " m_ddsHandler->fts() = " << m_ddsHandler->fts(); if (m_ddsHandler && m_ddsHandler->fts()) m_ddsHandler->fts()->triggerUpdateReply(cookie, ret); else ERROR_LOG(m_logger) << LOGFUNCTION << " no m_ddsHandler or m_ddsHandler->fts()"; if (!connected) doConnect(); return; } } // namespace ComponentMonitor