// $Id: lemon_collector.html,v 1.1 2001/05/22 07:58:08 paudley Exp $
// Time-stamp: <00/01/26 16:55:00 paudley>
#include <stl.h>
#include "stringplus.h"
#include "SNMPplus.h"
#include "instant.h"
#include "sqlfile.h"
extern "C" {
# include <unistd.h>
# include <sys/wait.h>
}
sqlfile* lemonDB = NULL;
stringplus id;
string_map *config;
stringplus SA[128]; // For decomposing OID's
string_map *V; // x -> VLAN
string_map *vInt; // int -> VLAN
string_map *ifMap;
SNMPplus *S;
SNMPquery *Q;
map<stringplus,stringplus>::iterator iter;
//bool _init_ok;
bool _reset;
void _run_id( const stringplus& t_id );
bool maybe_update_ifmapping( void );
bool collect( void );
bool commit_temp_data( void );
bool _verify_connection( void );
bool _verify_connection2( sqlfile* );
void collect_interface( const stringplus& num );
int main()
{
cout << "Lemon v4.0" << endl;
cout << " .intializing db connection." << endl;
sqlfile *lemonDBmain = new sqlfile("localhost","3306","lemon","lemon","");
if( !_verify_connection2(lemonDBmain) ) {
cerr << "Can't connect to DB." << endl;
exit(1);
}
SNMPplus::init();
// for( int i = 0; i<10; i++ ) {
while( true ) {
time_t start_t = time(0);
// Pull our config from the db...
if( _verify_connection2(lemonDBmain) ) {
sqlres* id_res = lemonDBmain->sql("select id from config");
for(int i=0; i<id_res->numrows(); i++ ) {
string_map row = id_res->row_map();
// Fork because snmplib is leaky and broken
pid_t pid;
if( (pid = fork()) < 0 ) {
cerr << "Error forking..." << endl;
} else {
if( pid == 0 ) { // Child
_run_id( row["id"] );
cout << "Child exiting." << endl;
exit(0);
}
// Parent
long time_p = time(0);
cout << ctime(&time_p) << ": Waiting for child.." << endl;
waitpid( pid, NULL, 0 );
cout << "Child is done." << endl;
}
}
delete id_res;
}
// delete lemonDB;
// exit(0);
long diff = time(0) - start_t;
#define PERIOD 150
if( diff < PERIOD ) {
cout << "Sleeping for " << PERIOD - diff << "seconds..." << endl;
sleep( PERIOD - diff );
}
}
delete lemonDBmain;
return 0;
}
void _run_id( const stringplus& t_id ) {
S = new SNMPplus;
Q = new SNMPquery;
ifMap = new string_map;
vInt = new string_map;
V = new string_map;
config = new string_map;
lemonDB = new sqlfile("localhost","3306","lemon","lemon","");
if( !_verify_connection() ) {
cerr << "Can't connect to DB." << endl;
exit(1);
}
id = t_id;
sqlres* conf_res = lemonDB->sql("select * from config where id = '%s'",id.AsPtr());
*config = conf_res->row_map(); delete conf_res;
if( config->size() < 1 ) {
cerr << " .LC::_run No config found for id:" << id.AsPtr() << endl;
goto cleanup;
}
S->open((*config)["host"],(*config)["community"]);
if( !S->good() ) {
cerr << S->error() << endl;
goto cleanup;
}
cout << " .LC::Starting collection run..." << endl;
if( !maybe_update_ifmapping() ) goto cleanup;
if( !collect() )
goto cleanup;
cleanup:
S->close();
delete lemonDB;
delete S;
delete Q;
delete ifMap;
delete vInt;
delete V;
delete config;
}
bool maybe_update_ifmapping( void ) {
Q->add_req(".1.3.6.1.2.1.1.3.0");
S->get( Q );
if( Q->results.size() != 1 )
return false;
iter = Q->results.begin();
bool update = false;
// This is how long the router tells us it's been up..
long uptime = (*iter).second.Field(2,"()").AsLong();
long last_uptime = 0L;
Q->clear();
// Grab the last uptime we checked.
sqlres* res = lemonDB->sql("select val_i from system where name = '%s' and var = 'uptime'",(*config)["host"].AsPtr());
string_map ret = res->row_map(); delete res;
if( ret.size() < 1 ) {
// We don't have a previous value, force the update and insert the current uptime.
update = true;
_reset = true;
lemonDB->sqlV("insert into system values ('%s','uptime',%ld,'')",(*config)["host"].AsPtr(),uptime);
} else
last_uptime = ret["val_i"].AsLong();
// Update the uptime...
lemonDB->sqlV("update system set val_i = %ld where name = '%s' and var = 'uptime'",uptime,(*config)["host"].AsPtr());
// Detect probable resets.
if( !update && uptime < last_uptime ) { update = true; _reset = true; }
// Detect ten minute intervals.
if( !update && uptime > (last_uptime+600)) { update = true; }
// Detect DB problems..
unsigned long n = 0;
if( (n=lemonDB->sqlN("select * from ifmapping where id = '%s' and name != ''",id.AsPtr())) < 1 ) update = true;
if( lemonDB->sqlN("select * from ifmapping where id = '%s' and temp != ''",id.AsPtr()) > 0 ) update = true;
if( n != ifMap->size() ) update = true;
update = true;
if( update ) {
V->clear();
vInt->clear();
// Nuke the old mappings...
lemonDB->sqlV("delete from ifmapping where id = '%s'",id.AsPtr());
ifMap->clear();
// Get the x -> VLAN mappings
for( int r=1; r<=(*config)["max_vlans"].AsLong(); r++ ) {
Q->add_req(stringplus(".1.3.6.1.4.1.353.5.3.1.1.2.1.14.")+r); // This is the table of x to vlan names.
}
S->get( Q );
for( iter=Q->results.begin();iter != Q->results.end(); iter++ ) {
int oid_n = (*iter).first.Split(SA,128,'.'); // Decompose the OID.
(*V)[ SA[ oid_n - 1 ] ] = (*iter).second;
}
Q->clear();
// Get the x -> Interface mappings
for( int r=1; r<=(*config)["max_vlans"].AsLong(); r++ )
Q->add_req(stringplus(".1.3.6.1.4.1.353.5.3.1.1.2.1.1.")+r); // This is the table of x to iterface numbers.
S->get( Q );
for( iter=Q->results.begin();iter != Q->results.end(); iter++ ) {
int oid_n = (*iter).first.Split(SA,128,'.'); // Decompose the OID.
// Remap the VLAN -> Interfaces.
(*vInt)[(*iter).second ] = (*V)[ SA[ oid_n - 1 ] ];
}
Q->clear();
// Add the new mappings to the master ifMap
for( iter=vInt->begin(); iter!=vInt->end(); iter++ )
(*ifMap)[ (*iter).first ] = (*iter).second;
// OK, get the real interface names..
for( int r=1; r<=(*config)["max_intf"].AsLong(); r++ )
Q->add_req(stringplus(".1.3.6.1.4.1.9.2.2.1.1.28.")+r);
S->get( Q );
for( iter=Q->results.begin();iter != Q->results.end(); iter++ ) {
int oid_n = (*iter).first.Split(SA,128,'.'); // Decompose the OID.
(*vInt)[ SA[ oid_n - 1 ] ] = (*iter).second;
}
Q->clear();
// Add the new mappings to the master ifMap (if they have a name..)
for( iter=vInt->begin(); iter!=vInt->end(); iter++ )
if( (*iter).second != "" && (*iter).first != "" )
{
(*iter).second.Replace("'","");
(*ifMap)[ (*iter).first ] = (*iter).second;
}
}
// Dump mappings to db.
for( iter=ifMap->begin(); iter!=ifMap->end(); iter++ ) {
lemonDB->sqlV("insert into ifmapping (id,name,val,temp) values ('%s','%s',%s,'')",
id.AsPtr(), (*iter).second.AsPtr(), (*iter).first.AsPtr() );
}
return true;
}
bool collect( void ) {
// Check for uncommitted temp data...
// if( !commit_temp_data() ) return false;
// Wipe the current temp db.
if( !_verify_connection() ) { return false; }
lemonDB->sqlV("delete from temp_data where id = '%s'",id.AsPtr());
for( iter=ifMap->begin(); iter!=ifMap->end(); iter++ )
collect_interface( iter->first );
// Toggle reset if it's set.
if( _reset )
_reset = false;
// Commit
if( !commit_temp_data() ) return false;
return true;
}
bool commit_temp_data( void ) {
if( !_verify_connection() ) { return false; }
// Check for any temp_data...
if( lemonDB->sqlN("select id from temp_data where id = '%s'",id.AsPtr()) < 1 ) {
cerr << "UhOh. There is no temp data for "<<id<<endl;
return false;
}
// Push the data into the raw_data table..
long n = ifMap->size();
lemonDB->sqlV("update temp_data set level = -1 where id = '%s'",id.AsPtr());
long tnum = lemonDB->sqlN("select level from temp_data where id = '%s' and level = -1",id.AsPtr());
cerr << "data for " << tnum << " interfaces found." << endl;
if( tnum != n ) {
for( iter=ifMap->begin(); iter!=ifMap->end(); iter++ ) {
if( lemonDB->sqlN("select * from temp_data where id = '%s' and name = '%s'",
id.AsPtr(), (*iter).second.AsPtr() ) != 1 ) {
cout << "!! Error !! Missing info for: " << id << ":" << (*iter).second << endl;
}
}
}
lemonDB->sqlV("replace into raw_data (id,ts,inOct,outOct,avgInRate,avgOutRate,name,reset) select id,ts,inOct,outOct,avgInRate,avgOutRate,name,reset from temp_data where id = '%s'",id.AsPtr());
// tnum = lemonDB->sqlN("select level from raw_data where id = '%s' and level = -1",id.AsPtr());
// if( tnum < n ) {
// cerr << "!!! temp_data to raw_data mismatch in LemonCollect::collect()" << endl;
// cerr << " interfaces: " << n << endl;
// cerr << " raw data exists for " << tnum << " interfaces for last run." <<endl << endl;
// for( iter=ifMap.begin(); iter!=ifMap.end(); iter++ ) {
// if( lemonDB->sqlN("select * from temp_data where id = '%s' and name = '%s'",
// id.AsPtr(), (*iter).second.AsPtr() ) != 1 ) {
// cout << "!! Error !! Missing info for: " << id << ":" << (*iter).second << endl;
// }
// }
// } else {
//lemonDB->sqlV("update raw_data set level = 0 where id = '%s' and level = -1",id.AsPtr());
lemonDB->sqlV("delete from temp_data where id = '%s'",id.AsPtr());
// }
return true;
}
#define LC_inOct ".1.3.6.1.2.1.2.2.1.10."
#define LC_outOct ".1.3.6.1.2.1.2.2.1.16."
#define LC_avgInRate ".1.3.6.1.4.1.9.2.2.1.6."
#define LC_avgOutRate ".1.3.6.1.4.1.9.2.2.1.8."
void collect_interface( const stringplus& num ) {
if( !_verify_connection() ) { return; }
if( num.AsLong() <= 0 ) return;
stringplus name = (*ifMap)[ num ],SinOct,SoutOct,SavgInRate,SavgOutRate;
Q->clear();
{ Q->add_req(stringplus( LC_inOct )+num.AsPtr()); S->get(Q); SinOct = (*(Q->results.begin())).second; Q->clear();}
{ Q->add_req(stringplus( LC_outOct )+num.AsPtr()); S->get(Q); SoutOct = (*(Q->results.begin())).second; Q->clear();}
// { Q=new SNMPquery; Q->add_req(stringplus( LC_avgInRate )+num.AsPtr()); S->get(&Q); SavgInRate = (*(Q.results.begin())).second; }
// { Q=new SNMPquery; Q->add_req(stringplus( LC_avgOutRate )+num.AsPtr()); S->get(&Q); SavgOutRate = (*(Q.results.begin())).second; }
if( SinOct == "" ) SinOct = "0";
if( SoutOct == "" ) SoutOct = "0";
if( SavgInRate == "" ) SavgInRate = "0";
if( SavgOutRate == "" ) SavgOutRate = "0";
lemonDB->sqlV("delete from temp_data where id = '%s' and name = '%s'",id.AsPtr(),name.AsPtr());
cout << "[id:"<<id<<"] [name:"<<name<<"] "<<SinOct<<" "<<SoutOct<<endl;
lemonDB->sqlV("insert into temp_data (id,name,ts,inOct,outOct,avgInRate,avgOutRate,reset) values ('%s','%s',now(),%s,%s,%s,%s,%ld)",
id.AsPtr(),name.AsPtr(),
SinOct.AsPtr(),
SoutOct.AsPtr(),
SavgInRate.AsPtr(),
SavgOutRate.AsPtr(),
_reset ? 1 : 0);
}
bool _verify_connection( void ) {
if( !lemonDB ) lemonDB = new sqlfile("localhost","3306","lemon","lemon","");
if( !lemonDB->isok() ) {
delete lemonDB;
lemonDB = new sqlfile("localhost","3306","lemon","lemon","");
}
return lemonDB->isok();
}
bool _verify_connection2( sqlfile* S ) {
if( !S ) S = new sqlfile("localhost","3306","lemon","lemon","");
if( !S->isok() ) {
delete S;
S = new sqlfile("localhost","3306","lemon","lemon","");
}
return S->isok();
}
syntax highlighted by Code2HTML, v. 0.9