/* * Copyright (c) 2015 Wind River Systems, Inc. * * SPDX-License-Identifier: Apache-2.0 * */ /** * @file * Wind River CGTS Platform PostgreSQL Database Access Utility module. **/ #include "pgdbClass.h" #include "jsonUtil.h" #define CONF_FILE ((const char *)("/etc/ceilometer/ceilometer.conf")) /* Cleanup exit handler */ void daemon_exit ( void ) { exit (0); } void daemon_sigchld_hdlr ( void ) { dlog("Received SIGCHLD ...\n"); } static daemon_config_type _config ; static opts_type * opts_ptr ; /* Ceilometer config read */ int _config_handler ( void * user, const char * section, const char * name, const char * value) { daemon_config_type* config_ptr = (daemon_config_type*)user; if (MATCH("database", "connection")) { config_ptr->ceilometer_url = strdup(value); if ( config_ptr->ceilometer_url ) { ilog ("Ceilometer URL: %s\n", config_ptr->ceilometer_url ); } } return (PASS); } daemon_config_type * daemon_get_cfg_ptr (void) { return (&_config); } int daemon_configure ( void ) { int rc = PASS ; opts_ptr = daemon_get_opts_ptr(); daemon_files_init (); ilog("Config File : %s\n", CONF_FILE ); if (ini_parse ( CONF_FILE, _config_handler, &_config ) < 0) { elog("Failed to load '%s'\n", CONF_FILE ); } return (rc) ; } int daemon_init ( string iface , string nodetype ) { UNUSED(iface); UNUSED(nodetype); daemon_configure (); // get_debug_options ( CONF_FILE, &_config ); return (PASS); } pgdbClass dbConn ; #define EXACT_MATCH (0) #define POSITION_ZERO (0) /************************************************************************************ * * Ceilometer Database: Sensor Value Correlation * * 1. The METER table lists valid meter_ids * - hardware.ipmi.* * * 2. The RESOURCE table lists all the sensors based on internal id * - hostname-{sensor number-}_ * ... nokia-2-temp_psu2_(0x94) * ... controller-1-37-system_board_(0x33) * * 3. The SAMPLE table lists sample data as volume based on specified unit type * - sensor resource lookup * ... SAMPLE:resource_id == RESOURCE:internal_id * - SAMPLE:meter_id is used to know it is a valid meter to monitor * ... METER:id is valid if METER:name has hardware.ipmi in it * ... hardware.ipmi.current * **************************************************************************************/ /* Valid meter ids */ #define PQ_TABLE_INDEX__METER_ID (0) #define PQ_TABLE_INDEX__METER_NAME (1) #define PQ_TABLE_INDEX__METER_TYPE (2) #define PQ_TABLE_INDEX__METER_UNIT (3) #define VALID_METER_PREFIX ((const char *)("hardware.ipmi.")) typedef struct { int id ; string scope; /* ipmi - VALID_METER_PREFIX */ string name ; string unit ; string type ; } hwmon_meter_type ; std::map global_meter_list ; #define PQ_TABLE_INDEX__RESOURCE__INTERNAL_ID (0) #define PQ_TABLE_INDEX__RESOURCE__RESOURCE_ID (1) #define PQ_TABLE_INDEX__RESOURCE__METADATA (2) typedef struct { int id ; string hostname ; string sensorname ; string somevalue ; } hwmon_resource_type ; std::map global_sensor_list ; std::map excluded_resource_list ; // mtc_key_value_type ipmi_sensor_group void daemon_service_run ( void ) { int rc = PASS ; pgdbUtil_get_version (); if ( ! _config.ceilometer_url ) { rc = FAIL_NULL_POINTER ; } else { PGresult * pqResult_ptr ; string pqCommand_str; ilog ("URI:%s\n", _config.ceilometer_url ); // check_connection: for ( ; ; ) { if ( dbConn.pg.connected == false ) { elog ("not connected\n"); sleep (2); dbConn.connect ( _config.ceilometer_url ); continue ; // goto check_connection ; } else if ( dbConn.monitor() != PASS ) { sleep (2); continue ; } global_meter_list.clear(); // ilog ("max number of meters allowed: %zu\n", global_meter_list.max_size()); /* PARSE METER - hwmon_get_ipmi_sensor_meters () ; */ pqCommand_str = "SELECT * FROM meter" ; pqResult_ptr = PQexec ( dbConn.pg.conn, pqCommand_str.data()); // +----+-------------------------------------+------------+--------- // | id | name | type | unit // +----+-------------------------------------+------------+--------- // | 1 | hardware.ipmi.current | gauge | W // | 2 | hardware.ipmi.temperature | gauge | C // | 3 | hardware.ipmi.fan | gauge | percent if ( PQresultStatus( pqResult_ptr ) == PGRES_TUPLES_OK) { hwmon_meter_type meter ; meter.scope = VALID_METER_PREFIX ; int rows = PQntuples(pqResult_ptr); for(int i=0; i sizeof(int)) ) { meter.id = atoi(meter_id.data()); global_meter_list.insert (std::make_pair(meter.id, meter )); dlog3 ("ipmi sensor group %d '%s' (%s:%s)\n", meter.id, meter.name.c_str(), meter.type.c_str(), meter.unit.c_str()); } } } } /* end 'meters rows parse' for loop */ if ( global_meter_list.size() ) { // ************** Testing ********************* #define WANT_QUERY_AUTO_ITERATOR_TEST #ifdef WANT_QUERY_DECLARED_ITERATOR_TEST /* TEST: Query Meters using declared iterator */ std::map::const_iterator global_meter_list_iter = global_meter_list.begin(); while ( global_meter_list_iter != global_meter_list.end() ) { ilog ("ipmi sensor group %d '%s' (%s:%s)\n", global_meter_list_iter->second.id, global_meter_list_iter->second.name.c_str(), global_meter_list_iter->second.type.c_str(), global_meter_list_iter->second.unit.c_str()); ++global_meter_list_iter ; } #endif #ifdef WANT_QUERY_AUTO_ITERATOR_TEST /* TEST: Loop Over meter List using C++11 auto iterator */ for ( auto _iter = global_meter_list.begin() ; _iter != global_meter_list.end() ; _iter++ ) { dlog ("ipmi sensor group %d '%s' (%s:%s)\n", _iter->second.id, _iter->second.name.c_str(), _iter->second.type.c_str(), _iter->second.unit.c_str()); } #endif #ifdef WANT_FIND_TEST /* TEST: Find meters test */ for ( int i = 0 ; i < 1000 ; i++ ) { global_meter_list_iter = global_meter_list.find(i); if ( global_meter_list_iter != global_meter_list.end() ) { ilog ("ipmi sensor group query test - %d:%d '%s' (%s:%s)\n", i, global_meter_list_iter->second.id, global_meter_list_iter->second.name.c_str(), global_meter_list_iter->second.type.c_str(), global_meter_list_iter->second.unit.c_str()); } } #endif ilog ( "%zu sensor groups total\n", global_meter_list.size() ); /* PARSE RESOURCE - hwmon_get_ipmi_sensor_list () ; */ pqCommand_str = "SELECT internal_id,resource_id,resource_metadata FROM resource" ; pqResult_ptr = PQexec ( dbConn.pg.conn, pqCommand_str.data()); // +-------------+--------------------------------------+-----------------------------+ // | internal_id | resource_id | resource_metadata // | 1 | controller-0-power_meter_(0x40) | {"node": "controller-0"} // | 2 | controller-0-26-ilo_zone_(0x26) | {"node": "controller-0"} // | 3 | controller-0-fan_2_(0x7) | {"node": "controller-0"} if ( PQresultStatus( pqResult_ptr ) == PGRES_TUPLES_OK) { hwmon_resource_type resource ; int rows = PQntuples(pqResult_ptr); for(int i=0; i sizeof(int)) ) { resource.id = atoi(internal_id.data()); } else { elog ("failed to convert internal_id:%s to integer ; excluded '%s'\n", internal_id.c_str(), resource_id.c_str()); continue ; } /* Add those that have a valid hostname as metadata key:value pair { node: "" } */ if ( metadata.size() && ( jsonUtil_get_key_val ( (char*)metadata.data(), "node", hostname ) == PASS )) { resource.hostname = hostname ; if ( resource_id.find (hostname, POSITION_ZERO ) == POSITION_ZERO ) { /* Get somevalue */ resource.somevalue.clear(); resource.sensorname = resource_id.substr ( hostname.length()); size_t index = resource.sensorname.find ("_(0x"); if ( index != std::string::npos ) { resource.somevalue = resource.sensorname.substr (index+1); } resource.sensorname = resource_id.substr ( hostname.length()+1, index-1 ); global_sensor_list.insert (std::make_pair(resource.id, resource )); added = true ; dlog ("added - %s %s\n", hostname.c_str(), resource.sensorname.c_str()); } } else { elog ("no valid metadata node:hostname key value pair (%s) ; excluded %s\n", metadata.c_str(), resource_id.c_str() ); } if ( added == false ) { resource.hostname = "none" ; resource.sensorname = resource_id ; resource.somevalue = metadata ; excluded_resource_list.insert(std::make_pair(resource.id, resource )); } } /* end 'resource rows parse' for loop */ } if ( global_sensor_list.size() ) { /* Loop over meter List using C++11 auto iterator */ for ( auto _iter = global_sensor_list.begin() ; _iter != global_sensor_list.end() ; _iter++ ) { dlog ("%s %d sensor '%s' %s\n", _iter->second.hostname.c_str(), _iter->second.id, _iter->second.sensorname.c_str(), _iter->second.somevalue.c_str()); } } #ifdef WANT_DISPLAY_EXCLUDED_METERS_LIST if ( excluded_resource_list.size() ) { /* Loop over meter List using C++11 auto iterator */ for ( auto _iter = excluded_resource_list.begin() ; _iter != excluded_resource_list.end() ; _iter++ ) { ilog ("excluded %d '%s' (%s)\n", _iter->second.id, _iter->second.sensorname.c_str(), _iter->second.somevalue.c_str()); } } #endif ilog ("%zu sensors ; system wide and %zu meter resources excluded\n", global_sensor_list.size(), excluded_resource_list.size()); /* SELECT id,volume,timestamp,meter_id,resource_id FROM sample WHERE timestamp >= '2016-11-22 21:57:45' AND resource_id = 149; */ /* PARSE RESOURCE - hwmon_get_ipmi_sensor_list () ; pqCommand_str = "SELECT internal_id,resource_id,resource_metadata FROM resource" ; pqResult_ptr = PQexec ( dbConn.pg.conn, pqCommand_str.data()); */ // +-------------+--------------------------------------+-----------------------------+ // | internal_id | resource_id | resource_metadata // | 1 | controller-0-power_meter_(0x40) | {"node": "controller-0"} // | 2 | controller-0-26-ilo_zone_(0x26) | {"node": "controller-0"} // | 3 | controller-0-fan_2_(0x7) | {"node": "controller-0"} //if ( PQresultStatus( pqResult_ptr ) == PGRES_TUPLES_OK) //{ // Query all samples based on the last // - keep track of sample ID numbers to discard already managed samples // for each host // for each sensor } else { elog ("no data retrieved for command '%s'\n", pqCommand_str.c_str()); } PQclear (pqResult_ptr); /* TODO: Group these 2 commands into an _fini proc */ //PQfinish(dbConn.pg.conn); //dbConn.pg.conn = NULL ; } } } ilog ("RC:%d\n", rc ); } /* STUBS */ /* Push daemon state to log file */ void daemon_dump_info ( void ) { daemon_dump_membuf_banner (); daemon_dump_membuf(); } int daemon_run_testhead ( void ) { return PASS ; } const char * dummy = "empty" ; const char * daemon_stream_info ( void ) { return (dummy) ; }