source: nscp/modules/NSCAAgent/NSCAThread.cpp @ f3da50a

stable
Last change on this file since f3da50a was f3da50a, checked in by Michael Medin <michael@…>, 2 years ago
  • Fixed (finally!!) the NSCA issue with multiple commands and missing "data"
  • Property mode set to 100644
File size: 13.5 KB
Line 
1//////////////////////////////////////////////////////////////////////////
2// PDH Collector
3//
4// Functions from this file collects data from the PDH subsystem and stores
5// it for later use
6// *NOTICE* that this is done in a separate thread so threading issues has
7// to be handled. I handle threading issues in the CounterListener's get/
8// set accessors.
9//
10// Copyright (c) 2004 MySolutions NORDIC (http://www.medin.nu)
11//
12// Date: 2004-03-13
13// Author: Michael Medin - <michael@medin.name>
14//
15// This software is provided "AS IS", without a warranty of any kind.
16// You are free to use/modify this code but leave this header intact.
17//
18//////////////////////////////////////////////////////////////////////////
19
20#include "stdafx.h"
21#include "NSCAThread.h"
22#include <Settings.h>
23
24#define REPORT_ERROR    0x01
25#define REPORT_WARNING  0x02
26#define REPORT_UNKNOWN  0x04
27#define REPORT_OK               0x08
28
29unsigned int parse_report_string(std::wstring str) {
30        unsigned int report = 0;
31        strEx::splitList lst = strEx::splitEx(str, _T(","));
32        for (strEx::splitList::const_iterator key = lst.begin(); key != lst.end(); ++key) {
33                if (*key == _T("all")) {
34                        report = REPORT_ERROR|REPORT_OK|REPORT_UNKNOWN|REPORT_WARNING;
35                } else if (*key == _T("error") || *key == _T("err") || *key == _T("critical") || *key == _T("crit")) {
36                        report |= REPORT_ERROR;
37                } else if (*key == _T("warning") || *key == _T("warn")) {
38                        report |= REPORT_WARNING;
39                } else if (*key == _T("unknown")) {
40                        report |= REPORT_UNKNOWN;
41                } else if (*key == _T("ok")) {
42                        report |= REPORT_OK;
43                }
44        }
45        return report;
46}
47std::wstring generate_report_string(unsigned int report) {
48        std::wstring ret;
49        if ((report&REPORT_OK)!=0) {
50                if (!ret.empty())       ret += _T(",");
51                ret += _T("ok");
52        }
53        if ((report&REPORT_WARNING)!=0) {
54                if (!ret.empty())       ret += _T(",");
55                ret += _T("warning");
56        }
57        if ((report&REPORT_ERROR)!=0) {
58                if (!ret.empty())       ret += _T(",");
59                ret += _T("critical");
60        }
61        if ((report&REPORT_UNKNOWN)!=0) {
62                if (!ret.empty())       ret += _T(",");
63                ret += _T("unknown");
64        }
65        return ret;
66}
67
68NSCAThread::NSCAThread() : hStopEvent_(NULL) {
69        std::wstring tmpstr = NSCModuleHelper::getSettingsString(NSCA_AGENT_SECTION_TITLE, NSCA_TIME_DELTA, NSCA_TIME_DELTA_DEFAULT);
70        if (tmpstr[0] == '-' && tmpstr.size() > 2)
71                timeDelta_ = 0 - strEx::stoui_as_time(tmpstr.substr(1));
72        if (tmpstr[0] == '+' && tmpstr.size() > 2)
73                timeDelta_ = strEx::stoui_as_time(tmpstr.substr(1));
74        else
75                timeDelta_ = strEx::stoui_as_time(tmpstr);
76        timeDelta_ = timeDelta_ / 1000;
77        NSC_DEBUG_MSG_STD(_T("Time difference for NSCA server is: ") + strEx::itos(timeDelta_));
78        checkIntervall_ = NSCModuleHelper::getSettingsInt(NSCA_AGENT_SECTION_TITLE, NSCA_INTERVAL, NSCA_INTERVAL_DEFAULT);
79        hostname_ = NSCModuleHelper::getSettingsString(NSCA_AGENT_SECTION_TITLE, NSCA_HOSTNAME, NSCA_HOSTNAME_DEFAULT);
80        nscahost_ = NSCModuleHelper::getSettingsString(NSCA_AGENT_SECTION_TITLE, NSCA_SERVER, NSCA_SERVER_DEFAULT);
81        nscaport_ = NSCModuleHelper::getSettingsInt(NSCA_AGENT_SECTION_TITLE, NSCA_PORT, NSCA_PORT_DEFAULT);
82        payload_length_ = NSCModuleHelper::getSettingsInt(NSCA_AGENT_SECTION_TITLE, NSCA_STRLEN, NSCA_STRLEN_DEFAULT);
83        read_timeout_ = NSCModuleHelper::getSettingsInt(NSCA_AGENT_SECTION_TITLE, NSCA_READ_TIMEOUT, NSCA_READ_TIMEOUT_DEFAULT);
84        resultInterval = NSCModuleHelper::getSettingsInt(NSCA_AGENT_SECTION_TITLE, NSCA_CHUNK, NSCA_CHUNK_DEFAULT);
85        std::wstring report = NSCModuleHelper::getSettingsString(NSCA_AGENT_SECTION_TITLE, NSCA_REPORT, NSCA_REPORT_DEFAULT);
86        report_ = parse_report_string(report);
87        NSC_DEBUG_MSG_STD(_T("Only reporting: ") + generate_report_string(report_));
88       
89        encryption_method_ = NSCModuleHelper::getSettingsInt(NSCA_AGENT_SECTION_TITLE, NSCA_ENCRYPTION, NSCA_ENCRYPTION_DEFAULT);
90        std::wstring password = NSCModuleHelper::getSettingsString(NSCA_AGENT_SECTION_TITLE, MAIN_OBFUSCATED_PASWD, MAIN_OBFUSCATED_PASWD_DEFAULT);
91        if (!password.empty())
92                password = NSCModuleHelper::Decrypt(password);
93        if (password.empty())
94                password = NSCModuleHelper::getSettingsString(NSCA_AGENT_SECTION_TITLE, NSCA_PASSWORD, NSCA_PASSWORD_DEFAULT);
95        if (password.empty()) {
96                // read main password if no NSCA one is found
97                password = NSCModuleHelper::getSettingsString(MAIN_SECTION_TITLE, MAIN_OBFUSCATED_PASWD, MAIN_OBFUSCATED_PASWD_DEFAULT);
98                if (!password.empty())
99                        password = NSCModuleHelper::Decrypt(password);
100                if (password.empty())
101                        password = NSCModuleHelper::getSettingsString(MAIN_SECTION_TITLE, MAIN_SETTINGS_PWD, MAIN_SETTINGS_PWD_DEFAULT);
102        }
103        password_ = strEx::wstring_to_string(password);
104
105        cacheNscaHost_ = NSCModuleHelper::getSettingsInt(NSCA_AGENT_SECTION_TITLE, NSCA_CACHE_HOST, NSCA_CACHE_HOST_DEFAULT) == 1;
106        std::list<std::wstring> items = NSCModuleHelper::getSettingsSection(NSCA_CMD_SECTION_TITLE);
107        for (std::list<std::wstring>::const_iterator cit = items.begin(); cit != items.end(); ++cit) {
108                addCommand(*cit);
109        }
110        if (hostname_.empty()) {
111                TCHAR *buf = new TCHAR[MAX_COMPUTERNAME_LENGTH + 2];
112                DWORD size = MAX_COMPUTERNAME_LENGTH+1;
113                if (!GetComputerName(buf, &size)) {
114                        NSC_LOG_ERROR(_T("Failed to get computer name: setting it to <unknown>"));
115                        hostname_ = _T("<unknown>");
116                } else {
117                        buf[size] = 0;
118                        hostname_ = buf;
119                        NSC_DEBUG_MSG_STD(_T("Autodetected hostname: ") + hostname_);
120                }
121                delete[] buf;
122        }
123}
124
125NSCAThread::~NSCAThread()
126{
127        if (hStopEvent_)
128                CloseHandle(hStopEvent_);
129}
130Command::Result Command::execute(std::wstring host) const {
131        Result result(host);
132        std::wstring msg;
133        std::wstring perf;
134        NSCAPI::nagiosReturn ret = NSCModuleHelper::InjectCommand(cmd_.c_str(), args_.getLen(), args_.get(), msg, perf);
135        result.service = alias_;
136        if (ret == NSCAPI::returnIgnored) {
137                result.result = _T("Command was not found: ") + cmd_;
138                result.code = NSCAPI::returnUNKNOWN;
139        } else if (ret == NSCAPI::returnInvalidBufferLen) {
140                result.result = _T("Result was to long: ") + cmd_;
141                result.code = NSCAPI::returnUNKNOWN;
142        } else {
143                result.result = msg + _T("|") + perf;
144                result.code = conv_code(ret);
145                if (result.result.length() >= NSCA_MAX_PLUGINOUTPUT_LENGTH) {
146                        NSC_LOG_ERROR(_T("NSCA return data truncated"));
147                        result.result = result.result.substr(0, NSCA_MAX_PLUGINOUTPUT_LENGTH-1);
148                }
149        }
150        return result;
151}
152
153
154void NSCAThread::addCommand(std::wstring key) {
155        std::wstring value = NSCModuleHelper::getSettingsString(NSCA_CMD_SECTION_TITLE, key, _T(""));
156        if ((key.length() > 4) && (key.substr(0,4) == _T("host")))
157                commands_.push_back(Command(_T(""), value));
158        else
159                commands_.push_back(Command(key, value));
160}
161
162
163/**
164* Thread that collects the data every "CHECK_INTERVAL" seconds.
165*
166* @param lpParameter Not used
167* @return thread exit status
168*
169* @author mickem
170*
171* @date 03-13-2004               
172*
173* @bug If we have "custom named" counters ?
174* @bug This whole concept needs work I think.
175*
176*/
177DWORD NSCAThread::threadProc(LPVOID lpParameter) {
178        hStopEvent_ = CreateEvent(NULL, TRUE, FALSE, NULL);
179        if (!hStopEvent_) {
180                NSC_LOG_ERROR_STD(_T("Create StopEvent failed: ") + error::lookup::last_error());
181                return 0;
182        }
183
184        srand( reinterpret_cast<int>(lpParameter) );
185
186        DWORD waitStatus = 0;
187        int drift = (checkIntervall_*rand())/RAND_MAX ;
188        NSC_DEBUG_MSG_STD(_T("Drifting: ") + strEx::itos(drift));
189        waitStatus = WaitForSingleObject(hStopEvent_, drift*1000);
190        if (waitStatus != WAIT_TIMEOUT)  {
191                NSC_LOG_ERROR_STD(_T("Drift failed... strange..."));
192        }
193        int remain = checkIntervall_;
194        try {
195                while (((waitStatus = WaitForSingleObject(hStopEvent_, remain*1000)) == WAIT_TIMEOUT)) {
196                        MutexLock mutex(mutexHandler);
197                        if (!mutex.hasMutex())
198                                NSC_LOG_ERROR(_T("Failed to get Mutex!"));
199                        else {
200                                __int64 start, stop;
201                                _time64( &start );
202
203                                std::list<Command::Result> results;
204                                for (std::list<Command>::const_iterator cit = commands_.begin(); cit != commands_.end(); ++cit) {
205                                        try {
206                                                NSC_DEBUG_MSG_STD(_T("Executing (from NSCA): ") + (*cit).alias());
207                                                Command::Result result = (*cit).execute(hostname_);
208                                                if (
209                                                        (result.code == NSCAPI::returnOK && ((report_&REPORT_OK)==REPORT_OK) ) ||
210                                                        (result.code == NSCAPI::returnCRIT && ((report_&REPORT_ERROR)==REPORT_ERROR) ) ||
211                                                        (result.code == NSCAPI::returnWARN && ((report_&REPORT_WARNING)==REPORT_WARNING) ) ||
212                                                        (result.code == NSCAPI::returnUNKNOWN && ((report_&REPORT_UNKNOWN)==REPORT_UNKNOWN) )
213                                                        )
214                                                {
215                                                        results.push_back(result);
216                                                } else {
217                                                        NSC_DEBUG_MSG_STD(_T("Ignoring result (it does not match our reporting prefix: ") + (*cit).alias());
218                                                }
219                                        } catch (...) {
220                                                NSC_LOG_ERROR_STD(_T("Unknown exception when executing: ") + (*cit).alias());
221                                        }
222                                }
223                                if (!results.empty()) {
224                                        try {
225                                                if (resultInterval != 0) {
226                                                        while (!results.empty()) {
227                                                                std::list<Command::Result> chunk;
228                                                                for (int i=0;i<resultInterval&&!results.empty();++i) {
229                                                                        chunk.push_back(results.front());
230                                                                        results.pop_front();
231                                                                }
232                                                                send(chunk);
233                                                        }
234                                                } else
235                                                        send(results);
236                                        } catch (...) {
237                                                NSC_LOG_ERROR_STD(_T("Unknown exception when sending commands to server..."));
238                                        }
239                                } else {
240                                        NSC_DEBUG_MSG_STD(_T("Nothing to report, thus not reporting anything..."));
241                                }
242                                _time64( &stop );
243                                __int64 elapsed = stop-start;
244                                remain = checkIntervall_-static_cast<int>(elapsed);
245                                if (remain < 1)
246                                        remain = 1;
247                        }
248                }
249        } catch (...) {
250                NSC_LOG_ERROR_STD(_T("Unknown exception in NSCA Thread terminating..."));
251        }
252
253
254        if (waitStatus != WAIT_OBJECT_0) {
255                NSC_LOG_ERROR(_T("Something odd happened, terminating NSCA submission thread!"));
256        }
257
258        {
259                MutexLock mutex(mutexHandler);
260                if (!mutex.hasMutex()) {
261                        NSC_LOG_ERROR(_T("Failed to get Mute when closing thread!"));
262                }
263
264                if (!CloseHandle(hStopEvent_)) {
265                        NSC_LOG_ERROR_STD(_T("Failed to close stopEvent handle: ") + error::lookup::last_error());
266                } else
267                        hStopEvent_ = NULL;
268        }
269        return 0;
270}
271void NSCAThread::send(const std::list<Command::Result> &results) {
272        NSC_DEBUG_MSG_STD(_T("Sending to server..."));
273        try {
274                nsca_encrypt crypt_inst;
275                simpleSocket::Socket socket(true);
276                simpleSocket::DataBuffer inc;
277                if (!cacheNscaHost_ || nscaaddr_.empty()) {
278                        nscaaddr_ = socket.getHostByName(nscahost_);
279                        NSC_DEBUG_MSG_STD(_T("Looked up ") + nscahost_ + _T(" to ") + nscaaddr_);
280                }
281                if (nscaaddr_.empty()) {
282                        NSC_LOG_ERROR_STD(_T("Failed to lookup host: ") + nscahost_);
283                        return;
284                }
285                if (socket.connect(nscaaddr_, nscaport_) == SOCKET_ERROR) {
286                        NSC_LOG_ERROR_STD(_T("<<< Could not connect to: ") + nscaaddr_ + _T(":") + strEx::itos(nscaport_) + _T(" ") + socket.getLastError());
287                        return;
288                }
289                socket.setNonBlock();
290
291                time_t start = time(NULL);
292                unsigned int sz_packet = sizeof(NSCAPacket::init_packet_struct);
293                do {
294                        bool lastReadHasMore = false;
295                        try {
296                                lastReadHasMore = socket.readAll(inc, sz_packet);
297                        } catch (simpleSocket::SocketException e) {
298                                NSC_LOG_ERROR_STD(_T("Could not read NSCA hdr packet from socket :") + e.getMessage());
299                                socket.close();
300                                return;
301                        }
302                        if (inc.getLength() >= sz_packet)
303                                break;
304                        if (!lastReadHasMore) {
305                                NSC_LOG_MESSAGE(_T("Could not read a full NSCA hdr packet from socket, only got: ") + strEx::itos(inc.getLength()));
306                                socket.close();
307                                return;
308                        }
309                        Sleep(100);
310                } while ((time(NULL) - start) < read_timeout_);
311                if (inc.getLength() != sz_packet) {
312                        NSC_LOG_ERROR_STD(_T("Timeout reading NSCA hdr packet (increase socket_timeout), we only got: ") + strEx::itos(inc.getLength()));
313                        socket.close();
314                        return;
315                }
316
317                NSCAPacket::init_packet_struct *packet_in = (NSCAPacket::init_packet_struct*) inc.getBuffer();
318                try {
319                        crypt_inst.encrypt_init(password_.c_str(),encryption_method_,reinterpret_cast<unsigned char*>(packet_in->iv));
320                } catch (nsca_encrypt::encryption_exception &e) {
321                        NSC_LOG_ERROR_STD(_T("<<< NSCA Encryption header missmatch (hint: if you dont use NSCA dot use the NSCA module): ") + e.getMessage());
322                        return;
323                } catch (...) {
324                        NSC_LOG_ERROR_STD(_T("<<< NSCA Encryption header missmatch (hint: if you dont use NSCA dot use the NSCA module)!"));
325                        return;
326                }
327                socket.setBlock();
328
329                try {
330                        for (std::list<Command::Result>::const_iterator cit = results.begin(); cit != results.end(); ++cit) {
331                                try {
332                                        socket.sendAll((*cit).getBuffer(crypt_inst, timeDelta_, payload_length_));
333                                } catch (NSCAPacket::NSCAException &e) {
334                                        NSC_LOG_ERROR_STD(_T("Failed to build command: ") + e.getMessage() );
335                                } catch (simpleSocket::SocketException &e) {
336                                        NSC_LOG_ERROR_STD(_T("Failed to send command: ") + e.getMessage() );
337                                }
338                        }
339                } catch (nsca_encrypt::encryption_exception &e) {
340                        NSC_LOG_ERROR_STD(_T("<<< Failed to encrypt packet: ") + e.getMessage());
341                        return;
342                } catch (...) {
343                        NSC_LOG_ERROR_STD(_T("<<< Failed to encrypt packet!"));
344                        return;
345                }
346                socket.shutdown();
347                socket.setLinger(30);
348                socket.close();
349        } catch (simpleSocket::SocketException &e) {
350                NSC_LOG_ERROR_STD(_T("NSCA Socket exception: ") + e.getMessage());
351                return;
352        } catch (...) {
353                NSC_LOG_ERROR_STD(_T("<<< NSCA Configuration missmatch (hint: if you dont use NSCA dot use the NSCA module)!"));
354                return;
355        }
356        NSC_DEBUG_MSG_STD(_T("Finnished sending to server..."));
357}
358
359
360
361/**
362* Request termination of the thread (waiting for thread termination is not handled)
363*/
364void NSCAThread::exitThread(void) {
365        if (hStopEvent_ == NULL) {
366                NSC_LOG_ERROR(_T("Stop event is not created!"));
367        } else {
368                if (!SetEvent(hStopEvent_)) {
369                        NSC_LOG_ERROR_STD(_T("SetStopEvent failed"));
370                }
371        }
372}
Note: See TracBrowser for help on using the repository browser.