Add new FM API methods

New API methods have been added to allow getting,
setting, and clearing faults by providing both
alarm_id and entity_instance_id.

Changes in this commit:
- For clear_fault operation, the query has been updated
to allow the removal of multiple rows with a single
query. The entity_instance_id parameter can now be a
prefix, enabling the matching of multiple alarms with
the same alarm_id.
This change does not affect existing use cases.

- New method get_faults_by_id_n_eid, This method allows
API clients to retrieve a list of alarms that match an
alarm_id and a prefix of entity_instance_id, thereby
matching multiple alarms.

- New method set_faults. This method accepts a list of
alarms as a parameter and calls the same core set_fault
function for each alarm.

[PASS] Build and install packages
[PASS] Remove several alarms that matches 'alarm_id',
       'entity_instance_id=%'
[PASS] Get list of alarms that match 'alarm_id' and
       'entity_instance_id=%'
[PASS] Verify that the new behavior for removing alarms
       does not affect previous use cases.
[PASS] Test set_faults API function providing a list
       of alarms. Verify the alarms in the list are
       being created.
[PASS] Enable debug mode to verify that queries are as
       expected.

Story: 2011106
task: 50756

Change-Id: Ib9dcfa97960a5d50865133a61810681e5a09edbe
Signed-off-by: fperez <fabrizio.perez@windriver.com>
This commit is contained in:
fperez 2024-08-02 16:58:08 -03:00
parent 05f5d63de9
commit 625e253b7c
11 changed files with 547 additions and 72 deletions

View File

@ -1,5 +1,5 @@
# #
# Copyright (c) 2013-2018 Wind River Systems, Inc. # Copyright (c) 2013-2024 Wind River Systems, Inc.
# #
# SPDX-License-Identifier: Apache-2.0 # SPDX-License-Identifier: Apache-2.0
# #
@ -185,6 +185,19 @@ class FaultAPIs(FaultAPIsBase):
except (RuntimeError, SystemError, TypeError): except (RuntimeError, SystemError, TypeError):
return None return None
def set_faults(self, data):
buff_list = []
with fm_api_lock:
for alarm_data in data:
self._check_required_attributes(alarm_data)
self._validate_attributes(alarm_data)
buff = self._alarm_to_str(alarm_data)
buff_list.append(buff)
try:
return fm_core.set_fault_list(buff_list)
except (RuntimeError, SystemError, TypeError):
return None
def clear_fault(self, alarm_id, entity_instance_id): def clear_fault(self, alarm_id, entity_instance_id):
with fm_api_lock: with fm_api_lock:
sep = constants.FM_CLIENT_STR_SEP sep = constants.FM_CLIENT_STR_SEP
@ -244,6 +257,22 @@ class FaultAPIs(FaultAPIsBase):
pass pass
return None return None
def get_faults_by_id_n_eid(self, alarm_id, entity_instance_id):
with fm_api_lock:
sep = constants.FM_CLIENT_STR_SEP
buff = (sep + self._check_val(alarm_id) + sep +
self._check_val(entity_instance_id) + sep)
try:
resp = fm_core.get_by_id_n_eid(buff)
if resp:
data = []
for i in resp:
data.append(self._str_to_alarm(i))
return data
except (RuntimeError, SystemError, TypeError):
pass
return None
def get_faults_by_id(self, alarm_id): def get_faults_by_id(self, alarm_id):
with fm_api_lock: with fm_api_lock:
try: try:

View File

@ -81,6 +81,17 @@ def get_all(instance_id):
print("No alarm returned") print("No alarm returned")
def get_all_by_id_n_eid(alarm_id, instance_id):
ll = ser.get_faults_by_id_n_eid(alarm_id, instance_id)
if ll is not None:
print("Total alarm returned: %d\n"
% len(ll))
for i in ll:
print_alarm(i)
else:
print("No alarm returned")
def get_list(alarm_id): def get_list(alarm_id):
ll = ser.get_faults_by_id(alarm_id) ll = ser.get_faults_by_id(alarm_id)
if ll is not None: if ll is not None:
@ -105,3 +116,5 @@ if __name__ == "__main__":
sys.exit(del_all(sys.argv[2])) sys.exit(del_all(sys.argv[2]))
elif sys.argv[1] == "get_list": elif sys.argv[1] == "get_list":
sys.exit(get_list(sys.argv[2])) sys.exit(get_list(sys.argv[2]))
elif sys.argv[1] == "get_list_id_eid":
sys.exit(get_all_by_id_n_eid(sys.argv[2], sys.argv[3]))

View File

