metal/mtce-common/cgts-mtce-common-1.0/hwmon/hwmonModel.cpp

546 lines
21 KiB
C++

/*
* Copyright (c) 2015-2017 Wind River Systems, Inc.
*
* SPDX-License-Identifier: Apache-2.0
*
*
*
* @file
* Wind River Titanium Cloud Hardware Monitor" Sensor Model" Utilities
*
*
* These are the utilities that load, create, group and delete sensor models
*
*
* ipmi_load_sensor_model ....... called by add_host_handler FSM
*
* ipmi_create_sensor_model
*
* ipmi_create_sample_model ... create model based on sample data
* ipmi_create_groups
* ipmi_create_sensors
* ipmi_group_sensors
*
* ipmi_create_quanta_model ... create model for Quanta server
* ipmi_add_group
* load_profile_groups
* load_profile_sensors
* hwmon_group_sensors
*
* ipmi_delete_sensor_model ..... called on model re-create
*
*****************************************************************************/
#include "daemon_ini.h" /* for ... parse_ini and MATCH */
#include "nodeBase.h" /* for ... mtce common definitions */
#include "jsonUtil.h" /* for ... json utilitiies */
#include "nodeUtil.h" /* for ... mtce common utilities */
#include "hwmonUtil.h" /* for ... get_severity */
#include "hwmonClass.h" /* for ... service class definition */
#include "hwmonHttp.h" /* for ... http podule header */
#include "hwmonSensor.h" /* for ... this module header */
#include "hwmonIpmi.h" /* for ... QUANTA_SENSOR_PROFILE_CHECKSUM */
/*****************************************************************************
*
* Name : ipmi_create_sensor_model
*
* Description: Top level utility that creates a sensor model based on
* sample data.
*
* The caller has already determined if the sample set matches
* the special case Quanta server model. If it does then we
* use the Quanta sensor profile to create the model. Otherwise,
* the model is created based on sensor samples.
*
******************************************************************************/
int hwmonHostClass::ipmi_create_sensor_model ( struct hwmonHostClass::hwmon_host * host_ptr )
{
int rc = PASS ;
ilog ("%s creating sensor model\n", host_ptr->hostname.c_str());
host_ptr->groups = 0 ;
/* If this is NOT a Quanta Server then ... */
if ( ! host_ptr->quanta_server )
{
/*
* Dynamically create a model based
* on the sensor sample reading data.
*/
rc = ipmi_create_sample_model ( host_ptr );
}
/* Otherwise create the model based on the known Quanta sensor profile */
else
{
if ( ( rc = ipmi_create_quanta_model ( host_ptr )) == PASS )
{
if ( host_ptr->groups >= MIN_SENSOR_GROUPS )
{
/*
* If this is a Quanta server then the best way to ensure the
* sensor profile is identical and backward compatible is to
* load the sensor profile from the legacy Quanta profile file.
*
* QUANTA_SENSOR_PROFILE_FILE
*/
struct sensor_group_type group_array [MAX_HOST_GROUPS] ;
sensor_type sensor_array [MAX_HOST_SENSORS];
int profile_groups ;
bool error = false ;
ilog ("%s provisioning Quanta server using %s\n",
host_ptr->hostname.c_str(), QUANTA_SENSOR_PROFILE_FILE );
profile_groups = load_profile_groups ( host_ptr, &group_array[0], MAX_HOST_GROUPS, error );
if (( error == false ) && ( profile_groups == host_ptr->groups ))
{
int profile_sensors;
for ( int g = 0 ; g < host_ptr->groups ; ++g )
{
/*
* Add the sensor label list to each host_ptr group[x].
*
* This list was fetched and attached to the group array
* in load_profile_groups.
*
* Having it prevents the need to parse the profile file
* again to associate the sensors to a group all over
* again inside load_profile_sensors
*/
host_ptr->group[g].sensor_labels = group_array[g].sensor_labels ;
blog ("%s '%s' group sensor list: %s\n",
host_ptr->hostname.c_str(),
host_ptr->group[g].group_name.c_str(),
host_ptr->group[g].sensor_labels.c_str());
}
ilog ( "%s %d profile groups loaded\n", host_ptr->hostname.c_str(), profile_groups );
profile_sensors = load_profile_sensors ( host_ptr, &sensor_array[0], MAX_HOST_SENSORS, error );
if (( error == false ) && ( profile_sensors ))
{
ilog ( "%s %d profile sensors loaded\n", host_ptr->hostname.c_str(), profile_sensors );
for ( int s = 0 ; s < profile_sensors ; ++s )
{
if (( rc = hwmonHttp_add_sensor ( host_ptr->hostname, host_ptr->event, sensor_array[s])) == PASS )
{
sensor_array[s].uuid = host_ptr->event.new_uuid ;
if (( rc = add_sensor ( host_ptr->hostname, sensor_array[s] )) == PASS )
{
blog ( "%s '%s' sensor added\n",
host_ptr->hostname.c_str(),
host_ptr->sensor[s].sensorname.c_str());
}
else
{
wlog ("%s '%s' sensor add failure (to hwmon)\n",
host_ptr->hostname.c_str(),
sensor_array[s].sensorname.c_str());
}
}
else
{
wlog ("%s '%s' sensor add failure (to sysinv)\n",
host_ptr->hostname.c_str(),
sensor_array[s].sensorname.c_str());
}
} /* end for loop */
}
else
{
elog ( "%s load_profile_sensors failed (rc:%d) (%d)\n",
host_ptr->hostname.c_str(),
error,
profile_sensors );
}
}
else
{
elog ( "%s load_profile_groups failed (rc:%d) (%d:%d)\n",
host_ptr->hostname.c_str(),
error,
profile_groups,
host_ptr->groups );
}
}
else
{
elog ("%s too few groups\n", host_ptr->hostname.c_str());
rc = FAIL_INVALID_DATA ;
}
}
else
{
elog ("%s failed to create group model (rc:%d)\n", host_ptr->hostname.c_str(), rc);
}
}
if (( rc == PASS ) && ( host_ptr->quanta_server))
{
/* Group all the sensors into the groups specified by the profile file */
rc = hwmonHostClass::hwmon_group_sensors ( host_ptr );
if ( rc == PASS )
{
ilog ("%s sensors grouped\n", host_ptr->hostname.c_str());
}
else
{
elog ("%s sensor grouping failed (rc:%d)\n", host_ptr->hostname.c_str(), rc );
}
plog ("%s sensor model created\n", host_ptr->hostname.c_str() );
}
if (( host_ptr->relearn == true ) ||
( host_ptr->interval < HWMON_MIN_AUDIT_INTERVAL ))
{
dlog ("%s requesting interval change (%d)\n",
host_ptr->hostname.c_str(),
host_ptr->interval );
host_ptr->interval_changed = true ;
}
/* make sure all sensors are updated with the group actions */
return (rc);
}
/******************************************************************************
*
* Name : ipmi_create_sample_model
*
* Description: Create a sensor model based on sample data.
*
******************************************************************************/
int hwmonHostClass::ipmi_create_sample_model ( struct hwmonHostClass::hwmon_host * host_ptr )
{
int rc = FAIL ;
if ( host_ptr->samples )
{
/* Start by creating a set of sensor groups based on sample data
* and specifically sensor type and save those groups in the database */
if ( ( rc = ipmi_create_groups ( host_ptr ) ) == PASS )
{
/* add all the sensors to hwmon and save that in the database */
if ( ( rc = ipmi_create_sensors ( host_ptr ) ) == PASS )
{
/* add the sensors to the groups and save that in the database */
rc = ipmi_group_sensors ( host_ptr );
}
}
}
else
{
rc = FAIL_NO_DATA ;
elog ("%s failed sensor sample model create ; no sensor samples\n", host_ptr->hostname.c_str() );
}
return(rc);
}
/******************************************************************************
*
* Name : ipmi_create_quanta_model
*
* Description: Create a static Quanta sever sensor group model.
*
******************************************************************************/
int hwmonHostClass::ipmi_create_quanta_model ( struct hwmonHostClass::hwmon_host * host_ptr )
{
int status = PASS ;
int rc = PASS ;
if ( host_ptr )
{
if ( host_ptr->quanta_server == true )
{
rc = ipmi_add_group ( host_ptr , DISCRETE, "fan" , HWMON_CANNED_GROUP__FANS, "server fans", "show /SYS/fan");
if (( rc ) && ( !status )) status = rc ;
rc = ipmi_add_group ( host_ptr , DISCRETE, "fan" , HWMON_CANNED_GROUP__FANS, "power supply fans", "show /SYS/fan");
if (( rc ) && ( !status )) status = rc ;
rc = ipmi_add_group ( host_ptr , DISCRETE, "power" , HWMON_CANNED_GROUP__POWER, "server power", "show /SYS/powerSupply");
if (( rc ) && ( !status )) status = rc ;
rc = ipmi_add_group ( host_ptr , DISCRETE, "temperature" , HWMON_CANNED_GROUP__TEMP, "server temperature", "show /SYS/temperature");
if (( rc ) && ( !status )) status = rc ;
rc = ipmi_add_group ( host_ptr , DISCRETE, "voltage" , HWMON_CANNED_GROUP__VOLT, "server voltage", "show /SYS/voltage");
if (( rc ) && ( !status )) status = rc ;
}
}
return (status);
}
int hwmonHostClass::ipmi_delete_sensor_model ( struct hwmonHostClass::hwmon_host * host_ptr )
{
int rc = PASS ;
if ( host_ptr->relearn_retry_counter == 0 )
{
ilog ("%s ... saving group customizations\n",
host_ptr->hostname.c_str());
this->save_model_attributes ( host_ptr );
ilog ("%s ... clearing existing assertions\n",
host_ptr->hostname.c_str());
this->clear_bm_assertions ( host_ptr );
ilog ("%s ... deleting sensor model\n",
host_ptr->hostname.c_str());
}
/* Delete the groups from the end to the start.
* If there is a failure then exit and the caller will retry.
*/
if ( host_ptr->groups )
{
for ( int g = host_ptr->groups-1 ;
host_ptr->groups != 0 ;
host_ptr->groups-- , g-- )
{
daemon_signal_hdlr ();
int rc_temp = hwmonHttp_del_group ( host_ptr->hostname,
host_ptr->event,
host_ptr->group[g] );
if ( rc_temp )
{
elog ("%s %s group delete failed (rc:%d) (%d)\n",
host_ptr->hostname.c_str(),
host_ptr->group[g].group_name.c_str(),
rc_temp, g );
host_ptr->relearn_retry_counter++ ;
return (rc_temp);
}
else
{
blog ("%s %s (index:%d)\n",
host_ptr->hostname.c_str(),
host_ptr->group[g].group_name.c_str(), g );
if ( host_ptr->group[g].timer.init == TIMER_INIT_SIGNATURE )
{
mtcTimer_reset ( host_ptr->group[g].timer );
}
hwmonGroup_init ( host_ptr->hostname, &host_ptr->group[g]);
}
}
}
/* Delete the sensors from the end to the start.
* If there is a failure then exit and the caller will retry.
*/
if ( host_ptr->sensors )
{
for ( int s = host_ptr->sensors-1 ;
host_ptr->sensors != 0 ;
host_ptr->sensors-- , s-- )
{
daemon_signal_hdlr ();
int rc_temp = hwmonHttp_del_sensor ( host_ptr->hostname,
host_ptr->event,
host_ptr->sensor[s] );
if ( rc_temp )
{
elog ("%s %s sensor delete failed (rc:%d) (%d)\n",
host_ptr->hostname.c_str(),
host_ptr->sensor[s].sensorname.c_str(),
rc_temp, s );
host_ptr->relearn_retry_counter++ ;
return (rc_temp);
}
else
{
blog ("%s %s (index:%d)\n",
host_ptr->hostname.c_str(),
host_ptr->sensor[s].sensorname.c_str(), s );
hwmonSensor_init ( host_ptr->hostname, &host_ptr->sensor[s]);
sensor_data_init ( host_ptr->sample[s] );
if ( host_ptr->sensors == 1 )
{
host_ptr->quanta_server = false ;
host_ptr->sensors =
host_ptr->samples =
host_ptr->profile_sensor_checksum =
host_ptr->sample_sensor_checksum =
host_ptr->last_sample_sensor_checksum = 0 ;
break ;
}
}
}
}
if (( host_ptr->sensors == 0 ) && ( host_ptr->groups == 0 ))
{
plog ("%s sensor model deleted\n", host_ptr->hostname.c_str() );
}
else
{
elog ("%s sensor model delete failed (%d:%d)\n",
host_ptr->hostname.c_str(),
host_ptr->groups,
host_ptr->sensors );
rc = FAIL ;
}
return (rc);
}
/* *************************************************************************
*
* Name : ipmi_load_sensor_model
*
* Description: Called from the add_handler to load sensors and groups
* for the specified host from the sysinv database.
*
* Warnings : Will return a failure and swerr if called when with an
* already loaded sensor profile.
*
* Assumptions: Inservice sensor model reprovisioning is done with
* ipmi_delete_sensor_model and ipmi_create_sensor_model API.
*
*
* Scope : private hwmonHostClass
*
* Parameters : host_ptr
*
* Returns : TODO: handle modify errors better.
*
* *************************************************************************/
int hwmonHostClass::ipmi_load_sensor_model ( struct hwmonHostClass::hwmon_host * host_ptr )
{
int rc ;
if (( host_ptr->sensors ) || ( host_ptr->groups ))
{
elog ("%s already has %d sensors across %d groups loaded - reloading\n",
host_ptr->hostname.c_str(),
host_ptr->sensors,
host_ptr->groups );
this->hwmon_del_sensors ( host_ptr );
this->hwmon_del_groups ( host_ptr );
rc = FAIL_INVALID_OPERATION ;
}
else
{
/* Load aleady provisioned sensors from the database
* into host_ptr->sensor list.
*
* Warning: This is a blocking call and always has been.
*/
rc = hwmonHttp_load_sensors ( host_ptr->hostname, host_ptr->event );
if ( rc == PASS )
{
daemon_signal_hdlr (); /* service the signals */
if ( host_ptr->sensors != 0 )
{
/* Load aleady provisioned groups from the database
* into host_ptr->group list */
rc = hwmonHttp_load_groups ( host_ptr->hostname, host_ptr->event );
if ( rc == PASS )
{
/* update sample severity to avoid state change
* from fail to ok to fail over a process restart */
for ( int s = 0 ; s < host_ptr->sensors ; s++ )
{
host_ptr->sensor[s].sample_severity = get_severity(host_ptr->sensor[s].status) ;
host_ptr->sensor[s].sample_status =
host_ptr->sensor[s].sample_status_last = host_ptr->sensor[s].status ;
}
rc = hwmonHostClass::hwmon_group_sensors ( host_ptr );
if ( rc == PASS )
{
blog ("%s sensors grouped\n", host_ptr->hostname.c_str());
}
else
{
wlog ("%s sensor grouping failed (in hwmon) (rc:%d)\n", host_ptr->hostname.c_str(), rc );
}
}
else
{
wlog ("%s sensor group load failed (from sysinv) (rc:%d)\n", host_ptr->hostname.c_str(), rc );
}
}
}
else
{
wlog ("%s sensors load failed (from sysinv) (rc:%d)\n", host_ptr->hostname.c_str(), rc );
}
}
if ( rc == PASS )
{
if (( host_ptr->sensors ) && ( host_ptr->groups ))
{
ilog ("%s has %d sensors across %d groups (in sysinv)\n",
host_ptr->hostname.c_str(),
host_ptr->sensors,
host_ptr->groups );
/* initialize sensor data */
for ( int i = 0 ; i < host_ptr->sensors ; ++i )
{
host_ptr->sensor[i].severity = get_severity ( host_ptr->sensor[i].status );
}
host_ptr->profile_sensor_checksum =
checksum_sensor_profile ( host_ptr->hostname,
host_ptr->sensors,
&host_ptr->sensor[0]);
ilog ("%s database profile checksum : %04x (%d sensors)\n",
host_ptr->hostname.c_str(),
host_ptr->profile_sensor_checksum,
host_ptr->sensors);
if ((( host_ptr->profile_sensor_checksum == QUANTA_SENSOR_PROFILE_CHECKSUM ) ||
( host_ptr->profile_sensor_checksum == QUANTA_SENSOR_PROFILE_CHECKSUM_13_53 )) &&
(( host_ptr->sensors == QUANTA_PROFILE_SENSORS ) || (QUANTA_PROFILE_SENSORS_REVISED_1)) &&
( host_ptr->groups == QUANTA_SENSOR_GROUPS ))
{
ilog ("%s ---------------------------------------------\n", host_ptr->hostname.c_str());
ilog ("%s is a Quanta server with legacy sensor profile\n", host_ptr->hostname.c_str());
ilog ("%s ---------------------------------------------\n", host_ptr->hostname.c_str());
host_ptr->quanta_server = true ;
}
else
{
ilog ("%s has unique sensor model\n", host_ptr->hostname.c_str());
}
}
else
{
/* Incomplete or no sensor/group model found in database */
ilog ("%s no valid sensor model found (in sysinv) (sensors:%d groups:%d)\n",
host_ptr->hostname.c_str(),
host_ptr->sensors,
host_ptr->groups );
if (( host_ptr->sensors ) || (host_ptr->groups ))
{
wlog ("%s has a corrupt sensor profile ; deleting ...\n", host_ptr->hostname.c_str());
ipmi_delete_sensor_model ( host_ptr );
}
}
}
return (rc);
}