Merge branch 'fixes' into main/rendor-staging
[ryzomcore.git] / nel / src / net / admin.cpp
blob4389e0f3487e9d364dfb8244ac385aca654e5c7c
1 // NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
2 // Copyright (C) 2010 Winch Gate Property Limited
3 //
4 // This program is free software: you can redistribute it and/or modify
5 // it under the terms of the GNU Affero General Public License as
6 // published by the Free Software Foundation, either version 3 of the
7 // License, or (at your option) any later version.
8 //
9 // This program is distributed in the hope that it will be useful,
10 // but WITHOUT ANY WARRANTY; without even the implied warranty of
11 // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 // GNU Affero General Public License for more details.
14 // You should have received a copy of the GNU Affero General Public License
15 // along with this program. If not, see <http://www.gnu.org/licenses/>.
19 // Includes
22 #include "stdnet.h"
24 #include "nel/net/service.h"
25 #include "nel/net/admin.h"
26 #include "nel/net/varpath.h"
30 // Namspaces
33 using namespace std;
34 using namespace NLMISC;
35 using namespace NLNET;
38 namespace NLNET {
42 // Structures
45 struct CRequest
47 CRequest (uint32 id, TServiceId sid) : Id(id), NbWaiting(0), NbReceived(0), SId(sid)
49 nldebug ("ADMIN: ++ NbWaiting %d NbReceived %d", NbWaiting, NbReceived);
50 Time = CTime::getSecondsSince1970 ();
53 uint32 Id;
54 uint NbWaiting;
55 uint32 NbReceived;
56 TServiceId SId;
57 uint32 Time; // when the request was ask
59 TAdminViewResult Answers;
64 // Variables
67 TRemoteClientCallback RemoteClientCallback = 0;
69 vector<CAlarm> Alarms;
71 vector<CGraphUpdate> GraphUpdates;
73 // check alarms every 5 seconds
74 const uint32 AlarmCheckDelay = 5;
76 vector<CRequest> Requests;
78 uint32 RequestTimeout = 4; // in second
82 // Callbacks
85 static void cbInfo (CMessage &msgin, const std::string &/* serviceName */, TServiceId /* sid */)
87 nlinfo ("ADMIN: Updating admin information");
89 vector<string> alarms;
90 msgin.serialCont (alarms);
91 vector<string> graphupdate;
92 msgin.serialCont (graphupdate);
94 setInformation (alarms, graphupdate);
97 static void cbServGetView (CMessage &msgin, const std::string &/* serviceName */, TServiceId sid)
99 uint32 rid;
100 string rawvarpath;
102 msgin.serial (rid);
103 msgin.serial (rawvarpath);
105 Requests.push_back (CRequest(rid, sid));
107 TAdminViewResult answer;
108 // just send the view in async mode, don't retrieve the answer
109 serviceGetView (rid, rawvarpath, answer, true);
110 nlassert (answer.empty());
113 static void cbExecCommand (CMessage &msgin, const std::string &/* serviceName */, TServiceId sid)
115 // create a displayer to gather the output of the command
116 class CStringDisplayer: public IDisplayer
118 public:
119 void serial(NLMISC::IStream &stream)
121 stream.serial(_Data);
124 protected:
125 virtual void doDisplay( const CLog::TDisplayInfo& /* args */, const char *message)
127 _Data += message;
130 std::string _Data;
132 CStringDisplayer stringDisplayer;
133 IService::getInstance()->CommandLog.addDisplayer(&stringDisplayer);
135 // retreive the command from the input message and execute it
136 string command;
137 msgin.serial (command);
138 nlinfo ("ADMIN: Executing command from network : '%s'", command.c_str());
139 ICommand::execute (command, IService::getInstance()->CommandLog);
141 // unhook our displayer as it's work is now done
142 IService::getInstance()->CommandLog.removeDisplayer(&stringDisplayer);
144 // send a reply message to the originating service
145 CMessage msgout("EXEC_COMMAND_RESULT");
146 stringDisplayer.serial(msgout);
147 CUnifiedNetwork::getInstance()->send(sid, msgout);
151 // AES wants to know if i'm not dead, I have to answer faster as possible or i'll be killed
152 static void cbAdminPing (CMessage &/* msgin */, const std::string &/* serviceName */, TServiceId sid)
154 // Send back a pong to say to the AES that I'm alive
155 CMessage msgout("ADMIN_PONG");
156 CUnifiedNetwork::getInstance()->send(sid, msgout);
159 static void cbStopService (CMessage &/* msgin */, const std::string &serviceName, TServiceId sid)
161 nlinfo ("ADMIN: Receive a stop from service %s-%hu, need to quit", serviceName.c_str(), sid.get());
162 IService::getInstance()->exit (0xFFFF);
166 void cbAESConnection (const string &/* serviceName */, TServiceId /* sid */, void * /* arg */)
168 // established a connection to the AES, identify myself
171 // Sends the identification message with the name of the service and all commands available on this service
174 nlinfo("cbAESConnection: Identifying self as: AliasName='%s' LongName='%s' PId=%u",
175 IService::getInstance()->_AliasName.c_str(),
176 IService::getInstance()->_LongName.c_str(),
177 getpid ());
178 CMessage msgout ("SID");
179 uint32 pid = getpid ();
180 msgout.serial (IService::getInstance()->_AliasName, IService::getInstance()->_LongName, pid);
181 ICommand::serialCommands (msgout);
182 CUnifiedNetwork::getInstance()->send("AES", msgout);
184 if (IService::getInstance()->_Initialized)
186 CMessage msgout2 ("SR");
187 CUnifiedNetwork::getInstance()->send("AES", msgout2);
192 static void cbAESDisconnection (const std::string &serviceName, TServiceId sid, void * /* arg */)
194 nlinfo("Lost connection to the %s-%hu", serviceName.c_str(), sid.get());
198 static TUnifiedCallbackItem CallbackArray[] =
200 { "INFO", cbInfo },
201 { "GET_VIEW", cbServGetView },
202 { "STOPS", cbStopService },
203 { "EXEC_COMMAND", cbExecCommand },
204 { "ADMIN_PING", cbAdminPing },
209 // Functions
212 void setRemoteClientCallback (TRemoteClientCallback cb)
214 RemoteClientCallback = cb;
219 // Request functions
222 static void addRequestWaitingNb (uint32 rid)
224 for (uint i = 0 ; i < Requests.size (); i++)
226 if (Requests[i].Id == rid)
228 Requests[i].NbWaiting++;
229 nldebug ("ADMIN: ++ i %d rid %d NbWaiting+ %d NbReceived %d", i, Requests[i].Id, Requests[i].NbWaiting, Requests[i].NbReceived);
230 // if we add a waiting, reset the timer
231 Requests[i].Time = CTime::getSecondsSince1970 ();
232 return;
235 nlwarning ("ADMIN: addRequestWaitingNb: can't find the rid %d", rid);
239 static void subRequestWaitingNb (uint32 rid)
241 for (uint i = 0 ; i < Requests.size (); i++)
243 if (Requests[i].Id == rid)
245 Requests[i].NbWaiting--;
246 nldebug ("ADMIN: ++ i %d rid %d NbWaiting- %d NbReceived %d", i, Requests[i].Id, Requests[i].NbWaiting, Requests[i].NbReceived);
247 return;
250 nlwarning ("ADMIN: subRequestWaitingNb: can't find the rid %d", rid);
254 void addRequestAnswer (uint32 rid, const TAdminViewVarNames& varNames, const TAdminViewValues& values)
256 if (!varNames.empty() && varNames[0] == "__log")
257 { nlassert (varNames.size() == 1); }
258 else
259 { nlassert (varNames.size() == values.size()); }
261 for (uint i = 0 ; i < Requests.size (); i++)
263 if (Requests[i].Id == rid)
265 Requests[i].Answers.push_back (SAdminViewRow(varNames, values));
267 Requests[i].NbReceived++;
268 nldebug ("ADMIN: ++ i %d rid %d NbWaiting %d NbReceived+ %d", i, Requests[i].Id, Requests[i].NbWaiting, Requests[i].NbReceived);
270 return;
273 // we received an unknown request, forget it
274 nlwarning ("ADMIN: Receive an answer for unknown request %d", rid);
278 static bool emptyRequest (uint32 rid)
280 for (uint i = 0 ; i < Requests.size (); i++)
282 if (Requests[i].Id == rid && Requests[i].NbWaiting != 0)
284 return false;
287 return true;
291 static void cleanRequest ()
293 uint32 currentTime = CTime::getSecondsSince1970 ();
295 for (uint i = 0 ; i < Requests.size ();)
297 // timeout
298 if (currentTime >= Requests[i].Time+RequestTimeout)
300 nlwarning ("ADMIN: **** i %d rid %d -> Requests[i].NbWaiting (%d) != Requests[i].NbReceived (%d)", i, Requests[i].Id, Requests[i].NbWaiting, Requests[i].NbReceived);
301 Requests[i].NbWaiting = Requests[i].NbReceived;
304 if (Requests[i].NbWaiting <= Requests[i].NbReceived)
306 // the request is over, send to the php
308 CMessage msgout("VIEW");
309 msgout.serial (Requests[i].Id);
311 for (uint j = 0; j < Requests[i].Answers.size (); j++)
313 msgout.serialCont (Requests[i].Answers[j].VarNames);
314 msgout.serialCont (Requests[i].Answers[j].Values);
317 if (Requests[i].SId.get() == 0)
319 nlinfo ("ADMIN: Receive an answer for the fake request %d with %d answers", Requests[i].Id, Requests[i].Answers.size ());
320 for (uint j = 0; j < Requests[i].Answers.size (); j++)
322 uint k;
323 for (k = 0; k < Requests[i].Answers[j].VarNames.size(); k++)
325 InfoLog->displayRaw ("%-10s", Requests[i].Answers[j].VarNames[k].c_str());
327 InfoLog->displayRawNL("");
328 for (k = 0; k < Requests[i].Answers[j].Values.size(); k++)
330 InfoLog->displayRaw ("%-10s", Requests[i].Answers[j].Values[k].c_str());
332 InfoLog->displayRawNL("");
333 InfoLog->displayRawNL("-------------------------");
336 else
338 nlinfo ("ADMIN: The request is over, send the result to AES");
339 CUnifiedNetwork::getInstance ()->send (Requests[i].SId, msgout);
342 // set to 0 to erase it
343 Requests[i].NbWaiting = 0;
344 nldebug ("ADMIN: ++ i %d rid %d NbWaiting0 %d NbReceived %d", i, Requests[i].Id, Requests[i].NbWaiting, Requests[i].NbReceived);
347 if (Requests[i].NbWaiting == 0)
349 Requests.erase (Requests.begin ()+i);
351 else
353 i++;
358 // all remote command start with rc or RC
359 bool isRemoteCommand(string &str)
361 if (str.size()<2) return false;
362 return tolower(str[0]) == 'r' && tolower(str[1]) == 'c';
366 // this callback is used to create a view for the admin system
367 void serviceGetView (uint32 rid, const string &rawvarpath, TAdminViewResult &answer, bool async)
369 string str;
370 CLog logDisplayVars;
371 CLightMemDisplayer mdDisplayVars;
372 logDisplayVars.addDisplayer (&mdDisplayVars);
373 mdDisplayVars.setParam (4096);
375 CVarPath varpath(rawvarpath);
377 if (varpath.empty())
378 return;
380 // special case for named command handler
381 if (CCommandRegistry::getInstance().isNamedCommandHandler(varpath.Destination[0].first))
383 varpath.Destination[0].first += "."+varpath.Destination[0].second;
384 varpath.Destination[0].second.clear();
387 if (varpath.isFinal())
389 TAdminViewVarNames varNames;
390 TAdminViewValues values;
392 // add default row
393 varNames.push_back ("service");
394 values.push_back (IService::getInstance ()->getServiceUnifiedName());
396 for (uint j = 0; j < varpath.Destination.size (); j++)
398 string cmd = varpath.Destination[j].first;
400 // replace = with space to execute the command
401 string::size_type eqpos = cmd.find("=");
402 if (eqpos != string::npos)
404 cmd[eqpos] = ' ';
405 varNames.push_back(cmd.substr(0, eqpos));
407 else
408 varNames.push_back(cmd);
410 mdDisplayVars.clear ();
411 ICommand::execute(cmd, logDisplayVars, !ICommand::isCommand(cmd));
412 const std::deque<std::string> &strs = mdDisplayVars.lockStrings();
414 if (ICommand::isCommand(cmd))
416 // we want the log of the command
417 if (j == 0)
419 varNames.clear ();
420 varNames.push_back ("__log");
421 values.clear ();
424 values.push_back ("----- Result from "+IService::getInstance()->getServiceUnifiedName()+" of command '"+cmd+"'\n");
425 for (uint k = 0; k < strs.size(); k++)
427 values.push_back (strs[k]);
430 else
433 if (!strs.empty())
435 str = strs[0].substr(0,strs[0].size()-1);
436 // replace all spaces into udnerscore because space is a reserved char
437 for (uint i = 0; i < str.size(); i++) if (str[i] == ' ') str[i] = '_';
439 else
441 str = "???";
443 values.push_back (str);
444 nlinfo ("ADMIN: Add to result view '%s' = '%s'", varpath.Destination[j].first.c_str(), str.c_str());
446 mdDisplayVars.unlockStrings();
449 if (!async)
450 answer.push_back (SAdminViewRow(varNames, values));
451 else
453 addRequestWaitingNb (rid);
454 addRequestAnswer (rid, varNames, values);
457 else
459 // there s an entity in the varpath, manage this case
461 TAdminViewVarNames *varNames=0;
462 TAdminViewValues *values=0;
464 // varpath.Destination contains the entity number
465 // subvarpath.Destination contains the command name
467 for (uint i = 0; i < varpath.Destination.size (); i++)
469 CVarPath subvarpath(varpath.Destination[i].second);
471 for (uint j = 0; j < subvarpath.Destination.size (); j++)
473 // set the variable name
474 string cmd = subvarpath.Destination[j].first;
476 if (isRemoteCommand(cmd))
478 if (async && RemoteClientCallback != 0)
480 // ok we have to send the request to another side, just send and wait
481 addRequestWaitingNb (rid);
482 RemoteClientCallback (rid, cmd, varpath.Destination[i].first);
485 else
487 // replace = with space to execute the command
488 string::size_type eqpos = cmd.find("=");
489 if (eqpos != string::npos)
491 cmd[eqpos] = ' ';
492 // add the entity
493 cmd.insert(eqpos, " "+varpath.Destination[i].first);
495 else
497 // add the entity
498 cmd += " "+varpath.Destination[i].first;
501 mdDisplayVars.clear ();
502 ICommand::execute(cmd, logDisplayVars, true);
503 const std::deque<std::string> &strs = mdDisplayVars.lockStrings();
504 for (uint k = 0; k < strs.size(); k++)
506 const string &str = strs[k];
508 string::size_type pos = str.find(" ");
509 if(pos == string::npos)
510 continue;
512 string entity = str.substr(0, pos);
513 string value = str.substr(pos+1, str.size()-pos-2);
514 for (uint u = 0; u < value.size(); u++) if (value[u] == ' ') value[u] = '_';
516 // look in the array if we already have something about this entity
518 if (!async)
520 uint y;
521 for (y = 0; y < answer.size(); y++)
523 if (answer[y].Values[1] == entity)
525 // ok we found it, just push_back new stuff
526 varNames = &(answer[y].VarNames);
527 values = &(answer[y].Values);
528 break;
531 if (y == answer.size ())
533 answer.push_back (SAdminViewRow());
535 varNames = &(answer[answer.size()-1].VarNames);
536 values = &(answer[answer.size()-1].Values);
538 // don't add service if we want an entity
539 // todo when we work on entity, we don't need service name and server so we should remove them and collapse all var for the same entity
540 varNames->push_back ("service");
541 string name = IService::getInstance ()->getServiceUnifiedName();
542 values->push_back (name);
544 // add default row
545 varNames->push_back ("entity");
546 values->push_back (entity);
549 varNames->push_back (cmd.substr(0, cmd.find(" ")));
550 values->push_back (value);
552 else
554 addRequestWaitingNb (rid);
556 TAdminViewVarNames varNames;
557 TAdminViewValues values;
558 varNames.push_back ("service");
559 string name = IService::getInstance ()->getServiceUnifiedName();
560 values.push_back (name);
562 // add default row
563 varNames.push_back ("entity");
564 values.push_back (entity);
566 varNames.push_back (cmd.substr(0, cmd.find(" ")));
567 values.push_back (value);
569 addRequestAnswer (rid, varNames, values);
571 nlinfo ("ADMIN: Add to result view for entity '%s', '%s' = '%s'", varpath.Destination[i].first.c_str(), subvarpath.Destination[j].first.c_str(), str.c_str());
573 mdDisplayVars.unlockStrings();
582 // Alarms functions
585 void sendAdminEmail (const char *format, ...)
587 char *text;
588 NLMISC_CONVERT_VARGS (text, format, 4096);
590 time_t t = time (&t);
592 string str;
593 str = asctime (localtime (&t));
594 str += " Server " + IService::getInstance()->getHostName();
595 str += " service " + IService::getInstance()->getServiceUnifiedName();
596 str += " : ";
597 str += text;
599 CMessage msgout("ADMIN_EMAIL");
600 msgout.serial (str);
601 if(IService::getInstance ()->getServiceShortName()=="AES")
602 CUnifiedNetwork::getInstance ()->send ("AS", msgout);
603 else
604 CUnifiedNetwork::getInstance ()->send ("AES", msgout);
606 nlinfo ("ADMIN: Forwarded email to AS with '%s'", str.c_str());
609 void initAdmin (bool dontUseAES)
611 if (!dontUseAES)
613 CUnifiedNetwork::getInstance()->setServiceUpCallback ("AES", cbAESConnection, NULL);
614 CUnifiedNetwork::getInstance()->setServiceDownCallback ("AES", cbAESDisconnection, NULL);
615 CUnifiedNetwork::getInstance()->addService ("AES", CInetAddress("localhost:49997"));
617 CUnifiedNetwork::getInstance()->addCallbackArray (CallbackArray, sizeof(CallbackArray)/sizeof(CallbackArray[0]));
621 void updateAdmin()
623 uint32 CurrentTime = CTime::getSecondsSince1970();
627 // check admin requests
630 cleanRequest ();
634 // Check graph updates
637 static uint32 lastGraphUpdateCheck = 0;
639 if (CurrentTime >= lastGraphUpdateCheck+1)
641 string str;
642 CLog logDisplayVars;
643 CLightMemDisplayer mdDisplayVars;
644 logDisplayVars.addDisplayer (&mdDisplayVars);
646 lastGraphUpdateCheck = CurrentTime;
648 CMessage msgout ("GRAPH_UPDATE");
649 bool empty = true;
650 for (uint j = 0; j < GraphUpdates.size(); j++)
652 if (CurrentTime >= GraphUpdates[j].LastUpdate + GraphUpdates[j].Update)
654 // have to send a new update for this var
655 ICommand::execute(GraphUpdates[j].Name, logDisplayVars, true, false);
656 const std::deque<std::string> &strs = mdDisplayVars.lockStrings();
657 sint32 val;
658 if (strs.size() != 1)
660 nlwarning ("ADMIN: The graph update command execution not return exactly 1 line but %d", strs.size());
661 for (uint i = 0; i < strs.size(); i++)
662 nlwarning ("ADMIN: line %d: '%s'", i, strs[i].c_str());
663 val = 0;
665 else
667 fromString(strs[0], val);
669 mdDisplayVars.unlockStrings ();
670 mdDisplayVars.clear ();
672 string name = IService::getInstance()->getServiceAliasName();
673 if (name.empty())
674 name = IService::getInstance()->getServiceShortName();
676 if(empty)
677 msgout.serial (CurrentTime);
679 msgout.serial (name);
680 msgout.serial (GraphUpdates[j].Name);
681 msgout.serial (val);
683 empty = false;
685 GraphUpdates[j].LastUpdate = CurrentTime;
689 if(!empty)
691 if(IService::getInstance ()->getServiceShortName()=="AES")
692 CUnifiedNetwork::getInstance ()->send ("AS", msgout);
693 else
694 CUnifiedNetwork::getInstance ()->send ("AES", msgout);
700 // Check alarms
703 static uint32 lastAlarmsCheck = 0;
705 if (CurrentTime >= lastAlarmsCheck+AlarmCheckDelay)
707 string str;
708 CLog logDisplayVars;
709 CLightMemDisplayer mdDisplayVars;
710 logDisplayVars.addDisplayer (&mdDisplayVars);
712 lastAlarmsCheck = CTime::getSecondsSince1970();
714 for (uint i = 0; i < Alarms.size(); )
716 mdDisplayVars.clear ();
717 ICommand::execute(Alarms[i].Name, logDisplayVars, true, false);
718 const std::deque<std::string> &strs = mdDisplayVars.lockStrings();
720 if (!strs.empty())
722 str = strs[0].substr(0,strs[0].size()-1);
724 else
726 str = "???";
729 mdDisplayVars.unlockStrings();
731 if (str == "???")
733 // variable doesn't exist, remove it from alarms
734 nlwarning ("ADMIN: Alarm problem: variable '%s' returns ??? instead of a good value", Alarms[i].Name.c_str());
735 Alarms.erase (Alarms.begin()+i);
737 else
739 // compare the value
740 uint32 err = Alarms[i].Limit;
741 uint32 val = humanReadableToBytes(str);
742 if (Alarms[i].GT && val >= err)
744 if (!Alarms[i].Activated)
746 nlinfo ("ADMIN: VARIABLE TOO BIG '%s' %u >= %u", Alarms[i].Name.c_str(), val, err);
747 Alarms[i].Activated = true;
748 sendAdminEmail ("Alarm: Variable %s is %u that is greater or equal than the limit %u", Alarms[i].Name.c_str(), val, err);
751 else if (!Alarms[i].GT && val <= err)
753 if (!Alarms[i].Activated)
755 nlinfo ("ADMIN: VARIABLE TOO LOW '%s' %u <= %u", Alarms[i].Name.c_str(), val, err);
756 Alarms[i].Activated = true;
757 sendAdminEmail ("Alarm: Variable %s is %u that is lower or equal than the limit %u", Alarms[i].Name.c_str(), val, err);
760 else
762 if (Alarms[i].Activated)
764 nlinfo ("ADMIN: variable is ok '%s' %u %s %u", Alarms[i].Name.c_str(), val, (Alarms[i].GT?"<":">"), err);
765 Alarms[i].Activated = false;
769 i++;
775 void setInformation (const vector<string> &alarms, const vector<string> &graphupdate)
777 uint i;
778 sint tmp;
780 // add only commands that I understand
781 Alarms.clear ();
782 for (i = 0; i < alarms.size(); i+=3)
784 CVarPath shardvarpath (alarms[i]);
785 if(shardvarpath.Destination.empty() || shardvarpath.Destination[0].second.empty())
786 continue;
787 CVarPath servervarpath (shardvarpath.Destination[0].second);
788 if(servervarpath.Destination.empty() || servervarpath.Destination[0].second.empty())
789 continue;
790 CVarPath servicevarpath (servervarpath.Destination[0].second);
791 if(servicevarpath.Destination.empty() || servicevarpath.Destination[0].second.empty())
792 continue;
794 string name = servicevarpath.Destination[0].second;
796 if (IService::getInstance()->getServiceUnifiedName().find(servicevarpath.Destination[0].first) != string::npos && ICommand::exists(name))
798 fromString(alarms[i+1], tmp);
799 nlinfo ("ADMIN: Adding alarm '%s' limit %d order %s (varpath '%s')", name.c_str(), tmp, alarms[i+2].c_str(), alarms[i].c_str());
800 Alarms.push_back(CAlarm(name, tmp, alarms[i+2]=="gt"));
802 else
804 if (IService::getInstance()->getServiceUnifiedName().find(servicevarpath.Destination[0].first) == string::npos)
806 nlinfo ("ADMIN: Skipping alarm '%s' limit %d order %s (varpath '%s') (not for my service, i'm '%s')", name.c_str(), fromString(alarms[i+1], tmp) ? tmp:tmp, alarms[i+2].c_str(), alarms[i].c_str(), IService::getInstance()->getServiceUnifiedName().c_str());
808 else
810 nlinfo ("ADMIN: Skipping alarm '%s' limit %d order %s (varpath '%s') (var not exist)", name.c_str(), fromString(alarms[i+1], tmp) ? tmp:tmp, alarms[i+2].c_str(), alarms[i].c_str());
815 // do the same with graph update
816 GraphUpdates.clear ();
817 for (i = 0; i < graphupdate.size(); i+=2)
819 CVarPath shardvarpath (graphupdate[i]);
820 if(shardvarpath.Destination.empty() || shardvarpath.Destination[0].second.empty())
821 continue;
822 CVarPath servervarpath (shardvarpath.Destination[0].second);
823 if(servervarpath.Destination.empty() || servervarpath.Destination[0].second.empty())
824 continue;
825 CVarPath servicevarpath (servervarpath.Destination[0].second);
826 if(servicevarpath.Destination.empty() || servicevarpath.Destination[0].second.empty())
827 continue;
829 string VarName = servicevarpath.Destination[0].second;
830 string ServiceName = servicevarpath.Destination[0].first;
832 if (ICommand::exists(VarName) && (ServiceName == "*" || IService::getInstance()->getServiceShortName() == ServiceName))
834 fromString(graphupdate[i+1], tmp);
835 nlinfo ("ADMIN: Adding graphupdate '%s' update %d (varpath '%s')", VarName.c_str(), tmp, graphupdate[i].c_str());
836 GraphUpdates.push_back(CGraphUpdate(VarName, tmp));
838 else
840 if (IService::getInstance()->getServiceShortName() != ServiceName)
842 nlinfo ("ADMIN: Skipping graphupdate '%s' limit %d (varpath '%s') (not for my service, i'm '%s')", VarName.c_str(), fromString(graphupdate[i+1], tmp) ? tmp:tmp, graphupdate[i].c_str(), IService::getInstance()->getServiceUnifiedName().c_str());
844 else
846 nlinfo ("ADMIN: Skipping graphupdate '%s' limit %d (varpath '%s') (var not exist)", VarName.c_str(), fromString(graphupdate[i+1], tmp) ? tmp:tmp, graphupdate[i].c_str());
853 // Commands
856 NLMISC_CATEGORISED_COMMAND(nel, displayInformation, "displays all admin information", "")
858 nlunreferenced(rawCommandString);
859 nlunreferenced(args);
860 nlunreferenced(quiet);
861 nlunreferenced(human);
863 uint i;
865 log.displayNL("There're %d alarms:", Alarms.size());
866 for (i = 0; i < Alarms.size(); i++)
868 log.displayNL(" %d %s %d %s %s", i, Alarms[i].Name.c_str(), Alarms[i].Limit, (Alarms[i].GT?"gt":"lt"), (Alarms[i].Activated?"on":"off"));
870 log.displayNL("There're %d graphupdate:", GraphUpdates.size());
871 for (i = 0; i < GraphUpdates.size(); i++)
873 log.displayNL(" %d %s %d %d", i, GraphUpdates[i].Name.c_str(), GraphUpdates[i].Update, GraphUpdates[i].LastUpdate);
875 return true;
878 NLMISC_CATEGORISED_COMMAND(nel, getView, "send a view and receive an array as result", "<varpath>")
880 nlunreferenced(rawCommandString);
881 nlunreferenced(quiet);
882 nlunreferenced(human);
884 if(args.size() != 1) return false;
886 TAdminViewResult answer;
887 serviceGetView (0, args[0], answer);
889 log.displayNL("have %d answer", answer.size());
890 for (uint i = 0; i < answer.size(); i++)
892 log.displayNL(" have %d value", answer[i].VarNames.size());
894 nlassert (answer[i].VarNames.size() == answer[i].Values.size());
896 for (uint j = 0; j < answer[i].VarNames.size(); j++)
898 log.displayNL(" %s -> %s", answer[i].VarNames[j].c_str(), answer[i].Values[j].c_str());
902 return true;
905 } // NLNET