@ -1,5 +1,5 @@
// //
// Copyright (c) 2017,2023 Wind River Systems, Inc. // Copyright (c) 2017,2024 Wind River Systems, Inc.
// //
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
// //
@ -287,7 +287,24 @@ EFmErrorT fm_set_fault(const SFmAlarmDataT *alarm,
return FM_ERR_OK; return FM_ERR_OK;
} }
/**
* Clears fault entries based on the specified filter.
*
* This function sends a request to the FM server which performs the
* query for the clear_fault operation.
* In addition, this allows the removal of multiple rows with a single query.
*
* **Parameters:**
* - `filter`: A pointer to an `AlarmFilter` structure. This includes `alarm_id`
* and `entity_instance_id`.
*
* **Returns:**
* - `FM_ERR_OK` if the operation was successful.
* - `FM_ERR_NOCONNECT` if the function failed to connect to the server or if the
* connection was lost during the operation.
* - Other error codes as defined in the `EFmErrorT` enumeration if the operation
* encountered other issues.
*/
EFmErrorT fm_clear_fault(AlarmFilter *filter) { EFmErrorT fm_clear_fault(AlarmFilter *filter) {
CFmMutexGuard m(getAPIMutex()); CFmMutexGuard m(getAPIMutex());
@ -479,6 +496,90 @@ EFmErrorT fm_get_faults_by_id(fm_alarm_id *alarm_id,
return FM_ERR_OK; return FM_ERR_OK;
} }
/**
* Retrieves alarms based on a filter with alarm_id and
* entity_instance_id.
*
* This function sends a request to the FM server to retrieve faults
* information matching the given filter criteria.
* The entity_instance_id parameter can now be a prefix (not complete),
* enabling the matching of multiple alarms with the same alarm_id
*
* **Parameters:**
* - `filter`: A pointer to an `AlarmFilter` structure. This includes `alarm_id`
* and `entity_instance_id`.
* - `alarm`: A pointer to an array of `SFmAlarmDataT` structures where
* the retrieved alarms will be stored.
* - `max_alarms_to_get`: On input, specifies the maximum number of alarms
* to retrieve. On output, specifies the number of alarms actually retrieved.
*
* **Returns:**
* An error code indicating the result of the operation. Possible values include:
* - `FM_ERR_OK`: Operation was successful.
* - `FM_ERR_NOCONNECT`: Failed to connect to the FM core.
* - Other error codes as defined in the `EFmErrorT` enumeration.
*/
EFmErrorT fm_get_faults_by_id_n_eid(AlarmFilter *filter,
SFmAlarmDataT *alarm,
unsigned int *max_alarms_to_get) {
CFmMutexGuard m(getAPIMutex());
if (!fm_lib_reconnect()) return FM_ERR_NOCONNECT;
fm_check_thread_pending_request();
fm_buff_t buff;
buff.clear();
EFmErrorT erc = fm_msg_utils_prep_requet_msg(buff, EFmGetFaultsByIdnEid,
filter,sizeof(*filter));
if (erc!=FM_ERR_OK) return erc;
// if it was not correctly sent by the API, set to the expected value
if (*max_alarms_to_get == 0){
*max_alarms_to_get = DEF_MAX_ALARMS;
}
if (m_client.write_packet(buff)) {
if (!m_client.read_packet(buff)) {
m_connected = false;
return FM_ERR_NOCONNECT;
}
if (ptr_to_hdr(buff)->msg_rc != FM_ERR_OK){
*max_alarms_to_get = 0;
EFmErrorT rc = (EFmErrorT)ptr_to_hdr(buff)->msg_rc;
return rc;
}
uint32_t pkt_size = ptr_to_hdr(buff)->msg_size;
if (pkt_size < sizeof(uint32_t)) {
FM_ERROR_LOG("Received invalid pkt size: %u\n",pkt_size );
m_connected = false;
return FM_ERR_COMMUNICATIONS;
}
// Decrement pkt_size by the size of the length field in the header
// to get the size of the actual alarm data
pkt_size-=sizeof(uint32_t);
char *dptr = (char*)ptr_to_data(buff);
uint32_t *len = (uint32_t*)dptr;
dptr+=sizeof(uint32_t);
if (*max_alarms_to_get < *len) {
return FM_ERR_NOT_ENOUGH_SPACE;
}
if (pkt_size < (*len*sizeof(SFmAlarmDataT)) ) {
return FM_ERR_COMMUNICATIONS;
}
*max_alarms_to_get = *len;
memcpy(alarm,dptr,pkt_size);
} else {
m_connected = false;
return FM_ERR_NOCONNECT;
}
return FM_ERR_OK;
}
/* /*
* APIs that enqueue the request and return ok for acknowledgment. * APIs that enqueue the request and return ok for acknowledgment.

View File

@ -1,5 +1,5 @@
// //
// Copyright (c) 2017 Wind River Systems, Inc. // Copyright (c) 2024 Wind River Systems, Inc.
// //
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
// //
@ -27,6 +27,8 @@ typedef unsigned char FMBoolTypeT;
#define FM_FALSE 0 #define FM_FALSE 0
static const size_t DEF_MAX_ALARMS (1000);
typedef enum{ typedef enum{
FM_ALARM_STATE_CLEAR = 0, FM_ALARM_STATE_CLEAR = 0,
FM_ALARM_STATE_SET = 1, FM_ALARM_STATE_SET = 1,
@ -204,6 +206,10 @@ EFmErrorT fm_get_faults(fm_ent_inst_t *inst_id, SFmAlarmDataT *alarm,
EFmErrorT fm_get_faults_by_id(fm_alarm_id *alarm_id, SFmAlarmDataT *alarm, EFmErrorT fm_get_faults_by_id(fm_alarm_id *alarm_id, SFmAlarmDataT *alarm,
unsigned int *max_alarms_to_get); unsigned int *max_alarms_to_get);
EFmErrorT fm_get_faults_by_id_n_eid(AlarmFilter *filter,
SFmAlarmDataT *alarm,
unsigned int *max_alarms_to_get);
/* /*
* APIs that enqueue the request and return ok for acknowledgment. * APIs that enqueue the request and return ok for acknowledgment.

View File

@ -1,5 +1,5 @@
// //
// Copyright (c) 2014-2018 Wind River Systems, Inc. // Copyright (c) 2014-2024 Wind River Systems, Inc.
// //
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
// //
@ -250,16 +250,85 @@ bool CFmDbAlarmOperation::get_alarm(CFmDBSession &sess, AlarmFilter &af, fm_db_r
return true; return true;
} }
bool CFmDbAlarmOperation::get_alarms(CFmDBSession &sess,const char *id, fm_db_result_t & alarms) { /** Function similar to 'get_alarm', the only difference is that this could match
std::string sql; * several rows, since this is using the LIKE % clause.
*/
bool CFmDbAlarmOperation::get_alarms_eid_not_strict(CFmDBSession &sess, AlarmFilter &af, fm_db_result_t & alarms) {
std::string sql;
char query[FM_MAX_SQL_STATEMENT_MAX];
if (strlen(af.entity_instance_id) == 0){
snprintf(query, sizeof(query),"%s = '%s' AND %s = ' '",
FM_ALARM_COLUMN_ALARM_ID, af.alarm_id,
FM_ALARM_COLUMN_ENTITY_INSTANCE_ID);
}
else {
snprintf(query, sizeof(query), "%s = '%s' AND %s LIKE '%s%%'",
FM_ALARM_COLUMN_ALARM_ID, af.alarm_id,
FM_ALARM_COLUMN_ENTITY_INSTANCE_ID, af.entity_instance_id);
}
fm_db_util_build_sql_query((const char*)FM_ALARM_TABLE_NAME, query, sql);
FM_DEBUG_LOG("get_alarm:(%s)\n", sql.c_str());
if ((sess.query(sql.c_str(), alarms)) != true){
return false;
}
return true;
}
bool CFmDbAlarmOperation::get_alarms_by_id(CFmDBSession &sess,const char *id, fm_db_result_t & alarms) {
fm_alarm_id alm_id = {0};
char query[FM_MAX_SQL_STATEMENT_MAX];
std::string sql;
snprintf(alm_id, sizeof(alm_id), "%s", id);
snprintf(query, sizeof(query),"%s = '%s'", FM_ALARM_COLUMN_ALARM_ID, id);
fm_db_util_build_sql_query((const char*)FM_ALARM_TABLE_NAME, query, sql);
FM_DEBUG_LOG("CMD:(%s)\n", sql.c_str());
if ((sess.query(sql.c_str(), alarms)) != true){
return false;
}
return true;
}
bool CFmDbAlarmOperation::get_alarms(CFmDBSession &sess, const char *entity_instance_id, fm_db_result_t &alarms) {
std::string sql = CFmDbAlarmOperation::build_base_alarm_query(entity_instance_id);
FM_DEBUG_LOG("CMD:(%s)\n", sql.c_str());
if (!sess.query(sql.c_str(), alarms))
return false;
return true;
}
bool CFmDbAlarmOperation::get_alarms_by_id_n_eid(CFmDBSession &sess, const AlarmFilter &af, fm_db_result_t &alarms) {
std::string sql = CFmDbAlarmOperation::build_base_alarm_query(af.entity_instance_id);
if (strlen(af.alarm_id) > 0) {
char query[FM_MAX_SQL_STATEMENT_MAX];
snprintf(query, sizeof(query), "%s.%s = '%s'", FM_ALARM_TABLE_NAME,
FM_ALARM_COLUMN_ALARM_ID, af.alarm_id);
sql += " AND ";
sql += query;
}else{
FM_INFO_LOG("Alarm_id not provided \n");
return false;
}
FM_DEBUG_LOG("CMD:(%s)\n", sql.c_str());
if (!sess.query(sql.c_str(), alarms))
return false;
return true;
}
std::string CFmDbAlarmOperation::build_base_alarm_query(const char *entity_instance_id) {
std::string sql;
char query[FM_MAX_SQL_STATEMENT_MAX]; char query[FM_MAX_SQL_STATEMENT_MAX];
fm_db_result_t res;
res.clear();
sql = FM_DB_SELECT_FROM_TABLE(FM_ALARM_TABLE_NAME); sql = FM_DB_SELECT_FROM_TABLE(FM_ALARM_TABLE_NAME);
sql += " ";
sql += " INNER JOIN "; sql += " INNER JOIN ";
sql += FM_EVENT_SUPPRESSION_TABLE_NAME; sql += FM_EVENT_SUPPRESSION_TABLE_NAME;
sql += " ON "; sql += " ON ";
@ -279,36 +348,14 @@ bool CFmDbAlarmOperation::get_alarms(CFmDBSession &sess,const char *id, fm_db_re
sql += FM_EVENT_SUPPRESSION_UNSUPPRESSED; sql += FM_EVENT_SUPPRESSION_UNSUPPRESSED;
sql += "'"; sql += "'";
if (id != NULL){ if (entity_instance_id != nullptr) {
snprintf(query, sizeof(query),"%s like '%s%s'", FM_ALARM_COLUMN_ENTITY_INSTANCE_ID, id,"%"); snprintf(query, sizeof(query), "%s.%s LIKE '%s%s'", FM_ALARM_TABLE_NAME,
if (NULL!=query) { FM_ALARM_COLUMN_ENTITY_INSTANCE_ID, entity_instance_id, "%");
sql += " AND "; sql += " AND ";
sql += query; sql += query;
} }
}
FM_DEBUG_LOG("CMD:(%s)\n", sql.c_str()); return sql;
if ((sess.query(sql.c_str(), alarms)) != true)
return false;
return true;
}
bool CFmDbAlarmOperation::get_alarms_by_id(CFmDBSession &sess,const char *id, fm_db_result_t & alarms) {
fm_alarm_id alm_id = {0};
char query[FM_MAX_SQL_STATEMENT_MAX];
std::string sql;
snprintf(alm_id, sizeof(alm_id), "%s", id);
snprintf(query, sizeof(query),"%s = '%s'", FM_ALARM_COLUMN_ALARM_ID, id);
fm_db_util_build_sql_query((const char*)FM_ALARM_TABLE_NAME, query, sql);
FM_DEBUG_LOG("CMD:(%s)\n", sql.c_str());
if ((sess.query(sql.c_str(), alarms)) != true){
return false;
}
return true;
} }
bool CFmDbAlarmOperation::get_all_alarms(CFmDBSession &sess, SFmAlarmDataT **alarms, size_t *len ) { bool CFmDbAlarmOperation::get_all_alarms(CFmDBSession &sess, SFmAlarmDataT **alarms, size_t *len ) {

View File

@ -66,9 +66,16 @@ public:
bool get_alarms_by_id(CFmDBSession &sess, const char *id, fm_db_result_t & alarms); bool get_alarms_by_id(CFmDBSession &sess, const char *id, fm_db_result_t & alarms);
bool get_alarms_by_id_n_eid(CFmDBSession &sess, const AlarmFilter &af, fm_db_result_t &alarms);
bool get_alarms_eid_not_strict(CFmDBSession &sess, AlarmFilter &af, fm_db_result_t & alarms);
bool mask_unmask_alarms(CFmDBSession &sess, SFmAlarmDataT &a, bool mask = true); bool mask_unmask_alarms(CFmDBSession &sess, SFmAlarmDataT &a, bool mask = true);
bool add_alarm_history(CFmDBSession &sess, SFmAlarmDataT &a, bool set); bool add_alarm_history(CFmDBSession &sess, SFmAlarmDataT &a, bool set);
private:
static std::string build_base_alarm_query(const char *entity_instance_id);
}; };
#endif /* FMDBALARM_H_ */ #endif /* FMDBALARM_H_ */

View File

@ -436,14 +436,14 @@ bool fm_db_util_build_sql_delete(const char* db_table, AlarmFilter *db_data,
char sql[FM_MAX_SQL_STATEMENT_MAX]; char sql[FM_MAX_SQL_STATEMENT_MAX];
if (strlen(db_data->entity_instance_id) == 0){ if (strlen(db_data->entity_instance_id) == 0){
snprintf(sql, sizeof(sql), "DElETE FROM %s WHERE %s = '%s' AND %s = ' '", snprintf(sql, sizeof(sql), "DELETE FROM %s WHERE %s = '%s' AND %s = ' '",
db_table, FM_ALARM_COLUMN_ALARM_ID, db_data->alarm_id, db_table, FM_ALARM_COLUMN_ALARM_ID, db_data->alarm_id,
FM_ALARM_COLUMN_ENTITY_INSTANCE_ID); FM_ALARM_COLUMN_ENTITY_INSTANCE_ID);
} }
else{ else{
snprintf(sql, sizeof(sql), "DElETE FROM %s WHERE %s = '%s' AND %s = '%s'", snprintf(sql, sizeof(sql), "DELETE FROM %s WHERE %s = '%s' AND %s like '%s%s'",
db_table, FM_ALARM_COLUMN_ALARM_ID, db_data->alarm_id, db_table, FM_ALARM_COLUMN_ALARM_ID, db_data->alarm_id,
FM_ALARM_COLUMN_ENTITY_INSTANCE_ID, db_data->entity_instance_id); FM_ALARM_COLUMN_ENTITY_INSTANCE_ID, db_data->entity_instance_id,"%");
} }
db_cmd.assign(sql); db_cmd.assign(sql);
return true; return true;
@ -456,7 +456,7 @@ bool fm_db_util_build_sql_delete_row(const char* db_table, int id,
char sql[FM_MAX_SQL_STATEMENT_MAX]; char sql[FM_MAX_SQL_STATEMENT_MAX];
snprintf(sql, sizeof(sql), "DElETE FROM %s WHERE %s = %d", snprintf(sql, sizeof(sql), "DELETE FROM %s WHERE %s = %d",
db_table, FM_ALARM_COLUMN_ID, id); db_table, FM_ALARM_COLUMN_ID, id);
db_cmd.assign(sql); db_cmd.assign(sql);
return true; return true;
@ -467,7 +467,7 @@ bool fm_db_util_build_sql_delete_all(const char* db_table, const char *id,
char sql[FM_MAX_SQL_STATEMENT_MAX]; char sql[FM_MAX_SQL_STATEMENT_MAX];
snprintf(sql, sizeof(sql), "DElETE FROM %s WHERE %s like '%s%s'", db_table, snprintf(sql, sizeof(sql), "DELETE FROM %s WHERE %s like '%s%s'", db_table,
FM_ALARM_COLUMN_ENTITY_INSTANCE_ID, id,"%"); FM_ALARM_COLUMN_ENTITY_INSTANCE_ID, id,"%");
db_cmd.assign(sql); db_cmd.assign(sql);
return true; return true;

View File

@ -1,5 +1,5 @@
// //
// Copyright (c) 2014 Wind River Systems, Inc. // Copyright (c) 2024 Wind River Systems, Inc.
// //
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
// //
@ -36,6 +36,7 @@ typedef enum {
EFmGetFaults, EFmGetFaults,
EFmReturnUUID, EFmReturnUUID,
EFmGetFaultsById, EFmGetFaultsById,
EFmGetFaultsByIdnEid,
EFmActMax EFmActMax
}EFmMsgActionsT; }EFmMsgActionsT;

View File

@ -1,5 +1,5 @@
// //
// Copyright (c) 2017-2018 Wind River Systems, Inc. // Copyright (c) 2017-2024 Wind River Systems, Inc.
// //
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
// //
@ -288,6 +288,97 @@ void get_db_alarms_by_id(CFmDBSession &sess, sFmGetReq &req, void *context){
} }
} }
/**
* Retrieves faults from the database based on the specified alarm ID and entity instance ID.
*
* This function queries the database for alarms that match the provided alarm ID
* and entity instance ID. The results are then sent back to the client through
* the provided socket server processor.
*
* **Parameters:**
* - `sess`: A reference to a `CFmDBSession` object representing the database session.
* - `req`: A reference to an `sFmGetReq` structure containing the request data.
* - `context`: A pointer to a context object.
*
* **Process Flow:**
* - The function initializes a buffer with the request data and extracts the header and data
* sections.
* - It casts the data section to an `AlarmFilter` pointer and the context to an
* `FmSocketServerProcessor` pointer.
* - Database Query
* - If alarms are found, it fills a vector with the alarm data.
* - Sets the number of alarms found in the buffer and copies the alarm data into the buffer.
* - It sends the response back to the client using the `send_response` method of the
* `FmSocketServerProcessor`.
*
* - If no alarms are found, it logs a message and sets the response code to
* `FM_ERR_ENTITY_NOT_FOUND`.
*
* **Returns:**
* - The function does not return a value but sends a response back to the client
* through the provided socket server processor.
*/
void get_db_alarms_by_id_n_eid(CFmDBSession &sess, sFmGetReq &req, void *context){
fm_buff_t buff = req.data;
SFmMsgHdrT *hdr = (SFmMsgHdrT *)&buff[0];
void * data = &buff[sizeof(SFmMsgHdrT)];
AlarmFilter *filter = (AlarmFilter *)data;
FmSocketServerProcessor *srv = (FmSocketServerProcessor *)context;
CFmDbAlarmOperation op;
fm_db_result_t res;
std::vector<SFmAlarmDataT> alarmv;
FM_DEBUG_LOG("handle get_db_alarms_by_id_n_eid:%s\n", filter->alarm_id);
hdr->msg_rc = FM_ERR_OK;
res.clear();
if (op.get_alarms_by_id_n_eid(sess, *filter, res) != true){
hdr->msg_rc = FM_ERR_DB_OPERATION_FAILURE;
}else if (res.size() > 0){
int ix = 0;
int resp_len = res.size();
SFmAlarmDataT alarm;
alarmv.clear();
// Fill the tuple data vector for the response.
for ( ; ix < resp_len ; ++ix ) {
CFmDbAlarm::convert_to(res[ix],&alarm);
alarmv.push_back(alarm);
}
} else {
FM_DEBUG_LOG("No alarms found for alarm id (%s), "
"entity_instance_id (%s)\n",
filter->alarm_id, filter->entity_instance_id);
hdr->msg_rc = FM_ERR_ENTITY_NOT_FOUND;
}
if ((hdr->msg_rc==FM_ERR_OK) && (alarmv.size() > 0)){
int found_num_alarms=alarmv.size();
FM_DEBUG_LOG("Get faults: found alarms: (%d)", found_num_alarms);
// (num of alarms found * size of alarm structure) +
// space to report number of alarms found.
int total_len =(found_num_alarms * sizeof(SFmAlarmDataT)) + sizeof(uint32_t);
void * buffer = malloc(total_len);
if (buffer==NULL) {
hdr->msg_rc =FM_ERR_SERVER_NO_MEM;
srv->send_response(req.fd,hdr,NULL,0);
return;
}
uint32_t *alen = (uint32_t*) buffer;
*alen = found_num_alarms;
SFmAlarmDataT * alarms = (SFmAlarmDataT*) ( ((char*)buffer)+sizeof(uint32_t));
memcpy(alarms,&(alarmv[0]),alarmv.size() * sizeof(SFmAlarmDataT));
srv->send_response(req.fd,hdr,buffer,total_len);
free(buffer);
} else {
srv->send_response(req.fd,hdr,NULL,0);
}
}
void fm_handle_job_request(CFmDBSession &sess, sFmJobReq &req){ void fm_handle_job_request(CFmDBSession &sess, sFmJobReq &req){
CFmDbAlarmOperation op; CFmDbAlarmOperation op;
CFmEventSuppressionOperation event_suppression_op; CFmEventSuppressionOperation event_suppression_op;
@ -333,6 +424,7 @@ void fm_handle_get_request(CFmDBSession &sess, sFmGetReq &req,
case EFmGetFault:get_db_alarm(sess,req,context); break; case EFmGetFault:get_db_alarm(sess,req,context); break;
case EFmGetFaults:get_db_alarms(sess,req,context); break; case EFmGetFaults:get_db_alarms(sess,req,context); break;
case EFmGetFaultsById:get_db_alarms_by_id(sess,req,context); break; case EFmGetFaultsById:get_db_alarms_by_id(sess,req,context); break;
case EFmGetFaultsByIdnEid:get_db_alarms_by_id_n_eid(sess,req,context); break;
default: default:
FM_ERROR_LOG("Unexpected job request, action:%u\n",hdr->action); FM_ERROR_LOG("Unexpected job request, action:%u\n",hdr->action);
break; break;
@ -471,8 +563,29 @@ void FmSocketServerProcessor::handle_delete_faults(int fd,
send_response(fd,hdr,NULL,0); send_response(fd,hdr,NULL,0);
} }
void FmSocketServerProcessor::handle_delete_fault(int fd, /**
SFmMsgHdrT *hdr, std::vector<char> &rdata, CFmDBSession &sess) { * Handles the deletion of faults based on the specified filter.
*
* This function processes the request to delete faults from the database.
* It first validates the request, then retrieves matching alarms and deletes
* them from the database. If multiple alarms are found, it handles each
* alarm separately and enqueues a job for each cleared alarm.
*
* **Parameters:**
* - `fd`: The file descriptor for the client connection.
* - `hdr`: A pointer to an `SFmMsgHdrT` structure containing the message header.
* - `rdata`: A reference to a vector of characters containing the request data.
* - `sess`: A reference to a `CFmDBSession` object representing the database session.
*
* **Returns:**
* - The function does not return a value but sends a response back to the client through
* the provided file descriptor.
*/
void FmSocketServerProcessor::handle_delete_fault(
int fd,
SFmMsgHdrT *hdr,
std::vector<char> &rdata,
CFmDBSession &sess) {
CFmDbAlarmOperation op; CFmDbAlarmOperation op;
sFmJobReq req; sFmJobReq req;
@ -480,28 +593,46 @@ void FmSocketServerProcessor::handle_delete_fault(int fd,
SFmAlarmDataT alarm; SFmAlarmDataT alarm;
fm_db_result_t res; fm_db_result_t res;
is_request_valid(hdr->msg_size,AlarmFilter); is_request_valid(hdr->msg_size, AlarmFilter);
void * data = &(rdata[sizeof(SFmMsgHdrT)]); void * data = &(rdata[sizeof(SFmMsgHdrT)]);
AlarmFilter *filter = (AlarmFilter *)(data); AlarmFilter *filter = (AlarmFilter *)(data);
hdr->msg_rc = FM_ERR_OK; hdr->msg_rc = FM_ERR_OK;
res.clear(); res.clear();
if ((op.get_alarm(sess, *filter, res)) != true){ if ((op.get_alarms_eid_not_strict(sess, *filter, res)) != true) {
hdr->msg_rc = FM_ERR_DB_OPERATION_FAILURE; hdr->msg_rc = FM_ERR_DB_OPERATION_FAILURE;
}else{ } else {
if (res.size() > 0){ if (res.size() > 0) {
if(op.delete_alarm(sess, *filter) > 0){ if (op.delete_alarm(sess, *filter) > 0) {
FM_INFO_LOG("Deleted alarm: (%s) (%s)\n", FM_INFO_LOG("Deleted alarm(s): (%s) (%s)\n",
filter->alarm_id, filter->entity_instance_id); filter->alarm_id, filter->entity_instance_id);
CFmDbAlarm::convert_to(res[0],&alarm); if (res.size() == 1) {
// normal workflow, just one alarm match
CFmDbAlarm::convert_to(res[0], &alarm);
fm_uuid_create(alarm.uuid);
req.type = FM_ALARM_CLEAR;
req.set = false;
req.data = alarm;
enqueue_job(req);
} else {
// Multiple alarms received
for (const auto &entry : res) {
SFmAlarmDataT alarm;
CFmDbAlarm::data_type entry_copy = entry;
CFmDbAlarm::convert_to(entry_copy, &alarm);
fm_uuid_create(alarm.uuid); fm_uuid_create(alarm.uuid);
req.type = FM_ALARM_CLEAR; req.type = FM_ALARM_CLEAR;
req.set = false; req.set = false;
req.data = alarm; req.data = alarm;
enqueue_job(req); enqueue_job(req);
}else{
hdr->msg_rc = FM_ERR_DB_OPERATION_FAILURE;
} }
}else{ }
} else {
hdr->msg_rc = FM_ERR_DB_OPERATION_FAILURE;
FM_INFO_LOG("Deleted alarm failed: (%s) (%s) (%s)\n",
filter->alarm_id, filter->entity_instance_id,
fm_error_from_int((EFmErrorT)hdr->msg_rc).c_str());
}
} else {
hdr->msg_rc = FM_ERR_ENTITY_NOT_FOUND; hdr->msg_rc = FM_ERR_ENTITY_NOT_FOUND;
FM_INFO_LOG("Deleted alarm failed: (%s) (%s) (%s)\n", FM_INFO_LOG("Deleted alarm failed: (%s) (%s) (%s)\n",
filter->alarm_id, filter->entity_instance_id, filter->alarm_id, filter->entity_instance_id,
@ -509,7 +640,7 @@ void FmSocketServerProcessor::handle_delete_fault(int fd,
} }
} }
FM_INFO_LOG("Response to delete fault: %u\n", hdr->msg_rc); FM_INFO_LOG("Response to delete fault: %u\n", hdr->msg_rc);
send_response(fd,hdr,NULL,0); send_response(fd, hdr, NULL, 0);
} }
void FmSocketServerProcessor::handle_get_faults_by_id(int fd, void FmSocketServerProcessor::handle_get_faults_by_id(int fd,
@ -522,6 +653,16 @@ void FmSocketServerProcessor::handle_get_faults_by_id(int fd,
enqueue_get(req); enqueue_get(req);
} }
void FmSocketServerProcessor::handle_get_faults_by_id_n_eid(int fd,
SFmMsgHdrT *hdr, std::vector<char> &rdata) {
is_request_valid(hdr->msg_size,AlarmFilter);
sFmGetReq req;
req.fd = fd;
req.data = rdata;
enqueue_get(req);
}
void FmSocketServerProcessor::handle_get_faults(int fd, void FmSocketServerProcessor::handle_get_faults(int fd,
SFmMsgHdrT *hdr, std::vector<char> &rdata) { SFmMsgHdrT *hdr, std::vector<char> &rdata) {
@ -555,6 +696,7 @@ void FmSocketServerProcessor::handle_socket_data(int fd,
case EFmGetFault:handle_get_fault(fd,hdr,rdata); break; case EFmGetFault:handle_get_fault(fd,hdr,rdata); break;
case EFmGetFaults:handle_get_faults(fd,hdr,rdata); break; case EFmGetFaults:handle_get_faults(fd,hdr,rdata); break;
case EFmGetFaultsById:handle_get_faults_by_id(fd,hdr,rdata); break; case EFmGetFaultsById:handle_get_faults_by_id(fd,hdr,rdata); break;
case EFmGetFaultsByIdnEid:handle_get_faults_by_id_n_eid(fd,hdr,rdata); break;
default: default:
FM_ERROR_LOG("Unexpected client request, action:%u\n",hdr->action); FM_ERROR_LOG("Unexpected client request, action:%u\n",hdr->action);
break; break;

View File

@ -31,6 +31,8 @@ protected:
std::vector<char> &rdata); std::vector<char> &rdata);
virtual void handle_get_faults_by_id(int fd, SFmMsgHdrT *hdr, virtual void handle_get_faults_by_id(int fd, SFmMsgHdrT *hdr,
std::vector<char> &rdata); std::vector<char> &rdata);
virtual void handle_get_faults_by_id_n_eid(int fd, SFmMsgHdrT *hdr,
std::vector<char> &rdata);
public: public:
void send_response(int fd, SFmMsgHdrT *hdr, void *data, size_t len); void send_response(int fd, SFmMsgHdrT *hdr, void *data, size_t len);
}; };

View File

@ -1,5 +1,5 @@
// //
// Copyright (c) 2018 Wind River Systems, Inc. // Copyright (c) 2024 Wind River Systems, Inc.
// //
// SPDX-License-Identifier: Apache-2.0 // SPDX-License-Identifier: Apache-2.0
// //
@ -13,7 +13,6 @@
#include "fmAlarmUtils.h" #include "fmAlarmUtils.h"
static const size_t DEF_MAX_ALARMS (1000);
static const size_t MAXSTRINGSIZE (500); static const size_t MAXSTRINGSIZE (500);
static PyObject *logging = NULL; static PyObject *logging = NULL;
@ -21,8 +20,8 @@ enum { error, warning, info, debug, max_level };
#define LOG_MSG(level,data,...) \ #define LOG_MSG(level,data,...) \
log_msg(level, "fm_python_extension: "\ log_msg(level, "%s:%d:%s: " data, __FILE__, __LINE__, \
data, ## __VA_ARGS__ ) __FUNCTION__, ##__VA_ARGS__)
#define ERROR_LOG(data,...) \ #define ERROR_LOG(data,...) \
LOG_MSG(error, data, ## __VA_ARGS__) LOG_MSG(error, data, ## __VA_ARGS__)
@ -100,6 +99,65 @@ static PyObject * _fm_set(PyObject * self, PyObject *args) {
Py_RETURN_NONE; Py_RETURN_NONE;
} }
static PyObject * _fm_set_list(PyObject * self, PyObject *args) {
/* Receives a PyObject expected to be a list of strings
containing different alarm information.
The function then parses each string into different alarm
structures, which are filled and sent to the C++ core. */
std::string alarm;
fm_uuid_t tmp_uuid;
PyObject *uuidList = PyList_New(0);
EFmErrorT rc = FM_ERR_INVALID_REQ;
PyObject *listObj = nullptr;
if (!PyArg_ParseTuple(args, "O", &listObj)) {
ERROR_LOG("Failed to parse args.");
Py_RETURN_NONE;
}
if (!PyList_Check(listObj)) {
ERROR_LOG("Expected a list.");
Py_RETURN_NONE;
}
Py_ssize_t num_items = PyList_Size(listObj);
for (Py_ssize_t i = 0; i < num_items; i++) {
PyObject *item = PyList_GetItem(listObj, i);
if (!PyUnicode_Check(item)) {
ERROR_LOG("List items must be strings.");
Py_RETURN_NONE;
}
const char *alm_str = PyUnicode_AsUTF8(item);
std::string alarm(alm_str);
SFmAlarmDataT alm_data;
if (!fm_alarm_from_string(alarm, &alm_data)) {
ERROR_LOG("Failed to convert string to alarm.");
continue;
}
rc = fm_set_fault(&alm_data, &tmp_uuid);
if (rc == FM_ERR_OK) {
PyObject *uuidStr = PyUnicode_FromString(tmp_uuid);
PyList_Append(uuidList, uuidStr);
Py_DECREF(uuidStr);
} else if (rc == FM_ERR_NOCONNECT) {
WARNING_LOG("Failed to connect to FM manager");
} else {
ERROR_LOG("Failed to generate an alarm: (%s) (%s)",
alm_data.alarm_id, alm_data.entity_instance_id);
}
}
if (rc == FM_ERR_OK) {
return uuidList;
}
Py_RETURN_NONE;
}
static PyObject * _fm_get(PyObject * self, PyObject *args) { static PyObject * _fm_get(PyObject * self, PyObject *args) {
const char *filter; const char *filter;
@ -237,6 +295,71 @@ static PyObject * _fm_get_by_eid(PyObject * self, PyObject *args, PyObject* kwar
Py_RETURN_FALSE; Py_RETURN_FALSE;
} }
static PyObject * _fm_get_by_id_n_eid(PyObject * self, PyObject *args) {
/* Receive a PyObject expected to be a filter containing
alarm_id and entity_instance_id. The entity_instance_id
does not need to be complete, allowing it to match
more than one row.
The function parses this object into different alarm
strings and fills a filter alarm structure that is
sent to the C++ core. */
const char *filter;
AlarmFilter af;
std::string alm_str, filter_str;
std::vector< SFmAlarmDataT > lst;
unsigned int max= DEF_MAX_ALARMS;
EFmErrorT rc;
if (!PyArg_ParseTuple(args, "s", &filter)) {
ERROR_LOG("Failed to parse args.");
Py_RETURN_FALSE;
}
filter_str.assign(filter);
if (!fm_alarm_filter_from_string(filter_str, &af)) {
ERROR_LOG("Invalid alarm filter: (%s)",
filter_str.c_str());
Py_RETURN_FALSE;
}
try {
lst.resize(max);
} catch(...) {
ERROR_LOG("Failed to allocate memory.");
Py_RETURN_FALSE;
}
unsigned int max_alarms_to_get = max;
rc = fm_get_faults_by_id_n_eid(&af, &(lst[0]), &max_alarms_to_get);
if (rc == FM_ERR_OK) {
PyObject *__lst = PyList_New(0);
for ( size_t ix = 0; ix < max_alarms_to_get; ++ix ) {
std::string s;
fm_alarm_to_string(&lst[ix], s);
if (s.size() > 0) {
if (PyList_Append(__lst,PyUnicode_FromString(s.c_str())) != 0) {
ERROR_LOG("Failed to append alarm to the list");
}
}
}
/* python will garbage collect if the reference count is correct
(it should be 1 at this point) */
return __lst;
}
if (rc == FM_ERR_ENTITY_NOT_FOUND) {
DEBUG_LOG("Alarm id (%s), Entity id:(%s) not found",
af.alarm_id, af.entity_instance_id);
Py_RETURN_NONE;
} else if (rc == FM_ERR_NOCONNECT) {
WARNING_LOG("Failed to connect to FM manager");
} else {
ERROR_LOG("Failed to get alarm list for entity id (%s), error code: (%d)",
af.entity_instance_id, rc);
}
Py_RETURN_FALSE;
}
static PyObject * _fm_clear(PyObject * self, PyObject *args) { static PyObject * _fm_clear(PyObject * self, PyObject *args) {
const char *filter; const char *filter;
@ -312,6 +435,10 @@ static PyMethodDef _methods [] = {
"Get alarms by alarm id" }, "Get alarms by alarm id" },
{ "get_by_eid", (PyCFunction)_fm_get_by_eid, METH_VARARGS | METH_KEYWORDS, { "get_by_eid", (PyCFunction)_fm_get_by_eid, METH_VARARGS | METH_KEYWORDS,
"Get alarms by entity instance id" }, "Get alarms by entity instance id" },
{ "get_by_id_n_eid", _fm_get_by_id_n_eid, METH_VARARGS,
"Get list of alarms by filter" },
{ "set_fault_list", _fm_set_list, METH_VARARGS,
"Set alarm list" },
{ NULL, NULL, 0, NULL } { NULL, NULL, 0, NULL }
}; };