// NeL - MMORPG Framework <http://dev.ryzom.com/projects/nel/>
// Copyright (C) 2010 Winch Gate Property Limited
//
// This program is free software: you can redistribute it and/or modify
// it under the terms of the GNU Affero General Public License as
// published by the Free Software Foundation, either version 3 of the
// License, or (at your option) any later version.
//
// This program is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU Affero General Public License for more details.
//
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <http://www.gnu.org/licenses/>.
//
// Includes
//
# include "stdnet.h"
# include "nel/net/service.h"
# include "nel/net/admin.h"
# include "nel/net/varpath.h"
//
// Namspaces
//
using namespace std ;
using namespace NLMISC ;
using namespace NLNET ;
namespace NLNET {
//
// Structures
//
struct CRequest
{
CRequest ( uint32 id , TServiceId sid ) : Id ( id ) , NbWaiting ( 0 ) , NbReceived ( 0 ) , SId ( sid )
{
nldebug ( " ADMIN: ++ NbWaiting %d NbReceived %d " , NbWaiting , NbReceived ) ;
Time = CTime : : getSecondsSince1970 ( ) ;
}
uint32 Id ;
uint NbWaiting ;
uint32 NbReceived ;
TServiceId SId ;
uint32 Time ; // when the request was ask
TAdminViewResult Answers ;
} ;
//
// Variables
//
TRemoteClientCallback RemoteClientCallback = 0 ;
vector < CAlarm > Alarms ;
vector < CGraphUpdate > GraphUpdates ;
// check alarms every 5 seconds
const uint32 AlarmCheckDelay = 5 ;
vector < CRequest > Requests ;
uint32 RequestTimeout = 4 ; // in second
//
// Callbacks
//
static void cbInfo ( CMessage & msgin , const std : : string & /* serviceName */ , TServiceId /* sid */ )
{
nlinfo ( " ADMIN: Updating admin information " ) ;
vector < string > alarms ;
msgin . serialCont ( alarms ) ;
vector < string > graphupdate ;
msgin . serialCont ( graphupdate ) ;
setInformation ( alarms , graphupdate ) ;
}
static void cbServGetView ( CMessage & msgin , const std : : string & /* serviceName */ , TServiceId sid )
{
uint32 rid ;
string rawvarpath ;
msgin . serial ( rid ) ;
msgin . serial ( rawvarpath ) ;
Requests . push_back ( CRequest ( rid , sid ) ) ;
TAdminViewResult answer ;
// just send the view in async mode, don't retrieve the answer
serviceGetView ( rid , rawvarpath , answer , true ) ;
nlassert ( answer . empty ( ) ) ;
}
static void cbExecCommand ( CMessage & msgin , const std : : string & /* serviceName */ , TServiceId sid )
{
// create a displayer to gather the output of the command
class CStringDisplayer : public IDisplayer
{
public :
void serial ( NLMISC : : IStream & stream )
{
stream . serial ( _Data ) ;
}
protected :
virtual void doDisplay ( const CLog : : TDisplayInfo & /* args */ , const char * message )
{
_Data + = message ;
}
std : : string _Data ;
} ;
CStringDisplayer stringDisplayer ;
IService : : getInstance ( ) - > CommandLog . addDisplayer ( & stringDisplayer ) ;
// retreive the command from the input message and execute it
string command ;
msgin . serial ( command ) ;
nlinfo ( " ADMIN: Executing command from network : '%s' " , command . c_str ( ) ) ;
ICommand : : execute ( command , IService : : getInstance ( ) - > CommandLog ) ;
// unhook our displayer as it's work is now done
IService : : getInstance ( ) - > CommandLog . removeDisplayer ( & stringDisplayer ) ;
// send a reply message to the originating service
CMessage msgout ( " EXEC_COMMAND_RESULT " ) ;
stringDisplayer . serial ( msgout ) ;
CUnifiedNetwork : : getInstance ( ) - > send ( sid , msgout ) ;
}
// AES wants to know if i'm not dead, I have to answer faster as possible or i'll be killed
static void cbAdminPing ( CMessage & /* msgin */ , const std : : string & /* serviceName */ , TServiceId sid )
{
// Send back a pong to say to the AES that I'm alive
CMessage msgout ( " ADMIN_PONG " ) ;
CUnifiedNetwork : : getInstance ( ) - > send ( sid , msgout ) ;
}
static void cbStopService ( CMessage & /* msgin */ , const std : : string & serviceName , TServiceId sid )
{
nlinfo ( " ADMIN: Receive a stop from service %s-%hu, need to quit " , serviceName . c_str ( ) , sid . get ( ) ) ;
IService : : getInstance ( ) - > exit ( 0xFFFF ) ;
}
void cbAESConnection ( const string & /* serviceName */ , TServiceId /* sid */ , void * /* arg */ )
{
// established a connection to the AES, identify myself
//
// Sends the identification message with the name of the service and all commands available on this service
//
nlinfo ( " cbAESConnection: Identifying self as: AliasName='%s' LongName='%s' PId=%u " ,
IService : : getInstance ( ) - > _AliasName . c_str ( ) ,
IService : : getInstance ( ) - > _LongName . c_str ( ) ,
getpid ( ) ) ;
CMessage msgout ( " SID " ) ;
uint32 pid = getpid ( ) ;
msgout . serial ( IService : : getInstance ( ) - > _AliasName , IService : : getInstance ( ) - > _LongName , pid ) ;
ICommand : : serialCommands ( msgout ) ;
CUnifiedNetwork : : getInstance ( ) - > send ( " AES " , msgout ) ;
if ( IService : : getInstance ( ) - > _Initialized )
{
CMessage msgout2 ( " SR " ) ;
CUnifiedNetwork : : getInstance ( ) - > send ( " AES " , msgout2 ) ;
}
}
static void cbAESDisconnection ( const std : : string & serviceName , TServiceId sid , void * /* arg */ )
{
nlinfo ( " Lost connection to the %s-%hu " , serviceName . c_str ( ) , sid . get ( ) ) ;
}
static TUnifiedCallbackItem CallbackArray [ ] =
{
{ " INFO " , cbInfo } ,
{ " GET_VIEW " , cbServGetView } ,
{ " STOPS " , cbStopService } ,
{ " EXEC_COMMAND " , cbExecCommand } ,
{ " ADMIN_PING " , cbAdminPing } ,
} ;
//
// Functions
//
void setRemoteClientCallback ( TRemoteClientCallback cb )
{
RemoteClientCallback = cb ;
}
//
// Request functions
//
static void addRequestWaitingNb ( uint32 rid )
{
for ( uint i = 0 ; i < Requests . size ( ) ; i + + )
{
if ( Requests [ i ] . Id = = rid )
{
Requests [ i ] . NbWaiting + + ;
nldebug ( " ADMIN: ++ i %d rid %d NbWaiting+ %d NbReceived %d " , i , Requests [ i ] . Id , Requests [ i ] . NbWaiting , Requests [ i ] . NbReceived ) ;
// if we add a waiting, reset the timer
Requests [ i ] . Time = CTime : : getSecondsSince1970 ( ) ;
return ;
}
}
nlwarning ( " ADMIN: addRequestWaitingNb: can't find the rid %d " , rid ) ;
}
/*
static void subRequestWaitingNb ( uint32 rid )
{
for ( uint i = 0 ; i < Requests . size ( ) ; i + + )
{
if ( Requests [ i ] . Id = = rid )
{
Requests [ i ] . NbWaiting - - ;
nldebug ( " ADMIN: ++ i %d rid %d NbWaiting- %d NbReceived %d " , i , Requests [ i ] . Id , Requests [ i ] . NbWaiting , Requests [ i ] . NbReceived ) ;
return ;
}
}
nlwarning ( " ADMIN: subRequestWaitingNb: can't find the rid %d " , rid ) ;
}
*/
void addRequestAnswer ( uint32 rid , const TAdminViewVarNames & varNames , const TAdminViewValues & values )
{
if ( ! varNames . empty ( ) & & varNames [ 0 ] = = " __log " )
{ nlassert ( varNames . size ( ) = = 1 ) ; }
else
{ nlassert ( varNames . size ( ) = = values . size ( ) ) ; }
for ( uint i = 0 ; i < Requests . size ( ) ; i + + )
{
if ( Requests [ i ] . Id = = rid )
{
Requests [ i ] . Answers . push_back ( SAdminViewRow ( varNames , values ) ) ;
Requests [ i ] . NbReceived + + ;
nldebug ( " ADMIN: ++ i %d rid %d NbWaiting %d NbReceived+ %d " , i , Requests [ i ] . Id , Requests [ i ] . NbWaiting , Requests [ i ] . NbReceived ) ;
return ;
}
}
// we received an unknown request, forget it
nlwarning ( " ADMIN: Receive an answer for unknown request %d " , rid ) ;
}
/*
static bool emptyRequest ( uint32 rid )
{
for ( uint i = 0 ; i < Requests . size ( ) ; i + + )
{
if ( Requests [ i ] . Id = = rid & & Requests [ i ] . NbWaiting ! = 0 )
{
return false ;
}
}
return true ;
}
*/
static void cleanRequest ( )
{
uint32 currentTime = CTime : : getSecondsSince1970 ( ) ;
for ( uint i = 0 ; i < Requests . size ( ) ; )
{
// timeout
if ( currentTime > = Requests [ i ] . Time + RequestTimeout )
{
nlwarning ( " ADMIN: **** i %d rid %d -> Requests[i].NbWaiting (%d) != Requests[i].NbReceived (%d) " , i , Requests [ i ] . Id , Requests [ i ] . NbWaiting , Requests [ i ] . NbReceived ) ;
Requests [ i ] . NbWaiting = Requests [ i ] . NbReceived ;
}
if ( Requests [ i ] . NbWaiting < = Requests [ i ] . NbReceived )
{
// the request is over, send to the php
CMessage msgout ( " VIEW " ) ;
msgout . serial ( Requests [ i ] . Id ) ;
for ( uint j = 0 ; j < Requests [ i ] . Answers . size ( ) ; j + + )
{
msgout . serialCont ( Requests [ i ] . Answers [ j ] . VarNames ) ;
msgout . serialCont ( Requests [ i ] . Answers [ j ] . Values ) ;
}
if ( Requests [ i ] . SId . get ( ) = = 0 )
{
nlinfo ( " ADMIN: Receive an answer for the fake request %d with %d answers " , Requests [ i ] . Id , Requests [ i ] . Answers . size ( ) ) ;
for ( uint j = 0 ; j < Requests [ i ] . Answers . size ( ) ; j + + )
{
uint k ;
for ( k = 0 ; k < Requests [ i ] . Answers [ j ] . VarNames . size ( ) ; k + + )
{
InfoLog - > displayRaw ( " %-10s " , Requests [ i ] . Answers [ j ] . VarNames [ k ] . c_str ( ) ) ;
}
InfoLog - > displayRawNL ( " " ) ;
for ( k = 0 ; k < Requests [ i ] . Answers [ j ] . Values . size ( ) ; k + + )
{
InfoLog - > displayRaw ( " %-10s " , Requests [ i ] . Answers [ j ] . Values [ k ] . c_str ( ) ) ;
}
InfoLog - > displayRawNL ( " " ) ;
InfoLog - > displayRawNL ( " ------------------------- " ) ;
}
}
else
{
nlinfo ( " ADMIN: The request is over, send the result to AES " ) ;
CUnifiedNetwork : : getInstance ( ) - > send ( Requests [ i ] . SId , msgout ) ;
}
// set to 0 to erase it
Requests [ i ] . NbWaiting = 0 ;
nldebug ( " ADMIN: ++ i %d rid %d NbWaiting0 %d NbReceived %d " , i , Requests [ i ] . Id , Requests [ i ] . NbWaiting , Requests [ i ] . NbReceived ) ;
}
if ( Requests [ i ] . NbWaiting = = 0 )
{
Requests . erase ( Requests . begin ( ) + i ) ;
}
else
{
i + + ;
}
}
}
// all remote command start with rc or RC
bool isRemoteCommand ( string & str )
{
if ( str . size ( ) < 2 ) return false ;
return tolower ( str [ 0 ] ) = = ' r ' & & tolower ( str [ 1 ] ) = = ' c ' ;
}
// this callback is used to create a view for the admin system
void serviceGetView ( uint32 rid , const string & rawvarpath , TAdminViewResult & answer , bool async )
{
string str ;
CLog logDisplayVars ;
CLightMemDisplayer mdDisplayVars ;
logDisplayVars . addDisplayer ( & mdDisplayVars ) ;
mdDisplayVars . setParam ( 4096 ) ;
CVarPath varpath ( rawvarpath ) ;
if ( varpath . empty ( ) )
return ;
// special case for named command handler
if ( CCommandRegistry : : getInstance ( ) . isNamedCommandHandler ( varpath . Destination [ 0 ] . first ) )
{
varpath . Destination [ 0 ] . first + = " . " + varpath . Destination [ 0 ] . second ;
varpath . Destination [ 0 ] . second = " " ;
}
if ( varpath . isFinal ( ) )
{
TAdminViewVarNames varNames ;
TAdminViewValues values ;
// add default row
varNames . push_back ( " service " ) ;
values . push_back ( IService : : getInstance ( ) - > getServiceUnifiedName ( ) ) ;
for ( uint j = 0 ; j < varpath . Destination . size ( ) ; j + + )
{
string cmd = varpath . Destination [ j ] . first ;
// replace = with space to execute the command
string : : size_type eqpos = cmd . find ( " = " ) ;
if ( eqpos ! = string : : npos )
{
cmd [ eqpos ] = ' ' ;
varNames . push_back ( cmd . substr ( 0 , eqpos ) ) ;
}
else
varNames . push_back ( cmd ) ;
mdDisplayVars . clear ( ) ;
ICommand : : execute ( cmd , logDisplayVars , ! ICommand : : isCommand ( cmd ) ) ;
const std : : deque < std : : string > & strs = mdDisplayVars . lockStrings ( ) ;
if ( ICommand : : isCommand ( cmd ) )
{
// we want the log of the command
if ( j = = 0 )
{
varNames . clear ( ) ;
varNames . push_back ( " __log " ) ;
values . clear ( ) ;
}
values . push_back ( " ----- Result from " + IService : : getInstance ( ) - > getServiceUnifiedName ( ) + " of command ' " + cmd + " ' \n " ) ;
for ( uint k = 0 ; k < strs . size ( ) ; k + + )
{
values . push_back ( strs [ k ] ) ;
}
}
else
{
if ( strs . size ( ) > 0 )
{
str = strs [ 0 ] . substr ( 0 , strs [ 0 ] . size ( ) - 1 ) ;
// replace all spaces into udnerscore because space is a reserved char
for ( uint i = 0 ; i < str . size ( ) ; i + + ) if ( str [ i ] = = ' ' ) str [ i ] = ' _ ' ;
}
else
{
str = " ??? " ;
}
values . push_back ( str ) ;
nlinfo ( " ADMIN: Add to result view '%s' = '%s' " , varpath . Destination [ j ] . first . c_str ( ) , str . c_str ( ) ) ;
}
mdDisplayVars . unlockStrings ( ) ;
}
if ( ! async )
answer . push_back ( SAdminViewRow ( varNames , values ) ) ;
else
{
addRequestWaitingNb ( rid ) ;
addRequestAnswer ( rid , varNames , values ) ;
}
}
else
{
// there s an entity in the varpath, manage this case
TAdminViewVarNames * varNames = 0 ;
TAdminViewValues * values = 0 ;
// varpath.Destination contains the entity number
// subvarpath.Destination contains the command name
for ( uint i = 0 ; i < varpath . Destination . size ( ) ; i + + )
{
CVarPath subvarpath ( varpath . Destination [ i ] . second ) ;
for ( uint j = 0 ; j < subvarpath . Destination . size ( ) ; j + + )
{
// set the variable name
string cmd = subvarpath . Destination [ j ] . first ;
if ( isRemoteCommand ( cmd ) )
{
if ( async & & RemoteClientCallback ! = 0 )
{
// ok we have to send the request to another side, just send and wait
addRequestWaitingNb ( rid ) ;
RemoteClientCallback ( rid , cmd , varpath . Destination [ i ] . first ) ;
}
}
else
{
// replace = with space to execute the command
string : : size_type eqpos = cmd . find ( " = " ) ;
if ( eqpos ! = string : : npos )
{
cmd [ eqpos ] = ' ' ;
// add the entity
cmd . insert ( eqpos , " " + varpath . Destination [ i ] . first ) ;
}
else
{
// add the entity
cmd + = " " + varpath . Destination [ i ] . first ;
}
mdDisplayVars . clear ( ) ;
ICommand : : execute ( cmd , logDisplayVars , true ) ;
const std : : deque < std : : string > & strs = mdDisplayVars . lockStrings ( ) ;
for ( uint k = 0 ; k < strs . size ( ) ; k + + )
{
const string & str = strs [ k ] ;
string : : size_type pos = str . find ( " " ) ;
if ( pos = = string : : npos )
continue ;
string entity = str . substr ( 0 , pos ) ;
string value = str . substr ( pos + 1 , str . size ( ) - pos - 2 ) ;
for ( uint u = 0 ; u < value . size ( ) ; u + + ) if ( value [ u ] = = ' ' ) value [ u ] = ' _ ' ;
// look in the array if we already have something about this entity
if ( ! async )
{
uint y ;
for ( y = 0 ; y < answer . size ( ) ; y + + )
{
if ( answer [ y ] . Values [ 1 ] = = entity )
{
// ok we found it, just push_back new stuff
varNames = & ( answer [ y ] . VarNames ) ;
values = & ( answer [ y ] . Values ) ;
break ;
}
}
if ( y = = answer . size ( ) )
{
answer . push_back ( SAdminViewRow ( ) ) ;
varNames = & ( answer [ answer . size ( ) - 1 ] . VarNames ) ;
values = & ( answer [ answer . size ( ) - 1 ] . Values ) ;
// don't add service if we want an entity
// 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
varNames - > push_back ( " service " ) ;
string name = IService : : getInstance ( ) - > getServiceUnifiedName ( ) ;
values - > push_back ( name ) ;
// add default row
varNames - > push_back ( " entity " ) ;
values - > push_back ( entity ) ;
}
varNames - > push_back ( cmd . substr ( 0 , cmd . find ( " " ) ) ) ;
values - > push_back ( value ) ;
}
else
{
addRequestWaitingNb ( rid ) ;
TAdminViewVarNames varNames ;
TAdminViewValues values ;
varNames . push_back ( " service " ) ;
string name = IService : : getInstance ( ) - > getServiceUnifiedName ( ) ;
values . push_back ( name ) ;
// add default row
varNames . push_back ( " entity " ) ;
values . push_back ( entity ) ;
varNames . push_back ( cmd . substr ( 0 , cmd . find ( " " ) ) ) ;
values . push_back ( value ) ;
addRequestAnswer ( rid , varNames , values ) ;
}
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 ( ) ) ;
}
mdDisplayVars . unlockStrings ( ) ;
}
}
}
}
}
//
// Alarms functions
//
void sendAdminEmail ( const char * format , . . . )
{
char * text ;
NLMISC_CONVERT_VARGS ( text , format , 4096 ) ;
time_t t = time ( & t ) ;
string str ;
str = asctime ( localtime ( & t ) ) ;
str + = " Server " + IService : : getInstance ( ) - > getHostName ( ) ;
str + = " service " + IService : : getInstance ( ) - > getServiceUnifiedName ( ) ;
str + = " : " ;
str + = text ;
CMessage msgout ( " ADMIN_EMAIL " ) ;
msgout . serial ( str ) ;
if ( IService : : getInstance ( ) - > getServiceShortName ( ) = = " AES " )
CUnifiedNetwork : : getInstance ( ) - > send ( " AS " , msgout ) ;
else
CUnifiedNetwork : : getInstance ( ) - > send ( " AES " , msgout ) ;
nlinfo ( " ADMIN: Forwarded email to AS with '%s' " , str . c_str ( ) ) ;
}
void initAdmin ( bool dontUseAES )
{
if ( ! dontUseAES )
{
CUnifiedNetwork : : getInstance ( ) - > setServiceUpCallback ( " AES " , cbAESConnection , NULL ) ;
CUnifiedNetwork : : getInstance ( ) - > setServiceDownCallback ( " AES " , cbAESDisconnection , NULL ) ;
CUnifiedNetwork : : getInstance ( ) - > addService ( " AES " , CInetAddress ( " localhost:49997 " ) ) ;
}
CUnifiedNetwork : : getInstance ( ) - > addCallbackArray ( CallbackArray , sizeof ( CallbackArray ) / sizeof ( CallbackArray [ 0 ] ) ) ;
}
void updateAdmin ( )
{
uint32 CurrentTime = CTime : : getSecondsSince1970 ( ) ;
//
// check admin requests
//
cleanRequest ( ) ;
//
// Check graph updates
//
static uint32 lastGraphUpdateCheck = 0 ;
if ( CurrentTime > = lastGraphUpdateCheck + 1 )
{
string str ;
CLog logDisplayVars ;
CLightMemDisplayer mdDisplayVars ;
logDisplayVars . addDisplayer ( & mdDisplayVars ) ;
lastGraphUpdateCheck = CurrentTime ;
CMessage msgout ( " GRAPH_UPDATE " ) ;
bool empty = true ;
for ( uint j = 0 ; j < GraphUpdates . size ( ) ; j + + )
{
if ( CurrentTime > = GraphUpdates [ j ] . LastUpdate + GraphUpdates [ j ] . Update )
{
// have to send a new update for this var
ICommand : : execute ( GraphUpdates [ j ] . Name , logDisplayVars , true , false ) ;
const std : : deque < std : : string > & strs = mdDisplayVars . lockStrings ( ) ;
sint32 val ;
if ( strs . size ( ) ! = 1 )
{
nlwarning ( " ADMIN: The graph update command execution not return exactly 1 line but %d " , strs . size ( ) ) ;
for ( uint i = 0 ; i < strs . size ( ) ; i + + )
nlwarning ( " ADMIN: line %d: '%s' " , i , strs [ i ] . c_str ( ) ) ;
val = 0 ;
}
else
{
fromString ( strs [ 0 ] , val ) ;
}
mdDisplayVars . unlockStrings ( ) ;
mdDisplayVars . clear ( ) ;
string name = IService : : getInstance ( ) - > getServiceAliasName ( ) ;
if ( name . empty ( ) )
name = IService : : getInstance ( ) - > getServiceShortName ( ) ;
if ( empty )
msgout . serial ( CurrentTime ) ;
msgout . serial ( name ) ;
msgout . serial ( GraphUpdates [ j ] . Name ) ;
msgout . serial ( val ) ;
empty = false ;
GraphUpdates [ j ] . LastUpdate = CurrentTime ;
}
}
if ( ! empty )
{
if ( IService : : getInstance ( ) - > getServiceShortName ( ) = = " AES " )
CUnifiedNetwork : : getInstance ( ) - > send ( " AS " , msgout ) ;
else
CUnifiedNetwork : : getInstance ( ) - > send ( " AES " , msgout ) ;
}
}
//
// Check alarms
//
static uint32 lastAlarmsCheck = 0 ;
if ( CurrentTime > = lastAlarmsCheck + AlarmCheckDelay )
{
string str ;
CLog logDisplayVars ;
CLightMemDisplayer mdDisplayVars ;
logDisplayVars . addDisplayer ( & mdDisplayVars ) ;
lastAlarmsCheck = CTime : : getSecondsSince1970 ( ) ;
for ( uint i = 0 ; i < Alarms . size ( ) ; )
{
mdDisplayVars . clear ( ) ;
ICommand : : execute ( Alarms [ i ] . Name , logDisplayVars , true , false ) ;
const std : : deque < std : : string > & strs = mdDisplayVars . lockStrings ( ) ;
if ( strs . size ( ) > 0 )
{
str = strs [ 0 ] . substr ( 0 , strs [ 0 ] . size ( ) - 1 ) ;
}
else
{
str = " ??? " ;
}
mdDisplayVars . unlockStrings ( ) ;
if ( str = = " ??? " )
{
// variable doesn't exist, remove it from alarms
nlwarning ( " ADMIN: Alarm problem: variable '%s' returns ??? instead of a good value " , Alarms [ i ] . Name . c_str ( ) ) ;
Alarms . erase ( Alarms . begin ( ) + i ) ;
}
else
{
// compare the value
uint32 err = Alarms [ i ] . Limit ;
uint32 val = humanReadableToBytes ( str ) ;
if ( Alarms [ i ] . GT & & val > = err )
{
if ( ! Alarms [ i ] . Activated )
{
nlinfo ( " ADMIN: VARIABLE TOO BIG '%s' %u >= %u " , Alarms [ i ] . Name . c_str ( ) , val , err ) ;
Alarms [ i ] . Activated = true ;
sendAdminEmail ( " Alarm: Variable %s is %u that is greater or equal than the limit %u " , Alarms [ i ] . Name . c_str ( ) , val , err ) ;
}
}
else if ( ! Alarms [ i ] . GT & & val < = err )
{
if ( ! Alarms [ i ] . Activated )
{
nlinfo ( " ADMIN: VARIABLE TOO LOW '%s' %u <= %u " , Alarms [ i ] . Name . c_str ( ) , val , err ) ;
Alarms [ i ] . Activated = true ;
sendAdminEmail ( " Alarm: Variable %s is %u that is lower or equal than the limit %u " , Alarms [ i ] . Name . c_str ( ) , val , err ) ;
}
}
else
{
if ( Alarms [ i ] . Activated )
{
nlinfo ( " ADMIN: variable is ok '%s' %u %s %u " , Alarms [ i ] . Name . c_str ( ) , val , ( Alarms [ i ] . GT ? " < " : " > " ) , err ) ;
Alarms [ i ] . Activated = false ;
}
}
i + + ;
}
}
}
}
void setInformation ( const vector < string > & alarms , const vector < string > & graphupdate )
{
uint i ;
sint tmp ;
// add only commands that I understand
Alarms . clear ( ) ;
for ( i = 0 ; i < alarms . size ( ) ; i + = 3 )
{
CVarPath shardvarpath ( alarms [ i ] ) ;
if ( shardvarpath . Destination . size ( ) = = 0 | | shardvarpath . Destination [ 0 ] . second . empty ( ) )
continue ;
CVarPath servervarpath ( shardvarpath . Destination [ 0 ] . second ) ;
if ( servervarpath . Destination . size ( ) = = 0 | | servervarpath . Destination [ 0 ] . second . empty ( ) )
continue ;
CVarPath servicevarpath ( servervarpath . Destination [ 0 ] . second ) ;
if ( servicevarpath . Destination . size ( ) = = 0 | | servicevarpath . Destination [ 0 ] . second . empty ( ) )
continue ;
string name = servicevarpath . Destination [ 0 ] . second ;
if ( IService : : getInstance ( ) - > getServiceUnifiedName ( ) . find ( servicevarpath . Destination [ 0 ] . first ) ! = string : : npos & & ICommand : : exists ( name ) )
{
fromString ( alarms [ i + 1 ] , tmp ) ;
nlinfo ( " ADMIN: Adding alarm '%s' limit %d order %s (varpath '%s') " , name . c_str ( ) , tmp , alarms [ i + 2 ] . c_str ( ) , alarms [ i ] . c_str ( ) ) ;
Alarms . push_back ( CAlarm ( name , tmp , alarms [ i + 2 ] = = " gt " ) ) ;
}
else
{
if ( IService : : getInstance ( ) - > getServiceUnifiedName ( ) . find ( servicevarpath . Destination [ 0 ] . first ) = = string : : npos )
{
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 ( ) ) ;
}
else
{
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 ( ) ) ;
}
}
}
// do the same with graph update
GraphUpdates . clear ( ) ;
for ( i = 0 ; i < graphupdate . size ( ) ; i + = 2 )
{
CVarPath shardvarpath ( graphupdate [ i ] ) ;
if ( shardvarpath . Destination . size ( ) = = 0 | | shardvarpath . Destination [ 0 ] . second . empty ( ) )
continue ;
CVarPath servervarpath ( shardvarpath . Destination [ 0 ] . second ) ;
if ( servervarpath . Destination . size ( ) = = 0 | | servervarpath . Destination [ 0 ] . second . empty ( ) )
continue ;
CVarPath servicevarpath ( servervarpath . Destination [ 0 ] . second ) ;
if ( servicevarpath . Destination . size ( ) = = 0 | | servicevarpath . Destination [ 0 ] . second . empty ( ) )
continue ;
string VarName = servicevarpath . Destination [ 0 ] . second ;
string ServiceName = servicevarpath . Destination [ 0 ] . first ;
if ( ICommand : : exists ( VarName ) & & ( ServiceName = = " * " | | IService : : getInstance ( ) - > getServiceShortName ( ) = = ServiceName ) )
{
fromString ( graphupdate [ i + 1 ] , tmp ) ;
nlinfo ( " ADMIN: Adding graphupdate '%s' update %d (varpath '%s') " , VarName . c_str ( ) , tmp , graphupdate [ i ] . c_str ( ) ) ;
GraphUpdates . push_back ( CGraphUpdate ( VarName , tmp ) ) ;
}
else
{
if ( IService : : getInstance ( ) - > getServiceShortName ( ) ! = ServiceName )
{
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 ( ) ) ;
}
else
{
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 ( ) ) ;
}
}
}
}
//
// Commands
//
NLMISC_CATEGORISED_COMMAND ( nel , displayInformation , " displays all admin information " , " " )
{
nlunreferenced ( rawCommandString ) ;
nlunreferenced ( args ) ;
nlunreferenced ( quiet ) ;
nlunreferenced ( human ) ;
uint i ;
log . displayNL ( " There're %d alarms: " , Alarms . size ( ) ) ;
for ( i = 0 ; i < Alarms . size ( ) ; i + + )
{
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 " ) ) ;
}
log . displayNL ( " There're %d graphupdate: " , GraphUpdates . size ( ) ) ;
for ( i = 0 ; i < GraphUpdates . size ( ) ; i + + )
{
log . displayNL ( " %d %s %d %d " , i , GraphUpdates [ i ] . Name . c_str ( ) , GraphUpdates [ i ] . Update , GraphUpdates [ i ] . LastUpdate ) ;
}
return true ;
}
NLMISC_CATEGORISED_COMMAND ( nel , getView , " send a view and receive an array as result " , " <varpath> " )
{
nlunreferenced ( rawCommandString ) ;
nlunreferenced ( quiet ) ;
nlunreferenced ( human ) ;
if ( args . size ( ) ! = 1 ) return false ;
TAdminViewResult answer ;
serviceGetView ( 0 , args [ 0 ] , answer ) ;
log . displayNL ( " have %d answer " , answer . size ( ) ) ;
for ( uint i = 0 ; i < answer . size ( ) ; i + + )
{
log . displayNL ( " have %d value " , answer [ i ] . VarNames . size ( ) ) ;
nlassert ( answer [ i ] . VarNames . size ( ) = = answer [ i ] . Values . size ( ) ) ;
for ( uint j = 0 ; j < answer [ i ] . VarNames . size ( ) ; j + + )
{
log . displayNL ( " %s -> %s " , answer [ i ] . VarNames [ j ] . c_str ( ) , answer [ i ] . Values [ j ] . c_str ( ) ) ;
}
}
return true ;
}
} // NLNET