osaf/services/saf/logsv/README | 16 + osaf/services/saf/logsv/config/Makefile.am | 4 +- osaf/services/saf/logsv/config/gcfg_classes.xml | 18 + osaf/services/saf/logsv/config/gcfg_objects.xml | 6 + osaf/services/saf/logsv/lgs/Makefile.am | 6 +- osaf/services/saf/logsv/lgs/lgs.h | 1 + osaf/services/saf/logsv/lgs/lgs_amf.cc | 9 +- osaf/services/saf/logsv/lgs/lgs_evt.cc | 11 +- osaf/services/saf/logsv/lgs/lgs_evt.h | 1 + osaf/services/saf/logsv/lgs/lgs_fmt.cc | 52 +- osaf/services/saf/logsv/lgs/lgs_fmt.h | 20 +- osaf/services/saf/logsv/lgs/lgs_imm_gcfg.cc | 1082 +++++++++++++++++++++++ osaf/services/saf/logsv/lgs/lgs_imm_gcfg.h | 28 + osaf/services/saf/logsv/lgs/lgs_main.cc | 1 + osaf/services/saf/logsv/lgs/lgs_mbcsv.cc | 50 +- osaf/services/saf/logsv/lgs/lgs_mbcsv.h | 1 + osaf/services/saf/logsv/lgs/lgs_mds.cc | 13 +- tests/logsv/logtest.c | 7 + tests/logsv/logtest.h | 2 + tests/logsv/tet_LogOiOps.c | 205 ++++ 20 files changed, 1498 insertions(+), 35 deletions(-)
Add new tokens (@Cq and @Cp) to represent node name and network name. diff --git a/osaf/services/saf/logsv/README b/osaf/services/saf/logsv/README --- a/osaf/services/saf/logsv/README +++ b/osaf/services/saf/logsv/README @@ -732,3 +732,19 @@ for file handling thread complete file I If user suffers the timeout when sending a big record size (e.g: 65535 bytes), the user can adjust the waiting time by updating logFileIoTimeout attribute value up to 5000ms. + +3. New tokens are added (#1480) +------------------------------- +- @Cp: for showing the network name +- @Cq: for showing node name where the log record comes from. + +a) The network name comes from an configurable attribute `opensafNetworkName` + which belongs to global configurable class `OpensafConfig`. + The attribute can be accessed via DN `opensafConfigId=opensafGlobalConfig,safApp=OpenSAF`. + + LOG service is an applier to this object class, so that whenever there is change in + network name attribute `opensafNetworkName`, LOG service will be notified. + +b) Regarding node name, LOG service gets this information when decoding messages at MDS layer. + + diff --git a/osaf/services/saf/logsv/config/Makefile.am b/osaf/services/saf/logsv/config/Makefile.am --- a/osaf/services/saf/logsv/config/Makefile.am +++ b/osaf/services/saf/logsv/config/Makefile.am @@ -26,6 +26,8 @@ if ENABLE_IMMXML dist_pkgimmxml_svc_DATA = \ logsv_sc_template.xml \ logsv_classes.xml \ - logsv_objects.xml + logsv_objects.xml \ + gcfg_classes.xml \ + gcfg_objects.xml endif diff --git a/osaf/services/saf/logsv/config/gcfg_classes.xml b/osaf/services/saf/logsv/config/gcfg_classes.xml new file mode 100644 --- /dev/null +++ b/osaf/services/saf/logsv/config/gcfg_classes.xml @@ -0,0 +1,18 @@ +<?xml version="1.0" encoding="utf-8"?> +<imm:IMM-contents xmlns:imm="http://www.saforum.org/IMMSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="SAI-AIS-IMM-XSD-A.02.13.xsd"> + <class name="OpensafConfig"> + <category>SA_CONFIG</category> + <rdn> + <name>opensafConfigId</name> + <type>SA_STRING_T</type> + <category>SA_CONFIG</category> + <flag>SA_INITIALIZED</flag> + </rdn> + <attr> + <name>opensafNetworkName</name> + <type>SA_STRING_T</type> + <category>SA_CONFIG</category> + <flag>SA_WRITABLE</flag> + </attr> + </class> +</imm:IMM-contents> diff --git a/osaf/services/saf/logsv/config/gcfg_objects.xml b/osaf/services/saf/logsv/config/gcfg_objects.xml new file mode 100644 --- /dev/null +++ b/osaf/services/saf/logsv/config/gcfg_objects.xml @@ -0,0 +1,6 @@ +<?xml version="1.0" encoding="utf-8"?> +<imm:IMM-contents xmlns:imm="http://www.saforum.org/IMMSchema" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="SAI-AIS-IMM-XSD-A.02.13.xsd"> + <object class="OpensafConfig"> + <dn>opensafConfigId=opensafGlobalConfig,safApp=OpenSAF</dn> + </object> +</imm:IMM-contents> diff --git a/osaf/services/saf/logsv/lgs/Makefile.am b/osaf/services/saf/logsv/lgs/Makefile.am --- a/osaf/services/saf/logsv/lgs/Makefile.am +++ b/osaf/services/saf/logsv/lgs/Makefile.am @@ -36,7 +36,8 @@ noinst_HEADERS = \ lgs_mbcsv_v2.h \ lgs_mbcsv_v3.h \ lgs_mbcsv_v5.h \ - lgs_recov.h + lgs_recov.h \ + lgs_imm_gcfg.h osaf_execbindir = $(pkglibdir) osaf_execbin_PROGRAMS = osaflogd @@ -65,7 +66,8 @@ osaflogd_SOURCES = \ lgs_mbcsv_v2.cc \ lgs_mbcsv_v3.cc \ lgs_mbcsv_v5.cc \ - lgs_recov.cc + lgs_recov.cc \ + lgs_imm_gcfg.cc osaflogd_LDADD = \ $(top_builddir)/osaf/tools/safimm/src/libimmutil.la \ diff --git a/osaf/services/saf/logsv/lgs/lgs.h b/osaf/services/saf/logsv/lgs/lgs.h --- a/osaf/services/saf/logsv/lgs/lgs.h +++ b/osaf/services/saf/logsv/lgs/lgs.h @@ -42,6 +42,7 @@ #include "lgs_util.h" #include "lgs_stream.h" #include "lgs_config.h" +#include "lgs_imm_gcfg.h" /* ======================================================================== * DEFINITIONS diff --git a/osaf/services/saf/logsv/lgs/lgs_amf.cc b/osaf/services/saf/logsv/lgs/lgs_amf.cc --- a/osaf/services/saf/logsv/lgs/lgs_amf.cc +++ b/osaf/services/saf/logsv/lgs/lgs_amf.cc @@ -66,6 +66,7 @@ static SaAisErrorT amf_active_state_hand lgs_imm_impl_set(cb->immOiHandle); conf_runtime_obj_create(cb->immOiHandle); + lgs_start_gcfg_applier(); /* check existing streams */ stream = log_stream_getnext_by_name(NULL); @@ -75,8 +76,8 @@ static SaAisErrorT amf_active_state_hand *stream->p_fd = -1; /* First Initialize fd */ stream = log_stream_getnext_by_name(stream->name); } - - done: + +done: immutilWrapperProfile.nTries = 20; /* Reset retry time to more normal value. */ immutilWrapperProfile.errorsAreFatal = 1; /* Update role independent of stream processing */ @@ -134,6 +135,8 @@ static SaAisErrorT amf_quiescing_state_h (void)immutil_saImmOiImplementerClear(cb->immOiHandle); immutilWrapperProfile.errorsAreFatal = 1; + lgs_stop_gcfg_applier(); + return saAmfCSIQuiescingComplete(cb->amf_hdl, invocation, SA_AIS_OK); } @@ -163,6 +166,8 @@ static SaAisErrorT amf_quiesced_state_ha (void)immutil_saImmOiImplementerClear(cb->immOiHandle); immutilWrapperProfile.errorsAreFatal = 1; + lgs_stop_gcfg_applier(); + /* ** Change the MDS VDSET role to Quiesced. Wait for MDS callback with type ** MDS_CALLBACK_QUIESCED_ACK. Then change MBCSv role. Don't change diff --git a/osaf/services/saf/logsv/lgs/lgs_evt.cc b/osaf/services/saf/logsv/lgs/lgs_evt.cc --- a/osaf/services/saf/logsv/lgs/lgs_evt.cc +++ b/osaf/services/saf/logsv/lgs/lgs_evt.cc @@ -22,6 +22,7 @@ #include "lgs_mbcsv_v1.h" #include "lgs_mbcsv_v2.h" #include "lgs_recov.h" +#include "lgs_imm_gcfg.h" /* Macro to validate the version */ #define m_LOG_VER_IS_VALID(ver) \ @@ -527,6 +528,7 @@ static uint32_t proc_rda_cb_msg(lgsv_lgs /* fail over, become implementer */ lgs_imm_impl_set(lgs_cb->immOiHandle); + lgs_start_gcfg_applier(); /* Agent down list has to be processed first */ lgs_process_lga_down_list(); @@ -1199,8 +1201,13 @@ static uint32_t proc_write_log_async_msg lgsv_ckpt_msg_v2_t ckpt_v2; void *ckpt_ptr; uint32_t max_logrecsize = 0; + char node_name[_POSIX_HOST_NAME_MAX]; - TRACE_ENTER2("client_id %u, stream ID %u", param->client_id, param->lstr_id); + memset(node_name, 0, _POSIX_HOST_NAME_MAX); + strncpy(node_name, evt->node_name, _POSIX_HOST_NAME_MAX); + + TRACE_ENTER2("client_id %u, stream ID %u, node_name = %s", + param->client_id, param->lstr_id, node_name); if (lgs_client_get_by_id(param->client_id) == NULL) { TRACE("Bad client ID: %u", param->client_id); @@ -1235,7 +1242,7 @@ static uint32_t proc_write_log_async_msg } if ((n = lgs_format_log_record(param->logRecord, stream->logFileFormat, stream->maxLogFileSize, - stream->fixedLogRecordSize, buf_size, logOutputString, ++stream->logRecordId)) == 0) { + stream->fixedLogRecordSize, buf_size, logOutputString, ++stream->logRecordId, node_name)) == 0) { error = SA_AIS_ERR_INVALID_PARAM; goto done; } diff --git a/osaf/services/saf/logsv/lgs/lgs_evt.h b/osaf/services/saf/logsv/lgs/lgs_evt.h --- a/osaf/services/saf/logsv/lgs/lgs_evt.h +++ b/osaf/services/saf/logsv/lgs/lgs_evt.h @@ -52,6 +52,7 @@ typedef struct lgsv_lgs_evt { */ MDS_DEST fr_dest; NODE_ID fr_node_id; + char node_name[_POSIX_HOST_NAME_MAX]; MDS_SEND_PRIORITY_TYPE rcvd_prio; /* Priority of the recvd evt */ LGSV_LGS_EVT_TYPE evt_type; union { diff --git a/osaf/services/saf/logsv/lgs/lgs_fmt.cc b/osaf/services/saf/logsv/lgs/lgs_fmt.cc --- a/osaf/services/saf/logsv/lgs/lgs_fmt.cc +++ b/osaf/services/saf/logsv/lgs/lgs_fmt.cc @@ -23,6 +23,7 @@ #include <logtrace.h> #include "lgs_fmt.h" +#include "lgs.h" /* Number of seconds per an hour/minute */ #define SECOND_PER_HOUR 3600L @@ -253,6 +254,24 @@ static SaBoolT validateComToken(SaString } break; + case C_NETWORK_NAME_LETTER: + shiftOffset = static_cast<int>(C_NETWORK_NAME_OFFSET); + if ((*tokenFlags >> shiftOffset) & 1) { + tokenOk = SA_FALSE; /* Same token used two times */ + } else { + *tokenFlags = (*tokenFlags | (1 << shiftOffset)); + } + break; + + case C_NODE_NAME_LETTER: + shiftOffset = static_cast<int>(C_NODE_NAME_OFFSET); + if ((*tokenFlags >> shiftOffset) & 1) { + tokenOk = SA_FALSE; /* Same token used two times */ + } else { + *tokenFlags = (*tokenFlags | (1 << shiftOffset)); + } + break; + default: /* Non valid token letter */ *fmtExpPtrOffset = 1; tokenOk = SA_FALSE; @@ -527,7 +546,10 @@ static int extractCommonField(char *dest SaInt32T inputPos, SaUint32T logRecordIdCounter, const SaBoolT *twelveHourModeFlag, - const struct tm *timeStampData, const SaLogRecordT *logRecord, SaUint16T rec_size) + const struct tm *timeStampData, + const SaLogRecordT *logRecord, + SaUint16T rec_size, + char *node_name) { SaInt32T fieldSize; size_t stringSize, i; @@ -785,6 +807,16 @@ static int extractCommonField(char *dest free(hex_string); break; + case C_NETWORK_NAME_LETTER: + characters = snprintf(dest, dest_size, "%s", lgs_get_networkname().c_str()); + stringSize = characters; + break; + + case C_NODE_NAME_LETTER: + characters = snprintf(dest, dest_size, "%s", node_name); + stringSize = characters; + break; + default: characters = 0; break; @@ -1003,7 +1035,7 @@ static int extractNotificationField(char fieldSize = (fieldSize > 2) ? (fieldSize - 2) : 2; characters = snprintf(dest, dest_size, "%#.*x", fieldSize, - logRecord->logHeader.ntfHdr.eventType); + logRecord->logHeader.ntfHdr.eventType); } *fmtExpPtrOffset = *fmtExpPtrOffset + fieldSizeOffset; @@ -1229,8 +1261,14 @@ SaBoolT lgs_is_valid_format_expression(c * * @return int number of bytes written to dest */ -int lgs_format_log_record(SaLogRecordT *logRecord, const SaStringT formatExpression, SaUint64T logFileSize, - SaUint16T fixedLogRecordSize, size_t dest_size, char *dest, SaUint32T logRecordIdCounter) +int lgs_format_log_record(SaLogRecordT *logRecord, + const SaStringT formatExpression, + SaUint64T logFileSize, + SaUint16T fixedLogRecordSize, + size_t dest_size, + char *dest, + SaUint32T logRecordIdCounter, + char *node_name) { SaStringT fmtExpPtr = &formatExpression[0]; SaStringT fmtExpPtrSnabel = &formatExpression[1]; @@ -1272,7 +1310,11 @@ int lgs_format_log_record(SaLogRecordT * &truncationLetterPos, (SaInt32T)strlen(dest), logRecordIdCounter, - twelveHourModeFlag, timeStampData, logRecord,rec_size); + twelveHourModeFlag, + timeStampData, + logRecord, + rec_size, + node_name); break; case NOTIFICATION_LOG_RECORD_FIELD_TYPE: diff --git a/osaf/services/saf/logsv/lgs/lgs_fmt.h b/osaf/services/saf/logsv/lgs/lgs_fmt.h --- a/osaf/services/saf/logsv/lgs/lgs_fmt.h +++ b/osaf/services/saf/logsv/lgs/lgs_fmt.h @@ -54,7 +54,9 @@ typedef enum { C_NOTIFICATION_CLASS_ID_SHIFT_OFFSET, C_LR_TRUNCATION_INFO_SHIFT_OFFSET, C_LR_STRING_BODY_SHIFT_OFFSET, - C_LR_HEX_CHAR_BODY_SHIFT_OFFSET + C_LR_HEX_CHAR_BODY_SHIFT_OFFSET, + C_NETWORK_NAME_OFFSET, + C_NODE_NAME_OFFSET } commonTokenShiftOffsetT; typedef enum { @@ -100,7 +102,9 @@ typedef enum { C_NOTIFICATION_CLASS_ID_LETTER = 'c', C_LR_TRUNCATION_INFO_LETTER = 'x', C_LR_STRING_BODY_LETTER = 'b', - C_LR_HEX_CHAR_BODY_LETTER = 'i' + C_LR_HEX_CHAR_BODY_LETTER = 'i', + C_NETWORK_NAME_LETTER = 'p', + C_NODE_NAME_LETTER = 'q' } commonTokenLetterT; typedef enum { @@ -172,7 +176,15 @@ typedef enum { } logStreamTypeT; extern SaBoolT lgs_is_valid_format_expression(const SaStringT, logStreamTypeT, SaBoolT *); -extern int lgs_format_log_record(SaLogRecordT *, const SaStringT, SaUint64T logFileSize, SaUint16T fixedLogRecordSize, - size_t dest_size, char *dest, SaUint32T); +extern int lgs_format_log_record( + SaLogRecordT *, + const SaStringT, + SaUint64T logFileSize, + SaUint16T fixedLogRecordSize, + size_t dest_size, + char *dest, + SaUint32T, + char *node_name + ); #endif diff --git a/osaf/services/saf/logsv/lgs/lgs_imm_gcfg.cc b/osaf/services/saf/logsv/lgs/lgs_imm_gcfg.cc new file mode 100644 --- /dev/null +++ b/osaf/services/saf/logsv/lgs/lgs_imm_gcfg.cc @@ -0,0 +1,1082 @@ +/* -*- OpenSAF -*- + * + * (C) Copyright 2016 The OpenSAF Foundation + * + * 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. This file and program are licensed + * under the GNU Lesser General Public License Version 2.1, February 1999. + * The complete license can be accessed from the following location: + * http://opensource.org/licenses/lgpl-license.php + * See the Copying file included with the OpenSAF distribution for full + * licensing terms. + * + * Author(s): Ericsson AB + * + */ + +#include "lgs_imm_gcfg.h" + +#include <errno.h> +#include <string.h> +#include <unistd.h> +#include <sys/socket.h> +#include <fcntl.h> + +#include "saf_error.h" +#include "logtrace.h" +#include "saImmOi.h" +#include "saImmOm.h" +#include "immutil.h" +#include "osaf_time.h" +#include "osaf_poll.h" + +/* + * Implements an IMM applier for the OpensafConfig class. + * Used for detecting changes of opensafNetworkName attribute. + * The applier runs in its own thread + * + * API: + * + * int lgs_start_gcfg_applier() + * This function starts the applier in a separate thread + * + * int lgs_stop_gcfg_applier() + * This function stops the applier and free all resources + * + * char* lgs_get_networkname(char **name_str) + * Gives a pointer to a network name string + * + * TBC: Place a message in the mail box when network name is changed?? + * + * USAGE: + * + * The applier shall be started on the ACTIVE server only. + * Start the applier when log server is started and when changing HA state + * to ACTIVE. + * Stop the applier when leaving ACTIVE state (quiesced and standby state handler) + * + * NOTES: + * 1. Immutil cannot be used. The immutil wrapper profile is global snd not + * thread safe. + * + */ + +/* Information given when starting thread + */ +typedef struct thread_info { + int socket; +} lgs_thread_info_t; + +/** + * 'Private' global variables used for: + */ +static const SaImmClassNameT gcfg_class = const_cast<SaImmClassNameT>("OpensafConfig"); +static const SaImmOiImplementerNameT applier_name = const_cast<SaImmOiImplementerNameT>("@safLogService_appl"); +/* IMM handling */ +static SaVersionT immVersion = { 'A', 2, 11 }; + +/* Network name handling */ +static char *network_name = NULL; /* Save pointer to current name */ +static pthread_mutex_t lgs_gcfg_applier_mutex = PTHREAD_MUTEX_INITIALIZER; + +/* Inter thread communication (socket pair) */ +static const char* CMD_STOP = "s"; +static const char* CMD_START = "a"; +static const size_t CMD_LEN = 2; + +typedef enum { + AP_START, + AP_STOP +} th_cmd_t; + +static int to_thread_fd = 0; /* Socket for communication with thread */ + +/* Become applier cancellation handling */ +static bool cancel_flg = false; /* If true, cancel at next cancellation point */ + +/* Thread */ +static pthread_t thread_id = 0; + +/* States for the applier thread. Stopping and starting the applier is handled + * differently dependent on the thread state + */ +typedef enum { + /* Thread not started */ + TH_NOT_STARTED = 0, + /* Thread is started but has not yet entered the event handling poll loop */ + TH_STARTING, + /* Thread is fully started and running as applier */ + TH_IS_APPLIER, + /* Thread is fully started but is not running as applier. In this state + * it can service commands e.g. start applier command but has never + * become an applier or have given up the applier role + */ + TH_IDLE +} th_state_t; + +static th_state_t th_state = TH_NOT_STARTED; + +extern struct ImmutilWrapperProfile immutilWrapperProfile; + +/****************************************************************************** + * Outside applier thread + ******************************************************************************/ + +/******************* + * Utility functions + */ + +static int start_applier_thread(lgs_thread_info_t *start_info); +static void save_network_name(char* new_name); +static void applier_finalize(SaImmOiHandleT imm_appl_hdl); +static void *applier_thread(void *info_in); +static int read_network_name(); +static bool th_do_cancel(); + +static void send_command(th_cmd_t command) +{ + const char *cmd_ptr = NULL; + int rc = 0; + + TRACE_ENTER(); + + switch (command) { + case AP_START: + cmd_ptr = CMD_START; + break; + case AP_STOP: + cmd_ptr = CMD_STOP; + break; + default: + LOG_ER("Unknown command %d", command); + osaf_abort(0); + } + + while (1) { + rc = write(to_thread_fd, cmd_ptr, CMD_LEN); + if ((rc == -1) && ((errno == EINTR) || (errno == EAGAIN))) + /* Try again */ + continue; + else + break; + } + + if (rc == -1) { + LOG_ER("Write Fail %s", strerror(errno)); + osaf_abort(0); + } + + TRACE_LEAVE2("Command '%s', rc=%d", cmd_ptr, rc); +} + +/** + * Activate cancellation of ongoing applier initialization. + * This function is used outside of thread to trig cancellation + * The corresponding th_cancel_check function is used inside thread as a + * "cancellation point". + */ +static void th_cancel_activate() +{ + osaf_mutex_lock_ordie(&lgs_gcfg_applier_mutex); + cancel_flg = true; + osaf_mutex_unlock_ordie(&lgs_gcfg_applier_mutex); +} + +/** + * Set th_state protected by mutex. See corresponding th_state_get() + * @param th_state_set[in] + */ +static th_state_t inline th_state_get() +{ + th_state_t rc_th_state; + + osaf_mutex_lock_ordie(&lgs_gcfg_applier_mutex); + rc_th_state = th_state; + osaf_mutex_unlock_ordie(&lgs_gcfg_applier_mutex); + + return rc_th_state; +} + +/************************** + * Network name handler API + */ + +/** + * Start the applier + * Create applier thread (if needed) and start the applier. + * The thread initiates the IMM applier, reads opensafNetworkName and then waits + * for callbacks (selection object) in a poll loop + * + */ +void lgs_start_gcfg_applier() +{ + static lgs_thread_info_t thread_input; + int sock_fd[2] = {0}; + int rc = 0; + std::string tmp_name; + + TRACE_ENTER(); + + switch (th_state_get()) { + case TH_NOT_STARTED: + TRACE("TH_NOT_STARTED"); + /* Get the network name if not already fetched and saved */ + tmp_name = lgs_get_networkname(); + if (tmp_name.empty() == true) { + rc = read_network_name(); + if (rc == -1) { + LOG_WA("read_network_name() Fail"); + } + } + + /* Create socket pair for communication with applier thread + * Non blocking + */ + rc = socketpair(AF_UNIX, SOCK_STREAM, 0, sock_fd); + if (rc == -1) { + LOG_ER("socketpair Fail %s", strerror(errno)); + osaf_abort(0); + } + + fcntl(sock_fd[0], F_SETFL, O_NONBLOCK); + fcntl(sock_fd[1], F_SETFL, O_NONBLOCK); + to_thread_fd = sock_fd[0]; + thread_input.socket = sock_fd[1]; + + /* Start the thread */ + (void) start_applier_thread(&thread_input); + break; + + case TH_IDLE: + TRACE("TH_IDLE"); + /* Send applier start command to running thread */ + send_command(AP_START); + break; + + case TH_STARTING: + TRACE("TH_STARTING"); + case TH_IS_APPLIER: + TRACE("TH_IS_APPLIER"); + /* There is nothing to start we are already applier */ + default: + TRACE("%s: Called in wrong state %d", __FUNCTION__, th_state); + break; + } + + TRACE_LEAVE(); +} + +/** + * Stop the applier but only if an applier is started + * + */ +void lgs_stop_gcfg_applier() +{ + TRACE_ENTER(); + + switch (th_state_get()) { + case TH_IS_APPLIER: + TRACE("TH_IS_APPLIER"); + send_command(AP_STOP); + break; + + case TH_STARTING: + TRACE("TH_STARTING"); + /* Cancel ongoing applier activation and send stop command to + * enter correct state + */ + th_cancel_activate(); + send_command(AP_STOP); + break; + + case TH_NOT_STARTED: + TRACE("TH_NOT_STARTED"); + case TH_IDLE: + TRACE("TH_IDLE"); + /* Nothing to stop there is no active applier */ + default: + TRACE("%s: Called in wrong state %d", __FUNCTION__, th_state); + } + + TRACE_LEAVE(); +} + +/** + * Get the network name. + * If no network name exist a NULL pointer is returned + * Saved as a dynamic variable string. In parameter name_str will be set + * to point to the string. + * network_name. Saving and reading is done in different threads so + * must be protected by mutex. See also save_network_name() + * + * @param name_str[in] + * Memory for a string will be allocated and the pointer will be given + * to the calling function that has to free the memory. + * + * @return pointer to a network name string + */ +std::string lgs_get_networkname() +{ + std::string networkName; + + TRACE_ENTER(); + + osaf_mutex_lock_ordie(&lgs_gcfg_applier_mutex); + + /* Thread safe handling of return value */ + if (network_name != NULL) { + networkName = network_name; + } + + osaf_mutex_unlock_ordie(&lgs_gcfg_applier_mutex); + + TRACE_LEAVE2("name_str \"%s\"", networkName.empty()? "<empty>": networkName.c_str()); + + return networkName; +} + +/****************************************************************************** + * Used by applier thread only + ******************************************************************************/ + +/********************************* + * Applier callback functions + * See IMM AIS SaImmOiCallbacksT_2 + * Executed in OI thread + */ + +/** + * Save ccb info if OpensafConfig object is modified + * + */ +static SaAisErrorT ccbObjectModifyCallback(SaImmOiHandleT immOiHandle, + SaImmOiCcbIdT ccbId, const SaNameT *objectName, + const SaImmAttrModificationT_2 **attrMods) +{ + SaAisErrorT rc = SA_AIS_OK; + struct CcbUtilCcbData *ccbUtilCcbData; + + TRACE_ENTER2("CCB ID %llu, '%s'", ccbId, objectName->value); + + if ((ccbUtilCcbData = ccbutil_findCcbData(ccbId)) == NULL) { + if ((ccbUtilCcbData = ccbutil_getCcbData(ccbId)) == NULL) { + TRACE("Failed to get CCB object for %llu", ccbId); + rc = SA_AIS_ERR_NO_MEMORY; + goto done; + } + } + + ccbutil_ccbAddModifyOperation(ccbUtilCcbData, objectName, attrMods); + +done: + TRACE_LEAVE(); + return rc; +} + +/** + * Cleanup by deleting saved ccb info if aborted + * + */ +static void ccbAbortCallback(SaImmOiHandleT immOiHandle, SaImmOiCcbIdT ccbId) +{ + struct CcbUtilCcbData *ccbUtilCcbData; + + TRACE_ENTER2("CCB ID %llu", ccbId); + + if ((ccbUtilCcbData = ccbutil_findCcbData(ccbId)) != NULL) + ccbutil_deleteCcbData(ccbUtilCcbData); + else + TRACE("Failed to find CCB object for %llu", ccbId); + + TRACE_LEAVE(); +} + +/** + * Check if network name has been modified and save new network name + * + * We are an applier for the OpensafConfig class. Only one object of this class + * can exist so we don't have iterate over objects. + * We only save modifications so the operation type must be modify. + * We iterate over attributes even if there is only one configuration attribute + * but more attributes may be added in the future. + * + */ +static void ccbApplyCallback(SaImmOiHandleT immOiHandle, SaImmOiCcbIdT ccbId) +{ + struct CcbUtilCcbData *ccbUtilCcbData; + struct CcbUtilOperationData *opdata; + const SaImmAttrModificationT_2 *attrMod; + char *value_str = NULL; + int i = 0; + + TRACE_ENTER2("CCB ID %llu", ccbId); + + /* Verify the ccb */ + if ((ccbUtilCcbData = ccbutil_findCcbData(ccbId)) == NULL) { + TRACE("Failed to find CCB object for %llu", ccbId); + goto done; + } + + /* We don't need to loop since the only possible opereation is MODIFY + * and the only possible class is OpensafConfig class + */ + opdata = ccbUtilCcbData->operationListHead; + if (opdata->operationType != CCBUTIL_MODIFY) { + TRACE("Not a modify operation"); + goto done; + } + + if (strncmp(reinterpret_cast<char *>(opdata->objectName.value), + "opensafConfigId", sizeof("opensafConfigId") - 1) != 0) { + TRACE("Object \"%s\" not a OpensafConfig object", + reinterpret_cast<char *>(opdata->objectName.value)); + goto done; + } + + /* Read value in opensafNetworkName + * Note: This is implemented as a loop in case more attributes are + * added in the class in the future. For now the only + * attribute of interest here is opensafNetworkName + */ + TRACE("Read value in attributes"); + i = 0; + attrMod = opdata->param.modify.attrMods[i]; + for (i = 1; attrMod != NULL; i++) { + const SaImmAttrValuesT_2 *attribute = &attrMod->modAttr; + TRACE("Found attribute \"%s\"", attribute->attrName); + if (strcmp(attribute->attrName, "opensafNetworkName") == 0) { + /* Get the value for opensafNetworkName */ + void *value = NULL; + if (attribute->attrValuesNumber != 0) + value = attribute->attrValues[0]; + + if (value == NULL) { + TRACE("Value is NULL"); + save_network_name(value_str); + goto done; + } + + value_str = *(static_cast<char **>(value)); + TRACE("%s='%s'", attribute->attrName, value_str); + + /* + * Save the new network_name + */ + save_network_name(value_str); + } else { + /* Not opensafNetworkName */ + TRACE("Found attribute %s", attribute->attrName); + } + + attrMod = opdata->param.modify.attrMods[i]; + } + +done: + if (ccbUtilCcbData != NULL) + ccbutil_deleteCcbData(ccbUtilCcbData); + + TRACE_LEAVE(); +} + +/** + * An object of OpensafConfig class is created. We don't have to do anything + * + */ +static SaAisErrorT ccbCreateCallback(SaImmOiHandleT immOiHandle, + SaImmOiCcbIdT ccbId, const SaImmClassNameT className, + const SaNameT *parentName, const SaImmAttrValuesT_2 **attr) +{ + TRACE_ENTER(); + TRACE_LEAVE(); + return SA_AIS_OK; +} + +/** + * An object of OpensafConfig class is deleted. We don't have to do anything + * + */ +static SaAisErrorT ccbDeleteCallback(SaImmOiHandleT immOiHandle, + SaImmOiCcbIdT ccbId, const SaNameT *objectName) +{ + TRACE_ENTER(); + TRACE_LEAVE(); + return SA_AIS_OK; +} + +/* Callback function list + * We need: + * Modify for saving modify ccb + * Apply for knowing that the modification has been applied + * Abort for removing saved ccb in case of an abortion of ccb + */ +static const SaImmOiCallbacksT_2 callbacks = { + .saImmOiAdminOperationCallback = NULL, + .saImmOiCcbAbortCallback = ccbAbortCallback, + .saImmOiCcbApplyCallback = ccbApplyCallback, + .saImmOiCcbCompletedCallback = NULL, + .saImmOiCcbObjectCreateCallback = ccbCreateCallback, + .saImmOiCcbObjectDeleteCallback = ccbDeleteCallback, + .saImmOiCcbObjectModifyCallback = ccbObjectModifyCallback, + .saImmOiRtAttrUpdateCallback = NULL +}; + + +/*************************************** + * Internal utility function definitions + */ + +/** + * Save a new network name + * Saved as a dynamic variable string pointed to by 'private' global pointer + * network_name. Saving and reading is done in different threads so + * must be protected by mutex. See also lgs_get_networkname + * + * @param new_name[in] + */ +static void save_network_name(char* new_name) +{ + uint32_t name_len = 0; + + TRACE_ENTER2("\"%s\"", new_name); + + osaf_mutex_lock_ordie(&lgs_gcfg_applier_mutex); + + /* Delete old name */ + if (network_name != NULL) + free(network_name); + + /* Save new name */ + if (new_name == NULL) { + network_name = NULL; + } else { + name_len = strlen(new_name) + 1; + network_name = static_cast<char *>(calloc(1, name_len)); + if (network_name == NULL) { + LOG_ER("%s: calloc Fail", __FUNCTION__); + osaf_abort(0); + } + + strcpy(network_name, new_name); + } + + osaf_mutex_unlock_ordie(&lgs_gcfg_applier_mutex); + + TRACE_LEAVE(); +} + +/** + * Read network name from the OpensafConfig object + * - Create an Object manager + * - Search for and get opensafNetworkName value + * - Allocate memory for and save the value. Save pointer in network_name + * + * If no value is found network_name will be NULL + * + * @return -1 on error + */ +static int read_network_name() +{ + SaAisErrorT ais_rc = SA_AIS_OK; + SaImmHandleT om_handle = 0; + char *tmp_name_str = NULL; + int rc = 0; + /* Setup value get parameters */ + SaNameT object_name; + SaImmAttrValuesT_2 **attributes; + SaImmAttrValuesT_2 *attribute; + void *value = NULL; + /* Setup search initialize parameters */ + SaImmSearchHandleT searchHandle; + SaImmSearchParametersT_2 searchParam; + searchParam.searchOneAttr.attrName = const_cast<SaImmAttrNameT>( + "opensafNetworkName"); + searchParam.searchOneAttr.attrValueType = SA_IMM_ATTR_SASTRINGT; + searchParam.searchOneAttr.attrValue = NULL; + + SaImmAttrNameT attributeNames[2] = { + const_cast<SaImmAttrNameT>("opensafNetworkName"), + NULL + }; + + TRACE_ENTER(); + + /* + * Initialize an IMM object manager + */ + // Wait up to 500ms + immutilWrapperProfile.errorsAreFatal = 0; + immutilWrapperProfile.nTries = 500; + immutilWrapperProfile.retryInterval = 1000; + + ais_rc = immutil_saImmOmInitialize(&om_handle, NULL, &immVersion); + if (ais_rc != SA_AIS_OK) { + TRACE("immutil_saImmOmInitialize FAIL %s", saf_error(ais_rc)); + rc = -1; + goto done; + } + + /* + * Search for objects with attribute opensafNetworkName + */ + /* Find the opensafNetworkName attribute in the OpensafConfig object and + * get its value + */ + ais_rc = immutil_saImmOmSearchInitialize_2( + om_handle, + NULL, + SA_IMM_SUBTREE, + SA_IMM_SEARCH_ONE_ATTR | SA_IMM_SEARCH_GET_SOME_ATTR, + &searchParam, + attributeNames, + &searchHandle + ); + if (ais_rc != SA_AIS_OK) { + TRACE("immutil_saImmOmSearchInitialize_2 FAIL %s", saf_error(ais_rc)); + rc = -1; + goto done; + } + + /* + * Get the value for the searched attribute + */ + ais_rc = immutil_saImmOmSearchNext_2(searchHandle, &object_name, &attributes); + if (ais_rc != SA_AIS_OK) { + TRACE("immutil_saImmOmSearchNext_2 FAIL %s", saf_error(ais_rc)); + rc = -1; + goto done; + } + + /* + * Save the network name or set to NULL if no name is found + * Note: Saving network_name must be thread safe + */ + attribute = attributes[0]; + if (attribute->attrValuesNumber != 0) { + value = attribute->attrValues[0]; + tmp_name_str = *(static_cast<char **>(value)); + } else { + /* Set network name to an empty string if the attribute value + * is "empty" + */ + tmp_name_str = const_cast<char *>(""); + } + + save_network_name(tmp_name_str); + +done: + /* Finalize search */ + ais_rc = immutil_saImmOmFinalize(om_handle); + if ((ais_rc != SA_AIS_OK) && (ais_rc != SA_AIS_ERR_BAD_HANDLE)) { + /* BAD HANDLE is not a fault here since finalize is called + * also if initialize failed + */ + TRACE("immutil_saImmOmFinalize FAIL %s", saf_error(ais_rc)); + rc = -1; + } + + TRACE_LEAVE2("rc = %d", rc); + return rc; +} + +/** + * Initialize IMM API and get selection object + * The following API sequence is used: + * - Finalize if a handle exist + * - Initialize (get imm OI handle) + * - Get selection object + * + * Note1:TRY AGAIN loops time out after "max_waiting_time..." which can be + * up to 60 sec. + * + * Note2: Init can be canclled. See th_cancel_activate() + * Cancelling is done when reaching a cancellation point defined by + * th_cancel_OIinit() + * + * Is 60 sec timeout for initialize really needed? + * + * @param imm_appl_hdl[out] + * @param imm_appl_selobj[out] + * + * @return -1 on error + */ +/** + * + * @param imm_appl_hdl + * @param imm_appl_selobj + * @param nfds + * @return + */ +static int applier_init(SaImmOiHandleT *imm_appl_hdl, + SaSelectionObjectT *imm_appl_selobj) +{ + SaAisErrorT ais_rc = SA_AIS_OK; + int rc = 0; + + TRACE_ENTER(); + + if (th_do_cancel()) { + TRACE("Canceled at 1"); + /* Cancellation point no error */ + goto done; + } + + /* Finalize applier OI handle if needed */ + applier_finalize(*imm_appl_hdl); + + if (th_do_cancel()) { + TRACE("Canceled at 2"); + /* Cancellation point no error */ + goto done; + } + + // Wait up to 500ms + immutilWrapperProfile.errorsAreFatal = 0; + immutilWrapperProfile.nTries = 500; + immutilWrapperProfile.retryInterval = 1000; + + /* Initialize OI for applier and get OI handle */ + ais_rc = immutil_saImmOiInitialize_2(imm_appl_hdl, &callbacks, &immVersion); + if (ais_rc != SA_AIS_OK) { + LOG_WA("immutil_saImmOiInitialize_2 Failed %s", saf_error(ais_rc)); + rc = -1; + goto done; + } + + if (th_do_cancel()) { + TRACE("Canceled at 3"); + /* Cancellation point no error */ + applier_finalize(*imm_appl_hdl); + goto done; + } + + /* Get selection object for event handling */ + ais_rc = immutil_saImmOiSelectionObjectGet(*imm_appl_hdl, imm_appl_selobj); + if (ais_rc != SA_AIS_OK) { + LOG_WA("immutil_saImmOiSelectionObjectGet Failed %s", saf_error(ais_rc)); + applier_finalize(*imm_appl_hdl); + imm_appl_hdl = 0; + rc = -1; + goto done; + } + + if (th_do_cancel()) { + TRACE("Canceled at 3"); + /* Cancellation point no error */ + applier_finalize(*imm_appl_hdl); + goto done; + } + +done: + TRACE_LEAVE2("rc = %d", rc); + return rc; +} + +/** + * Become an IMM applier for OpensafConfig class + * - Register applier name + * - Become class implementer + * + * Note1: TRY AGAIN loops time out after "max_waiting_time..." which can be + * up to 60 sec. + * + * Note2: Must be done after lgs_imma_init_handle() + * + * @return -1 on error + */ +static int applier_set_name_class(SaImmOiHandleT imm_appl_hdl) +{ + SaAisErrorT ais_rc = SA_AIS_OK; + int rc = 0; + + TRACE_ENTER(); + + if (th_do_cancel()) { + TRACE("Canceled at 1"); + /* Cancellation point no error */ + applier_finalize(imm_appl_hdl); + goto done; + } + + /* Become applier */ + immutilWrapperProfile.errorsAreFatal = 0; + immutilWrapperProfile.nTries = 500; + immutilWrapperProfile.retryInterval = 1000; + + ais_rc = immutil_saImmOiImplementerSet(imm_appl_hdl, applier_name); + if (ais_rc != SA_AIS_OK) { + LOG_WA("immutil_saImmOiImplementerSet Failed %s", saf_error(ais_rc)); + applier_finalize(imm_appl_hdl); + rc = -1; + goto done; + } + + if (th_do_cancel()) { + TRACE("Canceled at 2"); + /* Cancellation point no error */ + applier_finalize(imm_appl_hdl); + goto done; + } + + /* Become class implementer (applier) for the OpensafConfig class */ + ais_rc = immutil_saImmOiClassImplementerSet(imm_appl_hdl, gcfg_class); + if (ais_rc != SA_AIS_OK) { + LOG_WA("immutil_saImmOiClassImplementerSet Failed %s", saf_error(ais_rc)); + applier_finalize(imm_appl_hdl); + rc = -1; + goto done; + } + + if (th_do_cancel()) { + TRACE("Canceled at 3"); + /* Cancellation point no error */ + applier_finalize(imm_appl_hdl); + goto done; + } + +done: + TRACE_LEAVE(); + return rc; +} + +/** + * Finalize the IMM applier + * + * @param imm_appl_hdl[in] + */ +static void applier_finalize(SaImmOiHandleT imm_appl_hdl) +{ + SaAisErrorT ais_rc = SA_AIS_OK; + + TRACE_ENTER(); + + /* Finalize applier OI handle if needed */ + if (imm_appl_hdl != 0) { + /* We have a handle to finalize */ + TRACE("saImmOiFinalize"); + + immutilWrapperProfile.errorsAreFatal = 0; + immutilWrapperProfile.nTries = 500; + immutilWrapperProfile.retryInterval = 1000; + + ais_rc = immutil_saImmOiFinalize(imm_appl_hdl); + if (ais_rc != SA_AIS_OK) { + TRACE("immutil_saImmOiFinalize Failed %s", saf_error(ais_rc)); + } + + imm_appl_hdl = 0; + } else { + TRACE("Finalize not needed"); + } + + TRACE_LEAVE(); +} + + +/******************************* + * 'Private' variables used for: + */ + +/** + * Check if applier init cancellation is activated + * Return value of cancellation flag and reset flag + * + * @return true if cancellation is active + */ +static bool th_do_cancel() +{ + bool rc = false; + osaf_mutex_lock_ordie(&lgs_gcfg_applier_mutex); + rc = cancel_flg; + cancel_flg = false; + osaf_mutex_unlock_ordie(&lgs_gcfg_applier_mutex); + return rc; +} + +/**************************** + * Applier event handler main + * + * The applier runs in a separate thread. The thread uses a poll loop to handle + * IMM events and communication events. Communication is handled using a socket + * pair. + * Possible communication events: + * - Start applier + * Set implementer name and become class-applier + * - Stop applier + * Do saImmOiImplementerClear() + * + * The handler also needs a cancellation mechanism. This mechanism does not + * cancel the thread but an ongoing applier initiation must be possible to + * cancel. This means that if setting of implementer name or class is ongoing + * it will be stopped and saImmOiImplementerClear() is called + */ + +/** + * Start the applier thread if not already started + * + * @param start_info[in] See lgs_thread_info_t + * @return -1 on error + */ +static int start_applier_thread(lgs_thread_info_t *start_info) +{ + int rc = 0; + void *thr_arg = start_info; + + TRACE_ENTER(); + + if (th_state == TH_NOT_STARTED) { + rc = pthread_create(&thread_id, NULL, applier_thread, thr_arg); + if (rc != 0) { + LOG_ER("pthread_create Fail %d", rc); + osaf_abort(0); + } + } else { + TRACE("Thread already started"); + rc = -1; + } + + TRACE_LEAVE(); + return rc; +} + +/** + * Set th_state protected by mutex. See corresponding th_state_get() + * @param th_state_set[in] + */ +static void inline th_state_set(th_state_t th_state_set) +{ + osaf_mutex_lock_ordie(&lgs_gcfg_applier_mutex); + th_state = th_state_set; + osaf_mutex_unlock_ordie(&lgs_gcfg_applier_mutex); +} + +/** + * The applier thread + * @param info_in[in] See lgs_thread_info_t + * @return - + */ +static void *applier_thread(void *info_in) +{ + /* Event handling + * Note: + * IMM selection object can only be part of polling when IMM OI is + * initialized. If IMM is finalized the selection object is not valid. + * This is handled by placing IMM selection fd as last element in fds + * vector and decrease and decrease nfds when IMM is finalized. + */ + enum { + FDA_COM = 0, /* Communication events */ + FDA_IMM /* IMM events */ + }; + + static struct pollfd fds[2]; + static nfds_t nfds = 1; /* We have no IMM selection object yet */ + int rc = 0; + SaAisErrorT ais_rc = SA_AIS_OK; + static SaImmOiHandleT imm_appl_hdl = 0; + static SaSelectionObjectT imm_appl_selobj = 0; + + TRACE_ENTER2("Thread will never return"); + lgs_thread_info_t *start_info = static_cast<lgs_thread_info_t *>(info_in); + int com_fd = start_info->socket; + + /* Loop needed for new intialize if imm_appl_hdl becomes invalid or the + * applier is restarted + */ + while (1) { + /* Initiate applier */ + th_state_set(TH_STARTING); + + rc = applier_init(&imm_appl_hdl, &imm_appl_selobj); + if (rc == -1) { + /* Some error handling */ + TRACE("applier_init Fail"); + osaf_abort(0); + } + + nfds = FDA_IMM + 1; /* IMM selection object is valid */ + + rc = applier_set_name_class(imm_appl_hdl); + if (rc == -1) { + /* Some error handling */ + LOG_ER("applier_set_name_class Fail"); + osaf_abort(0); + } + + th_state_set(TH_IS_APPLIER); + + /* Event handling */ + fds[FDA_IMM].fd = imm_appl_selobj; + fds[FDA_IMM].events = POLLIN; + fds[FDA_COM].fd = com_fd; + fds[FDA_COM].events = POLLIN; + + /* If no network name is saved, read the network name from the + * OpensafConfig class and save it + */ + std::string tmp_networkname; + tmp_networkname = lgs_get_networkname(); + if (tmp_networkname.empty() == true) { + rc = read_network_name(); + if (rc == -1) { + LOG_WA("read_network_name() Fail"); + } + } + + /*** Event handling loop ***/ + while(1) { + + (void) osaf_poll(fds, nfds, -1); + + if (fds[FDA_IMM].revents & POLLIN) { + TRACE("%s: IMM event", __FUNCTION__); + ais_rc = saImmOiDispatch(imm_appl_hdl, SA_DISPATCH_ALL); + if (ais_rc == SA_AIS_ERR_BAD_HANDLE) { + /* Handle is lost. We must initialize again */ + th_state_set(TH_STARTING); + break; + } + } + + if (fds[FDA_COM].revents & POLLIN) { + TRACE("%s: COM event", __FUNCTION__); + /* Handle start and stop requests */ + char cmd_str[256] = {0}; + while (1) { + rc = read(com_fd, cmd_str, 256); + if ((rc == -1) && ((errno == EINTR) || + (errno == EAGAIN))) { + /* Try again */ + continue; + } else break; + } + + if (rc == -1) { + LOG_ER("write Fail %s", strerror(errno)); + osaf_abort(0); + } + + TRACE("Read command '%s'", cmd_str); + + if (!strcmp(cmd_str, CMD_STOP)) { + TRACE("STOP received"); + /* Reset cancel flag */ + th_do_cancel(); + /* Give up applier */ + applier_finalize(imm_appl_hdl); + /* The IMM selection object is no longer + * valid so we have to stop polling IMM + */ + nfds -= 1; + th_state_set(TH_IDLE); + } else if (!strcmp(cmd_str, CMD_START)) { + TRACE("START received"); + /* Leave event loop for outer restart + * loop + */ + break; + } + } + } /* END Event handling loop */ + } /* END Restart loop */ +} diff --git a/osaf/services/saf/logsv/lgs/lgs_imm_gcfg.h b/osaf/services/saf/logsv/lgs/lgs_imm_gcfg.h new file mode 100644 --- /dev/null +++ b/osaf/services/saf/logsv/lgs/lgs_imm_gcfg.h @@ -0,0 +1,28 @@ +/* -*- OpenSAF -*- + * + * (C) Copyright 2016 The OpenSAF Foundation + * + * 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. This file and program are licensed + * under the GNU Lesser General Public License Version 2.1, February 1999. + * The complete license can be accessed from the following location: + * http://opensource.org/licenses/lgpl-license.php + * See the Copying file included with the OpenSAF distribution for full + * licensing terms. + * + * Author(s): Ericsson AB + * + */ + +#ifndef LGS_IMM_CLM_H +#define LGS_IMM_CLM_H + +#include <string> + +void lgs_start_gcfg_applier(); +void lgs_stop_gcfg_applier(); +std::string lgs_get_networkname(); + +#endif /* LGS_IMM_CLM_H */ + diff --git a/osaf/services/saf/logsv/lgs/lgs_main.cc b/osaf/services/saf/logsv/lgs/lgs_main.cc --- a/osaf/services/saf/logsv/lgs/lgs_main.cc +++ b/osaf/services/saf/logsv/lgs/lgs_main.cc @@ -392,6 +392,7 @@ static uint32_t log_initialize(void) /* Become OI. We will be blocked here until done */ lgs_imm_impl_set(lgs_cb->immOiHandle); conf_runtime_obj_create(lgs_cb->immOiHandle); + lgs_start_gcfg_applier(); /* Create streams that has configuration objects and become * class implementer for the SaLogStreamConfig class diff --git a/osaf/services/saf/logsv/lgs/lgs_mbcsv.cc b/osaf/services/saf/logsv/lgs/lgs_mbcsv.cc --- a/osaf/services/saf/logsv/lgs/lgs_mbcsv.cc +++ b/osaf/services/saf/logsv/lgs/lgs_mbcsv.cc @@ -780,25 +780,29 @@ static uint32_t ckpt_encode_async_update TRACE_ENTER(); /* Set reo_hdl from callback arg to ckpt_rec */ if (lgs_is_peer_v5()) { - data_v5 = reinterpret_cast<lgsv_ckpt_msg_v5_t *>((long)cbk_arg->info.encode.io_reo_hdl); + data_v5 = reinterpret_cast<lgsv_ckpt_msg_v5_t *>( + static_cast<long>( cbk_arg->info.encode.io_reo_hdl)); vdata = data_v5; edp_function = edp_ed_ckpt_msg_v5; } else if (lgs_is_peer_v4()) { - data_v3 = reinterpret_cast<lgsv_ckpt_msg_v3_t *>((long)cbk_arg->info.encode.io_reo_hdl); + data_v3 = reinterpret_cast<lgsv_ckpt_msg_v3_t *>( + static_cast<long>(cbk_arg->info.encode.io_reo_hdl)); vdata = data_v3; edp_function = edp_ed_ckpt_msg_v3; } else if (lgs_is_peer_v2()) { - data_v2 = reinterpret_cast<lgsv_ckpt_msg_v2_t *>((long)cbk_arg->info.encode.io_reo_hdl); + data_v2 = reinterpret_cast<lgsv_ckpt_msg_v2_t *>( + static_cast<long>(cbk_arg->info.encode.io_reo_hdl)); vdata = data_v2; edp_function = edp_ed_ckpt_msg_v2; } else { - data_v1 = reinterpret_cast<lgsv_ckpt_msg_v1_t *>((long)cbk_arg->info.encode.io_reo_hdl); + data_v1 = reinterpret_cast<lgsv_ckpt_msg_v1_t *>( + static_cast<long>(cbk_arg->info.encode.io_reo_hdl)); vdata = data_v1; edp_function = edp_ed_ckpt_msg_v1; } if (vdata == NULL) { - TRACE(" data == NULL, FAILED"); + TRACE("data == NULL, FAILED"); TRACE_LEAVE(); return NCSCC_RC_FAILURE; } @@ -1136,11 +1140,11 @@ static uint32_t ckpt_decode_async_update lgsv_ckpt_msg_v5_t *ckpt_msg_v5 = &msg_v5; void *ckpt_msg; lgsv_ckpt_header_t hdr, *hdr_ptr = &hdr; - + /* Same in all versions */ lgs_ckpt_initialize_msg_t *reg_rec; lgs_ckpt_stream_open_t *stream_open; - + TRACE_ENTER(); /* Decode the message header */ @@ -1444,10 +1448,10 @@ static uint32_t process_ckpt_data(lgs_cb lgsv_ckpt_msg_v5_t *data_v5; if ((!cb) || (data == NULL)) { - TRACE("%s - FAILED: (!cb) || (data == NULL)",__FUNCTION__); + TRACE("%s - FAILED: (!cb) || (data == NULL)", __FUNCTION__); return (rc = NCSCC_RC_FAILURE); } - + if (lgs_is_peer_v5()) { data_v5 = static_cast<lgsv_ckpt_msg_v5_t *>(data); lgsv_ckpt_msg_type = data_v5->header.ckpt_rec_type; @@ -1615,10 +1619,19 @@ static void insert_localmsg_in_stream(lo goto done; } + /* Use local host name as node name for missing record */ + char host_name[_POSIX_HOST_NAME_MAX]; + memset(host_name, 0, _POSIX_HOST_NAME_MAX); + /* TODO: should use gethostname or fopen(PKGSYSCONFDIR "/node_name", "r") */ + if (gethostname(host_name, _POSIX_HOST_NAME_MAX) == -1) { + TRACE("gethostname failed. Use default SC-2"); + strcpy(host_name, "SC-2"); + } + /* Format the log record */ if ((n = lgs_format_log_record(&log_record, stream->logFileFormat, stream->maxLogFileSize, - stream->fixedLogRecordSize, buf_size, logOutputString, - LOG_REC_ID)) == 0) { + stream->fixedLogRecordSize, buf_size, logOutputString, + LOG_REC_ID, host_name)) == 0) { LOG_ER("%s - Could not format internal log record",__FUNCTION__); goto done; } @@ -1640,10 +1653,15 @@ static void insert_localmsg_in_stream(lo } /* Format the log record */ - if ((n = lgs_format_log_record(&log_record, stream->logFileFormat, stream->maxLogFileSize, - stream->fixedLogRecordSize, buf_size, logOutputString, - LOG_REC_ID)) == 0) { - LOG_ER("%s - Could not format internal log record",__FUNCTION__); + if ((n = lgs_format_log_record( + &log_record, + stream->logFileFormat, + stream->maxLogFileSize, + stream->fixedLogRecordSize, + buf_size, + logOutputString, + LOG_REC_ID, host_name)) == 0) { + LOG_ER("%s - Could not format internal log record", __FUNCTION__); } } @@ -1771,7 +1789,9 @@ static uint32_t ckpt_proc_log_write(lgs_ lgs_free_edu_mem(logRecord); logRecord = NULL; } + lgs_free_edu_mem(logFileCurrent); + TRACE_LEAVE(); /* If rc == -2, means something happens in log handler thread diff --git a/osaf/services/saf/logsv/lgs/lgs_mbcsv.h b/osaf/services/saf/logsv/lgs/lgs_mbcsv.h --- a/osaf/services/saf/logsv/lgs/lgs_mbcsv.h +++ b/osaf/services/saf/logsv/lgs/lgs_mbcsv.h @@ -35,6 +35,7 @@ #define LGS_MBCSV_VERSION_2 2 #define LGS_MBCSV_VERSION_4 4 #define LGS_MBCSV_VERSION_5 5 + /* Current version */ #define LGS_MBCSV_VERSION 5 #define LGS_MBCSV_VERSION_MIN 1 diff --git a/osaf/services/saf/logsv/lgs/lgs_mds.cc b/osaf/services/saf/logsv/lgs/lgs_mds.cc --- a/osaf/services/saf/logsv/lgs/lgs_mds.cc +++ b/osaf/services/saf/logsv/lgs/lgs_mds.cc @@ -283,7 +283,7 @@ static uint32_t dec_lstr_close_msg(NCS_U Notes : None. ******************************************************************************/ -static uint32_t dec_write_log_async_msg(NCS_UBAID *uba, lgsv_msg_t *msg) +static uint32_t dec_write_log_async_msg(NCS_UBAID *uba, lgsv_msg_t *msg, NODE_ID nodeId) { uint8_t *p8; uint32_t rc = NCSCC_RC_SUCCESS; @@ -796,6 +796,7 @@ static uint32_t mds_dec(struct ncsmds_ca uint8_t *p8; lgsv_lgs_evt_t *evt = NULL; NCS_UBAID *uba = info->info.dec.io_uba; + NODE_ID node_id = info->info.dec.i_node_id; uint8_t local_data[20]; uint32_t rc = NCSCC_RC_SUCCESS; @@ -841,7 +842,7 @@ static uint32_t mds_dec(struct ncsmds_ca rc = dec_lstr_close_msg(uba, &evt->info.msg); break; case LGSV_WRITE_LOG_ASYNC_REQ: - rc = dec_write_log_async_msg(uba, &evt->info.msg); + rc = dec_write_log_async_msg(uba, &evt->info.msg, node_id); break; default: break; @@ -979,14 +980,18 @@ static uint32_t mds_rcv(struct ncsmds_ca /* Wait if the mailbox is being reinitialized in the main thread. */ osaf_mutex_lock_ordie(&lgs_mbox_init_mutex); - + evt->evt_type = LGSV_LGS_LGSV_MSG; evt->cb_hdl = (uint32_t)mds_info->i_yr_svc_hdl; evt->fr_node_id = mds_info->info.receive.i_node_id; evt->fr_dest = mds_info->info.receive.i_fr_dest; evt->rcvd_prio = mds_info->info.receive.i_priority; evt->mds_ctxt = mds_info->info.receive.i_msg_ctxt; - + + /* Get node name from MDS */ + memset(evt->node_name, 0, _POSIX_HOST_NAME_MAX); + strncpy(evt->node_name, mds_info->info.receive.i_node_name, _POSIX_HOST_NAME_MAX); + /* for all msg types but WRITEs, sample curr time and store in msg */ if ((type == LGSV_INITIALIZE_REQ) || (type == LGSV_STREAM_OPEN_REQ)) { osaf_clock_gettime(CLOCK_MONOTONIC, &evt->entered_at); diff --git a/tests/logsv/logtest.c b/tests/logsv/logtest.c --- a/tests/logsv/logtest.c +++ b/tests/logsv/logtest.c @@ -44,6 +44,13 @@ SaNameT alarmStreamName = .length = sizeof(SA_LOG_STREAM_ALARM) }; +SaNameT globalConfig = +{ + .value = LOGTST_IMM_LOG_GCFG, + .length = sizeof(LOGTST_IMM_LOG_GCFG) +}; + + SaNameT notificationStreamName = { .value = SA_LOG_STREAM_NOTIFICATION, diff --git a/tests/logsv/logtest.h b/tests/logsv/logtest.h --- a/tests/logsv/logtest.h +++ b/tests/logsv/logtest.h @@ -49,10 +49,12 @@ #define LOGTST_IMM_LOG_CONFIGURATION "logConfig=1,safApp=safLogService" #define LOGTST_IMM_LOG_RUNTIME "logConfig=currentConfig,safApp=safLogService" +#define LOGTST_IMM_LOG_GCFG "opensafConfigId=opensafGlobalConfig,safApp=OpenSAF" extern SaNameT systemStreamName; extern SaNameT alarmStreamName; extern SaNameT notificationStreamName; +extern SaNameT globalConfig; extern SaNameT app1StreamName; extern SaNameT notifyingObject; extern SaNameT notificationObject; diff --git a/tests/logsv/tet_LogOiOps.c b/tests/logsv/tet_LogOiOps.c --- a/tests/logsv/tet_LogOiOps.c +++ b/tests/logsv/tet_LogOiOps.c @@ -3401,6 +3401,209 @@ void verLogFileName(void) rc_validate(WEXITSTATUS(rc), 1); } + +/**************************************** + * These below function(s) are used to test added new tokens @Cq and @Cp: + * @Cp: represents network name. + * @Cq: represent node name. + * + * The test case will do following sequences: + * + * 1. Backup the current `opensafNetworkName` attribute. + * 2. Modify the attribute to a specific name. + * 3. Backup the current `saLogStreamLogFileFormat` + * 4. Modify the attribute by adding new @Cq, @Cp tokens + * 5. Send a log stream + * 6. Check content of log file (*.log) cotaining the node name & network name. + * 7. Restore the modified attributes to previous values + * + ***************************************/ + +/* Commands to search for specific pattern on files having 01 last minute + * (?) accessed, but only openning file. + * + * The flow of execution as below: + * + * 1. Find (linux `find` command) all files in the directory specificed by + * %s (e.g: root_log_path) and subfolders which having 01 last minute accessed + * (e.g: read/write access) or lesser. + * + * 2. With `egrep``, it helps to filter just openning log files + * in list of files found - which have correct format + * <logfilename>_<yyyymmdd>_<hhmmss>.log + * + * 3. With `egrep`, search content in the list of right-format + * found files for a specific pattern. + * (e.g: timezone format = [+-][0-9]{4}, millisecond format = [0-9]{3}) + * + * 4. Don't show found result (if tester wants to see the search result, + * comment final line and its above slash) + * + * Note: If found pattern, exit status of these pipes will be + * EXIT_SUCCESS(0), otherwise EXIT_FAILURE(1)/non-zero(?) + */ +#define VERIFY_CMD_1 "find %s -type f -mmin -1" \ + " | egrep \".*(%s_[0-9]{8}_[0-9]{6})\\.log$\"" \ + " | xargs egrep \" %s \"" \ + " 1> /dev/null" + +/* Search pattern for node name pattern, including prefix for testing */ +#define NODENAME_PATTERN "prefNd_[a-zA-Z0-9,_,-]*" +/* Search pattern for network name pattern, including prefix for testing */ +#define NWNAME_PATTERN "prefNw_Network A" + +/** + * CCB Object Modify saLogStreamLogFileFormat of alarm log stream + * by adding node name token and check if log file are reflected correctly. + */ +void verNodeName_01(void) +{ + int rc; + char command[MAX_DATA]; + char preLogStrFileFmt[MAX_DATA]; + + /* Enable node name token - @Cq */ + const char* modLogStrFileFmt = "@Cr @Ct prefNd_@Cq @Nz @Ne6 @No30 @Ng30 @Cb"; + + /* Get current value of the attribute, use default value if failed */ + rc = get_attr_value(&alarmStreamName, "saLogStreamLogFileFormat", NULL, + preLogStrFileFmt); + if (rc == -1) { + /* Failed, use default one */ + fprintf(stderr, "Failed to get attribute value from IMM\n"); + strncpy(preLogStrFileFmt, DEFAULT_ALM_NOT_FORMAT_EXP, MAX_DATA); + } + + /* Modify the attribute */ + sprintf(command, IMMCFG_CMD, modLogStrFileFmt, SA_LOG_STREAM_ALARM); + rc = system(command); + if (WEXITSTATUS(rc) == 0) { + /* Send an alarm to alarm log stream */ + rc = system("saflogger -l"); + if (WEXITSTATUS(rc)) { + /* Failed to send the alarm to log stream */ + fprintf(stderr, "Failed to invoke saflogger -a\n"); + rc_validate(WEXITSTATUS(rc), 0); + /* Exit the test case */ + return; + } + + /* Verify the content of log file if it is reflected with right format */ + sprintf(command, VERIFY_CMD_1, log_root_path, ALM_LOG_FILE, NODENAME_PATTERN); + rc = system(command); + if (rc == -1) { + fprintf(stderr, "Failed to execute command (%s) on shell\n", + VERIFY_CMD_1); + test_validate(rc, 0); + /* Exit the test case */ + return; + } + /* Command is executed succesfully on the shell, verify the result */ + rc_validate(WEXITSTATUS(rc), 0); + + /* Restore the attribute to previous value */ + sprintf(command, IMMCFG_CMD, preLogStrFileFmt, SA_LOG_STREAM_ALARM); + rc = system(command); + if (WEXITSTATUS(rc) != 0) { + /* Failed to restore to privous value, print message */ + fprintf(stderr, "Failed to restore the attribute to previous value\n"); + } + } else { + rc_validate(WEXITSTATUS(rc), 0); + } +} + +/** + * CCB Object Modify saLogStreamLogFileFormat of alarm log stream + * by adding node name token and check if log file are reflected correctly. + */ +void verNetworkName_01(void) +{ + int rc; + char command[MAX_DATA]; + char preLogStrFileFmt[MAX_DATA]; + char networkName[MAX_DATA]; + + /* Enable network name token - @Cp */ + const char* modLogStrFileFmt = "@Cr @Ct prefNw_@Cp @Nz @Ne6 @No30 @Ng30 @Cb"; + + /* Get current value of the attribute, use default value if failed */ + rc = get_attr_value(&alarmStreamName, "saLogStreamLogFileFormat", NULL, + preLogStrFileFmt); + if (rc == -1) { + /* Failed, use default one */ + fprintf(stderr, "Failed to get attribute value from IMM\n"); + strncpy(preLogStrFileFmt, DEFAULT_ALM_NOT_FORMAT_EXP, MAX_DATA); + } + + /* Get current value of the attribute, use default value if failed */ + rc = get_attr_value(&globalConfig, "opensafNetworkName", NULL, + networkName); + if (rc == -1) { + /* Failed, use default one */ + strncpy(networkName, "", MAX_DATA); + } + + /* Modify attribute network name */ + sprintf(command, "immcfg -a opensafNetworkName=\"Network A\" %s", + LOGTST_IMM_LOG_GCFG); + rc = system(command); + if (WEXITSTATUS(rc)) { + /* Failed to send the alarm to log stream */ + fprintf(stderr, "Failed to invoke command %s\n", command); + rc_validate(WEXITSTATUS(rc), 0); + /* Exit the test case */ + return; + } + + /* Modify the logfileFmt attribute */ + sprintf(command, IMMCFG_CMD, modLogStrFileFmt, SA_LOG_STREAM_ALARM); + rc = system(command); + if (WEXITSTATUS(rc) == 0) { + /* Send an alarm to alarm log stream */ + rc = system("saflogger -l"); + if (WEXITSTATUS(rc)) { + /* Failed to send the alarm to log stream */ + fprintf(stderr, "Failed to invoke saflogger -a\n"); + rc_validate(WEXITSTATUS(rc), 0); + /* Exit the test case */ + return; + } + + /* Verify the content of log file if it is reflected with right format */ + sprintf(command, VERIFY_CMD_1, log_root_path, ALM_LOG_FILE, NWNAME_PATTERN); + rc = system(command); + if (rc == -1) { + fprintf(stderr, "Failed to execute command (%s) on shell\n", + VERIFY_CMD_1); + test_validate(rc, 0); + /* Exit the test case */ + return; + } + /* Command is executed succesfully on the shell, verify the result */ + rc_validate(WEXITSTATUS(rc), 0); + + /* Restore the attribute to previous value */ + sprintf(command, IMMCFG_CMD, preLogStrFileFmt, SA_LOG_STREAM_ALARM); + rc = system(command); + if (WEXITSTATUS(rc) != 0) { + /* Failed to restore to privous value, print message */ + fprintf(stderr, "Failed to restore logFileFmt\n"); + } + + sprintf(command, "immcfg -a opensafNetworkName=%s %s", + networkName, LOGTST_IMM_LOG_GCFG); + rc = system(command); + if (WEXITSTATUS(rc) != 0) { + /* Failed to restore to privous value, print message */ + fprintf(stderr, "Failed to restore opensafNetworkName\n"); + } + + } else { + rc_validate(WEXITSTATUS(rc), 0); + } +} + __attribute__ ((constructor)) static void saOiOperations_constructor(void) { /* Stream objects */ @@ -3467,6 +3670,8 @@ void verLogFileName(void) test_case_add(4, modStrLogFileFmt_03, "CCB Object Modify, saLogstreamLogFileFormat, timezone token (@Cz)"); test_case_add(4, modStrLogFileFmt_04, "CCB Object Modify, saLogstreamLogFileFormat, millisecond token (@Ck)"); test_case_add(4, modStrLogFileFmt_05, "CCB Object Modify, saLogstreamLogFileFormat, timezone & millisecond token (@Cz @Ck)"); + test_case_add(4, verNodeName_01, "CCB Object Modify, saLogStreamLogFileFormat, node name token (@Cq)"); + test_case_add(4, verNetworkName_01, "CCB Object Modify, saLogStreamLogFileFormat, network name token (@Cp)"); test_case_add(4, verDefaultLogFileFmt, "Application stream with default log file format"); /* Configuration object */ ------------------------------------------------------------------------------ Site24x7 APM Insight: Get Deep Visibility into Application Performance APM + Mobile APM + RUM: Monitor 3 App instances at just $35/Month Monitor end-to-end web transactions and take corrective actions now Troubleshoot faster and improve end-user experience. Signup Now! http://pubads.g.doubleclick.net/gampad/clk?id=272487151&iu=/4140 _______________________________________________ Opensaf-devel mailing list Opensaf-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/opensaf-devel