You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
569 lines
16 KiB
569 lines
16 KiB
/*
|
|
* Copyright (c) 2013-2016 Wind River Systems, Inc.
|
|
*
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*
|
|
*/
|
|
|
|
/**
|
|
* @file
|
|
* Wind River CGCS Platform Process Monitor Service Header
|
|
*/
|
|
|
|
#include "pmon.h"
|
|
#include "alarmUtil.h" /* for ... alarmUtil_getSev_str and alarmUtil_query_identity */
|
|
#include "pmonAlarm.h" /* for ... PMON_ALARM_ID__PMOND */
|
|
|
|
/* Process Monitor Configuration File */
|
|
#define CONFIG_FILE ((const char *)"/etc/mtc/pmond.conf")
|
|
|
|
/* Process Monitor Control Structure */
|
|
static pmon_ctrl_type pmon_ctrl ;
|
|
pmon_ctrl_type * get_ctrl_ptr ( void ) { return (&pmon_ctrl); }
|
|
|
|
|
|
/** Daemon Configuration Structure
|
|
* - Allocation and get pointer
|
|
* @see daemon_common.h for daemon_config_type struct format. */
|
|
static daemon_config_type pmon_config ;
|
|
daemon_config_type * daemon_get_cfg_ptr () { return &pmon_config ; }
|
|
|
|
/* Cleanup exit handler */
|
|
void daemon_exit ( void )
|
|
{
|
|
pmon_msg_fini ();
|
|
pmon_hdlr_fini ( &pmon_ctrl );
|
|
daemon_files_fini ();
|
|
daemon_dump_info ();
|
|
exit (0);
|
|
}
|
|
|
|
|
|
/* Startup config read */
|
|
static int pmon_config_handler ( void * user,
|
|
const char * section,
|
|
const char * name,
|
|
const char * value)
|
|
{
|
|
daemon_config_type* config_ptr = (daemon_config_type*)user;
|
|
|
|
if (MATCH("config", "audit_period"))
|
|
{
|
|
config_ptr->audit_period = atoi(value);
|
|
config_ptr->mask |= CONFIG_AUDIT_PERIOD ;
|
|
}
|
|
else if (MATCH("config", "pmon_cmd_port"))
|
|
{
|
|
config_ptr->pmon_cmd_port = atoi(value);
|
|
config_ptr->mask |= CONFIG_CMD_PORT ;
|
|
}
|
|
else if (MATCH("config", "pmon_event_port"))
|
|
{
|
|
config_ptr->pmon_event_port = atoi(value);
|
|
config_ptr->mask |= CONFIG_TX_PORT ;
|
|
}
|
|
else if (MATCH("config", "pmon_amon_port"))
|
|
{
|
|
config_ptr->pmon_amon_port = atoi(value);
|
|
config_ptr->mask |= CONFIG_RX_PORT ;
|
|
}
|
|
else if (MATCH("config", "pmon_pulse_port"))
|
|
{
|
|
config_ptr->pmon_pulse_port = atoi(value);
|
|
config_ptr->mask |= CONFIG_PULSE_PORT ;
|
|
}
|
|
else if (MATCH("config", "audit_period"))
|
|
{
|
|
config_ptr->audit_period = atoi(value);
|
|
config_ptr->mask |= CONFIG_AUDIT_PERIOD ;
|
|
}
|
|
else if (MATCH("config", "hostwd_update_period"))
|
|
{
|
|
config_ptr->hostwd_update_period = atoi(value);
|
|
config_ptr->mask |= CONFIG_HOSTWD_PERIOD ;
|
|
}
|
|
else if (MATCH("timeouts", "start_delay"))
|
|
{
|
|
config_ptr->start_delay = atoi(value);
|
|
config_ptr->mask |= CONFIG_START_DELAY ;
|
|
}
|
|
return (PASS);
|
|
}
|
|
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* Name : pmon_load_config
|
|
*
|
|
* Purpose : Read process config file settings into the daemon configuration
|
|
*
|
|
*****************************************************************************/
|
|
int pmon_process_config ( void * user,
|
|
const char * section,
|
|
const char * name,
|
|
const char * value)
|
|
{
|
|
int rc = FAIL ;
|
|
process_config_type * ptr = (process_config_type*)user;
|
|
|
|
if (MATCH("process", "process"))
|
|
{
|
|
ptr->mask |= CONF_PROCESS ;
|
|
ptr->status_mask |= CONF_PROCESS ;
|
|
ptr->process = strdup(value);
|
|
dlog1 ("Process : %s\n", ptr->process );
|
|
rc = PASS ;
|
|
}
|
|
if (MATCH("process", "service"))
|
|
{
|
|
ptr->mask |= CONF_RECOVERY ;
|
|
ptr->service = strdup(value);
|
|
dlog1 ("Service : %s\n", ptr->service );
|
|
rc = PASS ;
|
|
}
|
|
else if (MATCH("process", "script"))
|
|
{
|
|
ptr->mask |= CONF_RECOVERY ;
|
|
ptr->status_mask |= CONF_RECOVERY ;
|
|
ptr->script = strdup(value);
|
|
dlog1 ("Script : %s\n", ptr->script );
|
|
}
|
|
else if (MATCH("process", "style"))
|
|
{
|
|
ptr->mask |= CONF_STYLE ;
|
|
ptr->status_mask |= CONF_STYLE ;
|
|
ptr->style = strdup(value);
|
|
dlog1 ("Style : %s\n", ptr->style );
|
|
rc = PASS ;
|
|
}
|
|
else if (MATCH("process", "pidfile"))
|
|
{
|
|
ptr->mask |= CONF_PIDFILE ;
|
|
ptr->pidfile = strdup(value);
|
|
dlog1 ("Pid File : %s\n", ptr->pidfile );
|
|
rc = PASS ;
|
|
}
|
|
else if (MATCH("process", "severity"))
|
|
{
|
|
ptr->mask |= CONF_SEVERITY ;
|
|
ptr->status_mask |= CONF_SEVERITY ;
|
|
ptr->severity = strdup(value);
|
|
dlog1 ("Severity : %s\n", ptr->severity );
|
|
rc = PASS ;
|
|
}
|
|
else if (MATCH("process", "restarts"))
|
|
{
|
|
ptr->mask |= CONF_RESTARTS ;
|
|
ptr->status_mask |= CONF_RESTARTS ;
|
|
ptr->restarts = atoi(value);
|
|
dlog1 ("Restarts : %d\n", ptr->restarts );
|
|
rc = PASS ;
|
|
}
|
|
else if (MATCH("process", "interval"))
|
|
{
|
|
ptr->mask |= CONF_INTERVAL ;
|
|
ptr->status_mask |= CONF_INTERVAL ;
|
|
ptr->interval = atoi(value);
|
|
dlog1 ("Interval : %d\n", ptr->interval );
|
|
rc = PASS ;
|
|
}
|
|
else if (MATCH("process", "debounce"))
|
|
{
|
|
ptr->mask |= CONF_DEBOUNCE ;
|
|
ptr->debounce = atoi(value);
|
|
dlog1 ("Debounce : %d\n", ptr->debounce );
|
|
rc = PASS ;
|
|
}
|
|
else if (MATCH("process", "startuptime"))
|
|
{
|
|
ptr->startuptime = atoi(value);
|
|
dlog1 ("Debounce : %d\n", ptr->startuptime );
|
|
rc = PASS ;
|
|
}
|
|
else if (MATCH("process", "subfunction"))
|
|
{
|
|
ptr->subfunction = strdup(value);
|
|
dlog1 ("Subfunction: %s\n", ptr->subfunction );
|
|
rc = PASS ;
|
|
}
|
|
|
|
else if (MATCH("process", "mode"))
|
|
{
|
|
// ptr->mask |= CONF_MODE ;
|
|
ptr->mode = strdup(value);
|
|
if (( strcmp(ptr->mode, "active" )) &&
|
|
( strcmp(ptr->mode, "passive" )) &&
|
|
( strcmp(ptr->mode, "status" )))
|
|
{
|
|
ptr->ignore = true ;
|
|
dlog1 ("Mode : ignore\n");
|
|
}
|
|
else
|
|
{
|
|
dlog1 ("Mode : %s\n", ptr->mode );
|
|
}
|
|
rc = PASS ;
|
|
}
|
|
else if (MATCH("process", "quorum"))
|
|
{
|
|
if (atoi(value) > 0)
|
|
{
|
|
ptr->quorum = true;
|
|
}
|
|
dlog1 ("Quorum : %d\n", (int) ptr->quorum );
|
|
rc = PASS ;
|
|
}
|
|
else if (MATCH("process", "full_init_reqd"))
|
|
{
|
|
if (atoi(value) > 0)
|
|
{
|
|
ptr->full_init_reqd = true;
|
|
}
|
|
dlog1 ("Full_init_reqd : %d\n", (int) ptr->full_init_reqd );
|
|
rc = PASS ;
|
|
}
|
|
if (( ptr->mode != NULL ) && ( !strcmp(ptr->mode, "active" )))
|
|
{
|
|
if (MATCH("process", "port"))
|
|
{
|
|
ptr->amask |= CONF_PORT ;
|
|
ptr->port = atoi(value);
|
|
dlog1 ("Active Port: %d\n", ptr->port );
|
|
rc = PASS ;
|
|
}
|
|
if (MATCH("process", "period"))
|
|
{
|
|
ptr->amask |= CONF_PERIOD ;
|
|
ptr->period = atoi(value);
|
|
dlog1 ("Period : %d\n", ptr->period );
|
|
rc = PASS ;
|
|
}
|
|
else if (MATCH("process", "timeout"))
|
|
{
|
|
ptr->amask |= CONF_TIMEOUT ;
|
|
ptr->timeout = atoi(value);
|
|
dlog1 ("Timeout : %d\n", ptr->timeout );
|
|
rc = PASS ;
|
|
}
|
|
else if (MATCH("process", "threshold"))
|
|
{
|
|
ptr->amask |= CONF_THRESHOLD ;
|
|
ptr->threshold = atoi(value);
|
|
dlog1 ("Threshold : %d\n", ptr->threshold );
|
|
rc = PASS ;
|
|
}
|
|
}
|
|
|
|
if (( ptr->mode != NULL ) && ( !strcmp(ptr->mode, "status" )))
|
|
{
|
|
if (MATCH("process", "period"))
|
|
{
|
|
ptr->status_mask |= CONF_PERIOD ;
|
|
ptr->period = atoi(value);
|
|
dlog1 ("Period : %d\n", ptr->period );
|
|
rc = PASS ;
|
|
}
|
|
else if (MATCH("process", "timeout"))
|
|
{
|
|
ptr->status_mask |= CONF_TIMEOUT ;
|
|
ptr->timeout = atoi(value);
|
|
dlog1 ("Timeout : %d\n", ptr->timeout );
|
|
rc = PASS ;
|
|
}
|
|
else if (MATCH("process", "status_arg"))
|
|
{
|
|
ptr->status_mask |= CONF_STATUS_ARG ;
|
|
ptr->status_arg = strdup(value);
|
|
dlog1 ("status script argument : %s\n", ptr->status_arg );
|
|
rc = PASS ;
|
|
}
|
|
else if (MATCH("process", "start_arg"))
|
|
{
|
|
ptr->status_mask |= CONF_START_ARG ;
|
|
ptr->start_arg = strdup(value);
|
|
dlog1 ("start script argument : %s\n", ptr->start_arg );
|
|
rc = PASS ;
|
|
}
|
|
else if (MATCH("process", "status_failure_text"))
|
|
{
|
|
ptr->status_failure_text_file = strdup(value);
|
|
dlog1 ("Status error text file : %s\n", ptr->status_failure_text_file);
|
|
rc = PASS ;
|
|
}
|
|
}
|
|
|
|
else
|
|
rc = PASS ;
|
|
|
|
return (rc);
|
|
}
|
|
|
|
/*****************************************************************************
|
|
*
|
|
* Name : daemon_configure
|
|
*
|
|
* Purpose : Read process config file settings into the daemon configuration
|
|
*
|
|
*****************************************************************************/
|
|
int daemon_configure ( void )
|
|
{
|
|
int rc = PASS ;
|
|
|
|
if (ini_parse( CONFIG_FILE, pmon_config_handler, &pmon_config) < 0)
|
|
{
|
|
elog("Can't load '%s'\n", CONFIG_FILE );
|
|
}
|
|
|
|
get_debug_options ( CONFIG_FILE, &pmon_config );
|
|
|
|
/* Verify loaded config against an expected mask
|
|
* as an ini file fault detection method */
|
|
if ( pmon_config.mask != CONFIG_MASK )
|
|
{
|
|
elog ("Error: Agent configuration failed (%x)\n",
|
|
((-1 ^ pmon_config.mask) & CONFIG_MASK));
|
|
return (FAIL_INI_CONFIG);
|
|
}
|
|
|
|
/* This ensures any link aggregation interface overrides the physical */
|
|
pmon_config.mgmnt_iface = daemon_get_iface_master ( pmon_config.mgmnt_iface );
|
|
|
|
/* Log the startup settings */
|
|
ilog("Interface : %s\n", pmon_config.mgmnt_iface );
|
|
ilog("Event Port : %d\n", pmon_config.pmon_event_port );
|
|
|
|
get_iface_macaddr ( pmon_config.mgmnt_iface, pmon_ctrl.my_macaddr );
|
|
get_iface_address ( pmon_config.mgmnt_iface, pmon_ctrl.my_address, true );
|
|
get_hostname (&pmon_ctrl.my_hostname[0], MAX_HOST_NAME_SIZE );
|
|
|
|
/* Manage the daemon pulse period setting - ensure in bound values */
|
|
if ( pmon_config.audit_period < PMON_MIN_AUDIT_PERIOD )
|
|
{
|
|
wlog ("Pulse Period: %d msecs (rounded up)\n",
|
|
PMON_MIN_AUDIT_PERIOD );
|
|
pmon_ctrl.pulse_period = PMON_MIN_AUDIT_PERIOD ;
|
|
}
|
|
else if ( pmon_config.audit_period > PMON_MAX_AUDIT_PERIOD )
|
|
{
|
|
wlog ("Pulse Period: %d msecs (rounded down)\n",
|
|
PMON_MAX_AUDIT_PERIOD );
|
|
pmon_ctrl.pulse_period = PMON_MAX_AUDIT_PERIOD ;
|
|
}
|
|
else
|
|
{
|
|
pmon_ctrl.pulse_period = pmon_config.audit_period ;
|
|
ilog("Pulse Period: %d\n", pmon_ctrl.pulse_period );
|
|
}
|
|
|
|
/* Manage the daemon pulse period setting - ensure in bound values */
|
|
if ( pmon_config.start_delay < PMON_MIN_START_DELAY )
|
|
{
|
|
wlog ("Start Delay : %d msecs (rounded up)\n",
|
|
PMON_MIN_AUDIT_PERIOD );
|
|
pmon_config.start_delay = PMON_MIN_START_DELAY ;
|
|
}
|
|
else if ( pmon_config.start_delay > PMON_MAX_START_DELAY )
|
|
{
|
|
wlog ("Start Delay : %d msecs (rounded down)\n",
|
|
PMON_MAX_AUDIT_PERIOD );
|
|
pmon_config.start_delay = PMON_MAX_START_DELAY ;
|
|
}
|
|
else
|
|
{
|
|
ilog("Start Delay : %d\n", pmon_config.start_delay );
|
|
}
|
|
|
|
if ( (rc = pmon_hdlr_init (&pmon_ctrl)) != PASS )
|
|
{
|
|
elog ("pmon_hdlt_init failed\n");
|
|
rc = FAIL_HDLR_INIT ;
|
|
}
|
|
ilog ("Function : %d\n", pmon_ctrl.function );
|
|
ilog ("SubFunction : %d\n", pmon_ctrl.subfunction );
|
|
|
|
pmon_ctrl.reload_config = true ;
|
|
pmon_ctrl.patching_in_progress = false ;
|
|
|
|
return (rc);
|
|
}
|
|
|
|
|
|
/****************************/
|
|
/* Initialization Utilities */
|
|
/****************************/
|
|
|
|
/* Setup the daemon messaging interfaces/sockets */
|
|
int socket_init ( void )
|
|
{
|
|
pmon_msg_init ( );
|
|
|
|
/* Setup the pmon event port.
|
|
* This is the port that pmon sends events
|
|
* to maintenance on */
|
|
int rc = event_port_init ( pmon_config.mgmnt_iface ,
|
|
pmon_config.pmon_event_port );
|
|
|
|
/* Setup the pmon autonomout pulse port.
|
|
* This is the port that pmon sends i'm alive messages
|
|
* to the hbsClient - the watcher of the watcher */
|
|
if ( rc == PASS )
|
|
{
|
|
rc = pulse_port_init ( );
|
|
}
|
|
|
|
/* Init the avtive monitor receive port.
|
|
* This is the port that all active monitored
|
|
* processes send their responses on */
|
|
if ( rc == PASS )
|
|
{
|
|
rc = amon_port_init ( pmon_config.pmon_amon_port );
|
|
}
|
|
|
|
/* Setup the pmon hostwd connection.
|
|
* This lets pmon commuicate essential process info to the
|
|
* host watchdog process */
|
|
if ( rc == PASS )
|
|
{
|
|
hostwd_port_init ( );
|
|
}
|
|
|
|
pmon_inbox_init ( );
|
|
|
|
return (rc);
|
|
}
|
|
|
|
/* The main heartbeat service loop */
|
|
int daemon_init ( string iface, string nodetype_str )
|
|
{
|
|
int rc = PASS ;
|
|
|
|
/* init the control struct */
|
|
memset ( &pmon_ctrl.my_hostname[0], 0, sizeof(pmon_ctrl.my_hostname));
|
|
pmon_ctrl.my_macaddr = "" ;
|
|
pmon_ctrl.my_address = "" ;
|
|
pmon_ctrl.pulse_period = PMON_MAX_AUDIT_PERIOD ;
|
|
pmon_ctrl.processes = 0 ;
|
|
pmon_ctrl.system_type = daemon_system_type ();
|
|
|
|
/* sets in pmonHdlr.cpp */
|
|
pmon_set_ctrl_ptr ( &pmon_ctrl );
|
|
|
|
pmonAlarm_init ();
|
|
|
|
/* Assign interface to config */
|
|
pmon_config.mgmnt_iface = (char*)iface.data() ;
|
|
|
|
if ( daemon_files_init ( ) != PASS )
|
|
{
|
|
elog ("Pid, log or other files could not be opened\n");
|
|
return ( FAIL_FILES_INIT ) ;
|
|
}
|
|
|
|
/* Bind signal handlers */
|
|
if ( daemon_signal_init () != PASS )
|
|
{
|
|
elog ("daemon_signal_init failed\n");
|
|
return ( FAIL_SIGNAL_INIT );
|
|
}
|
|
|
|
if ( set_host_functions ( nodetype_str, &pmon_ctrl.nodetype, &pmon_ctrl.function, &pmon_ctrl.subfunction ) != PASS )
|
|
{
|
|
elog ("failed to extract nodetype\n");
|
|
return ( FAIL_NODETYPE );
|
|
}
|
|
|
|
/************************************************************************
|
|
* There is no point continuing with init ; i.e. running daemon_configure,
|
|
* initializing sockets and trying to query for an ip address until the
|
|
* daemon's configuration requirements are met. Here we wait for those
|
|
* flag files to be present before continuing.
|
|
************************************************************************
|
|
* Wait for /etc/platform/.initial_config_complete & /var/run/.goenabled */
|
|
daemon_wait_for_file ( CONFIG_COMPLETE_FILE , 0);
|
|
daemon_wait_for_file ( GOENABLED_MAIN_READY , 0);
|
|
|
|
/* Configure the daemon */
|
|
if ( (rc = daemon_configure ( )) != PASS )
|
|
{
|
|
elog ("Daemon service configuration failed (rc:%i)\n", rc );
|
|
rc = FAIL_DAEMON_CONFIG ;
|
|
}
|
|
|
|
/* Setup the messaging sockets */
|
|
else if ( (rc = socket_init ( )) != PASS )
|
|
{
|
|
elog ("socket initialization failed (rc:%d)\n", rc );
|
|
rc = FAIL_SOCKET_INIT ;
|
|
}
|
|
else
|
|
{
|
|
/* Init the pmon service timers */
|
|
pmon_timer_init ();
|
|
}
|
|
|
|
pmon_ctrl.recovery_method = PMOND_RECOVERY_METHOD__SYSTEMD ;
|
|
pmon_ctrl.system_state = get_system_state();
|
|
ilog ("Recovery Method: %s\n", pmon_ctrl.recovery_method ? "systemd via systemctl" : "sysvinit via script" );
|
|
return (rc);
|
|
}
|
|
|
|
/* Start the service
|
|
*
|
|
* 1. Wait for host config (install) complete
|
|
* 2. Wait for goenable
|
|
* 3. Do startup delay
|
|
* 4. run the pmon service inside pmonHdlr.cpp
|
|
*
|
|
*/
|
|
void daemon_service_run ( void )
|
|
{
|
|
int rc = PASS ;
|
|
|
|
process_config_type dummy_process ;
|
|
memset ( (char*)&dummy_process, 0, (sizeof(process_config_type)));
|
|
dummy_process.process = strdup("pmond");
|
|
|
|
ilog ("Transmitting: 'monitor ready event'\n" );
|
|
do
|
|
{
|
|
rc = pmon_send_event ( MTC_EVENT_MONITOR_READY, &dummy_process ) ;
|
|
if ( rc == RETRY )
|
|
{
|
|
mtcWait_secs ( 2 );
|
|
}
|
|
if ( rc == FAIL )
|
|
{
|
|
elog ("Failed to Send READY event (rc=%d)\n", rc );
|
|
elog ("Trying to provide service anyway\n");
|
|
}
|
|
} while ( rc == RETRY ) ;
|
|
|
|
/* Wait a few seconds after go enabled to
|
|
* allow the rest of init to finish before
|
|
* starting to process monitor */
|
|
ilog ("Delaying %d seconds to allow other processes to start\n", pmon_config.start_delay);
|
|
for ( int i = 0 ; i < pmon_config.start_delay ; i++ )
|
|
{
|
|
mtcWait_secs ( 1 );
|
|
pmon_send_pulse ( );
|
|
}
|
|
|
|
pmon_service ( &pmon_ctrl );
|
|
daemon_exit ();
|
|
}
|
|
|
|
|
|
|
|
const char MY_DATA [100] = { "eieio\n" } ;
|
|
const char * daemon_stream_info ( void )
|
|
{
|
|
return (&MY_DATA[0]);
|
|
}
|
|
|
|
/** Teat Head Entry */
|
|
int daemon_run_testhead ( void )
|
|
{
|
|
ilog ("Empty test head.\n");
|
|
return (PASS);
|
|
}
|