e0d9d60d28
The AIO (All-In-One) inactive controller is failed by maintenance in a DOR (Dead-Office-Recovery) situation ; power off then power on of the system. This update scales the AIO DOR timeout to accomodate for the extra time needed for the compute function manifest to apply. Change-Id: I3006060fe04285881f95d2084cada40ec1002d1c Signed-off-by: Eric MacDonald <eric.macdonald@windriver.com>
1541 lines
52 KiB
C++
Executable File
1541 lines
52 KiB
C++
Executable File
/*
|
|
* Copyright (c) 2013, 2016 Wind River Systems, Inc.
|
|
*
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*
|
|
*/
|
|
|
|
/**
|
|
* @file
|
|
* Wind River CGTS Platform Controller Maintenance Daemon
|
|
*/
|
|
|
|
#include <sys/types.h>
|
|
#include <sys/socket.h>
|
|
#include <sys/un.h>
|
|
#include <netinet/in.h>
|
|
#include <arpa/inet.h>
|
|
#include <sys/ioctl.h>
|
|
#include <net/if.h>
|
|
#include <netdb.h> /* for hostent */
|
|
#include <iostream>
|
|
#include <fcntl.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <errno.h>
|
|
#include <unistd.h> /* for ... close and usleep */
|
|
#include <evhttp.h> /* for ... HTTP_ status definitions */
|
|
#include <linux/rtnetlink.h> /* for ... RTMGRP_LINK */
|
|
|
|
using namespace std;
|
|
|
|
#ifdef __AREA__
|
|
#undef __AREA__
|
|
#endif
|
|
#define __AREA__ "mtc"
|
|
|
|
#include "daemon_common.h" /* */
|
|
#include "daemon_ini.h" /* Init parset header */
|
|
#include "daemon_option.h" /* */
|
|
|
|
#include "nodeBase.h" /* Service header */
|
|
#include "nodeTimers.h" /* */
|
|
#include "nodeClass.h" /* */
|
|
#include "nodeUtil.h" /* */
|
|
#include "threadUtil.h" /* for ... threadUtil_init/fini */
|
|
#include "timeUtil.h" /* for ... daemon_sample_time_init */
|
|
#include "tokenUtil.h" /* for ... keystone_config_handler */
|
|
#include "nodeMacro.h" /* for ... CREATE_REUSABLE_INET_UDP_TX_SOCKET */
|
|
#include "nodeEvent.h" /* for ... inotify utility services */
|
|
#include "mtcNodeFsm.h" /* */
|
|
#include "mtcNodeMsg.h" /* */
|
|
#include "mtcHttpSvr.h" /* for ... mtcHttpSvr_init/_fini/_look */
|
|
#include "mtcInvApi.h" /* */
|
|
#include "mtcSmgrApi.h" /* */
|
|
#include "nlEvent.h" /* for ... open_netlink_socket */
|
|
|
|
/**************************************************************
|
|
* Implementation Structure
|
|
**************************************************************
|
|
*
|
|
* Call sequence:
|
|
*
|
|
* daemon_init
|
|
* daemon_configure
|
|
* daemon_signal_init
|
|
* mtc_hostname_read
|
|
* mtc_message_init (obsolete ?)
|
|
* mtc_socket_init
|
|
*
|
|
* daemon_service_run
|
|
* forever ( timer_handler )
|
|
* mtc_fsm_run
|
|
* mtc_service_inbox
|
|
*
|
|
*/
|
|
|
|
extern void mtcTimer_handler ( int sig, siginfo_t *si, void *uc);
|
|
extern int service_events ( nodeLinkClass * obj_ptr,
|
|
mtc_socket_type * sock_ptr );
|
|
extern bool mtc_get_inventory_in_progress ( void );
|
|
|
|
int mtc_service_inbox ( nodeLinkClass * obj_ptr,
|
|
mtc_socket_type * sock_ptr,
|
|
int interface );
|
|
|
|
string my_hostname = "" ;
|
|
|
|
/** Instanciate the NodeLinkClass and pointer to it */
|
|
nodeLinkClass mtcInv ;
|
|
nodeLinkClass * mtcInv_ptr ;
|
|
nodeLinkClass * get_mtcInv_ptr ( void )
|
|
{
|
|
return (&mtcInv);
|
|
}
|
|
|
|
static event_type mtce_event ;
|
|
event_type * get_eventPtr ( void )
|
|
{
|
|
return(&mtce_event);
|
|
}
|
|
|
|
int module_init ( void )
|
|
{
|
|
mtcInv_ptr = &mtcInv ;
|
|
return (PASS);
|
|
}
|
|
|
|
void daemon_sigchld_hdlr ( void )
|
|
{
|
|
; /* dlog("Received SIGCHLD ... no action\n"); */
|
|
}
|
|
|
|
/**
|
|
* Daemon Configuration Structure - The allocated struct
|
|
* @see mtc.h for daemon_config_type struct format.
|
|
*/
|
|
static daemon_config_type mtc_config ;
|
|
daemon_config_type * daemon_get_cfg_ptr ( void ) { return &mtc_config ; }
|
|
|
|
|
|
/**
|
|
* Heartbeat Daemon Messaging Socket Control Struct - The allocated struct
|
|
* @see bhs.h for mtc_socket_type struct format.
|
|
*/
|
|
static mtc_socket_type mtc_sock ;
|
|
static mtc_socket_type * sock_ptr ;
|
|
mtc_socket_type * get_sockPtr ( void )
|
|
{ return ( &mtc_sock ) ; }
|
|
|
|
msgSock_type * get_mtclogd_sockPtr ( void )
|
|
{
|
|
return (&mtc_sock.mtclogd);
|
|
}
|
|
|
|
void daemon_exit ( void )
|
|
{
|
|
/* Cancel the uptime timer */
|
|
if ( mtcInv.mtcTimer_uptime.tid )
|
|
{
|
|
mtcTimer_stop ( mtcInv.mtcTimer_uptime );
|
|
}
|
|
|
|
daemon_dump_info ();
|
|
daemon_files_fini ();
|
|
|
|
/* Close the watch over the /etc/shadow file */
|
|
set_inotify_close ( mtcInv.inotify_shadow_file_fd,
|
|
mtcInv.inotify_shadow_file_wd);
|
|
|
|
/* Close open sockets */
|
|
if (mtc_sock.mtc_agent_rx_socket)
|
|
delete (mtc_sock.mtc_agent_rx_socket);
|
|
|
|
if (mtc_sock.mtc_agent_tx_socket)
|
|
delete (mtc_sock.mtc_agent_tx_socket);
|
|
|
|
if (mtc_sock.mtc_client_rx_socket)
|
|
delete(mtc_sock.mtc_client_rx_socket);
|
|
|
|
if (mtc_sock.mtc_client_tx_socket)
|
|
delete (mtc_sock.mtc_client_tx_socket);
|
|
|
|
if (mtc_sock.mtc_client_infra_rx_socket)
|
|
delete (mtc_sock.mtc_client_infra_rx_socket);
|
|
|
|
if (mtc_sock.mtc_client_infra_tx_socket)
|
|
delete (mtc_sock.mtc_client_infra_tx_socket);
|
|
|
|
if (mtc_sock.mtc_event_rx_sock)
|
|
delete (mtc_sock.mtc_event_rx_sock);
|
|
|
|
if (mtc_sock.mtc_to_hbs_sock)
|
|
delete (mtc_sock.mtc_to_hbs_sock);
|
|
|
|
if ( mtc_sock.mtclogd.sock > 0 )
|
|
close (mtc_sock.mtclogd.sock);
|
|
|
|
if ( mtc_sock.netlink_sock > 0 )
|
|
close (mtc_sock.netlink_sock);
|
|
|
|
if ( mtc_sock.ioctl_sock > 0 )
|
|
close (mtc_sock.ioctl_sock);
|
|
|
|
mtcHttpSvr_fini ( mtce_event );
|
|
|
|
threadUtil_fini () ;
|
|
|
|
exit (0) ;
|
|
}
|
|
|
|
|
|
/** Control Config Mask */
|
|
#define CONFIG_AGENT_MASK (CONFIG_AGENT_PORT |\
|
|
CONFIG_MTC_TO_HBS_CMD_PORT |\
|
|
CONFIG_MTC_TO_HWMON_CMD_PORT |\
|
|
CONFIG_HBS_TO_MTC_EVENT_PORT |\
|
|
CONFIG_AGENT_HA_PORT |\
|
|
CONFIG_AGENT_KEY_PORT |\
|
|
CONFIG_AGENT_TOKEN_REFRESH |\
|
|
CONFIG_AGENT_LOC_TIMEOUT |\
|
|
CONFIG_AGENT_INV_EVENT_PORT |\
|
|
CONFIG_AGENT_API_RETRIES |\
|
|
CONFIG_CLIENT_PORT)
|
|
|
|
static int mtc_nfvi_handler ( void * user,
|
|
const char * section,
|
|
const char * name,
|
|
const char * value)
|
|
{
|
|
daemon_config_type* config_ptr = (daemon_config_type*)user;
|
|
|
|
if (MATCH("infrastructure-rest-api", "port"))
|
|
{
|
|
config_ptr->vim_cmd_port = atoi(value);
|
|
}
|
|
else
|
|
{
|
|
return (PASS);
|
|
}
|
|
return (FAIL);
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Startup config read */
|
|
static int mtc_config_handler ( void * user,
|
|
const char * section,
|
|
const char * name,
|
|
const char * value)
|
|
{
|
|
daemon_config_type* config_ptr = (daemon_config_type*)user;
|
|
|
|
if (MATCH("agent", "ha_port"))
|
|
{
|
|
config_ptr->ha_port = atoi(value);
|
|
config_ptr->mask |= CONFIG_AGENT_HA_PORT ;
|
|
}
|
|
|
|
else if (MATCH("agent", "inv_event_port"))
|
|
{
|
|
config_ptr->inv_event_port = atoi(value);
|
|
config_ptr->mask |= CONFIG_AGENT_INV_EVENT_PORT ;
|
|
}
|
|
|
|
else if (MATCH("agent", "keystone_port"))
|
|
{
|
|
config_ptr->keystone_port = atoi(value);
|
|
config_ptr->mask |= CONFIG_AGENT_KEY_PORT ;
|
|
}
|
|
|
|
else if (MATCH("agent", "mtc_agent_port"))
|
|
{
|
|
config_ptr->mtc_agent_port = atoi(value);
|
|
config_ptr->mask |= CONFIG_AGENT_PORT ;
|
|
}
|
|
else if (MATCH("agent", "mtc_to_hbs_cmd_port"))
|
|
{
|
|
config_ptr->mtc_to_hbs_cmd_port = atoi(value);
|
|
config_ptr->mask |= CONFIG_MTC_TO_HBS_CMD_PORT ;
|
|
}
|
|
else if (MATCH("agent", "mtc_to_guest_cmd_port"))
|
|
{
|
|
config_ptr->mtc_to_guest_cmd_port = atoi(value);
|
|
// config_ptr->mask |= CONFIG_MTC_TO_GUEST_CMD_PORT ;
|
|
}
|
|
else if (MATCH("agent", "hbs_to_mtc_event_port"))
|
|
{
|
|
config_ptr->hbs_to_mtc_event_port = atoi(value);
|
|
config_ptr->mask |= CONFIG_HBS_TO_MTC_EVENT_PORT ;
|
|
}
|
|
else if (MATCH("client", "hwmon_cmd_port"))
|
|
{
|
|
config_ptr->hwmon_cmd_port = atoi(value);
|
|
config_ptr->mask |= CONFIG_MTC_TO_HWMON_CMD_PORT ;
|
|
}
|
|
else if (MATCH("client", "daemon_log_port"))
|
|
{
|
|
config_ptr->daemon_log_port = atoi(value);
|
|
}
|
|
else if (MATCH("client", "mtc_rx_mgmnt_port"))
|
|
{
|
|
config_ptr->cmd_port = atoi(value);
|
|
config_ptr->mask |= CONFIG_CLIENT_PORT ;
|
|
}
|
|
else if (MATCH("agent", "token_refresh_rate"))
|
|
{
|
|
config_ptr->token_refresh_rate = atoi(value);
|
|
config_ptr->mask |= CONFIG_AGENT_TOKEN_REFRESH ;
|
|
}
|
|
else if (MATCH("agent", "api_retries"))
|
|
{
|
|
config_ptr->api_retries = atoi(value);
|
|
config_ptr->mask |= CONFIG_AGENT_API_RETRIES ;
|
|
mtcInv.api_retries = config_ptr->api_retries ;
|
|
}
|
|
else if (MATCH("agent", "mnfa_threshold_type"))
|
|
{
|
|
config_ptr->mnfa_threshold_type = strdup(value);
|
|
}
|
|
else if (MATCH("agent", "mnfa_threshold_percent"))
|
|
{
|
|
config_ptr->mnfa_threshold_percent = atoi(value);
|
|
}
|
|
else if (MATCH("agent", "mnfa_threshold_number"))
|
|
{
|
|
config_ptr->mnfa_threshold_number = atoi(value);
|
|
}
|
|
else if (MATCH("timeouts", "failsafe_shutdown_delay"))
|
|
{
|
|
config_ptr->failsafe_shutdown_delay = atoi(value);
|
|
ilog ("Shutdown TO : %d secs\n", config_ptr->failsafe_shutdown_delay );
|
|
}
|
|
else if (MATCH("agent", "autorecovery_threshold"))
|
|
{
|
|
config_ptr->autorecovery_threshold = atoi(value);
|
|
ilog ("AR Threshold: %d\n",
|
|
config_ptr->autorecovery_threshold );
|
|
}
|
|
else if (MATCH("agent", "offline_period"))
|
|
{
|
|
mtcInv.offline_period = atoi(value);
|
|
ilog ("OfflineAudit: %d msecs\n", mtcInv.offline_period );
|
|
}
|
|
else if (MATCH("agent", "offline_threshold"))
|
|
{
|
|
mtcInv.offline_threshold = atoi(value);
|
|
ilog ("OfflineThrsh: %d\n", mtcInv.offline_threshold );
|
|
}
|
|
else
|
|
{
|
|
return (PASS);
|
|
}
|
|
return (FAIL);
|
|
}
|
|
|
|
/* Read and process mtc.ini file settings into the daemon configuration */
|
|
int daemon_configure ( void )
|
|
{
|
|
int rc = PASS ;
|
|
|
|
timeUtil_sched_init ( );
|
|
|
|
/* Read the ini */
|
|
mtc_config.mask = 0 ;
|
|
if (ini_parse(MTCE_CONF_FILE, mtc_config_handler, &mtc_config) < 0)
|
|
{
|
|
elog ("Can't load '%s'\n", MTCE_CONF_FILE );
|
|
return (FAIL_LOAD_INI);
|
|
}
|
|
|
|
if (ini_parse(MTCE_INI_FILE, keystone_config_handler, &mtc_config) < 0)
|
|
{
|
|
elog ("Can't load '%s'\n", MTCE_INI_FILE );
|
|
return (FAIL_LOAD_INI);
|
|
}
|
|
|
|
if (ini_parse(NFVI_PLUGIN_CFG_FILE, mtc_nfvi_handler, &mtc_config) < 0)
|
|
{
|
|
elog ("Can't load '%s'\n", NFVI_PLUGIN_CFG_FILE );
|
|
return (FAIL_LOAD_INI);
|
|
}
|
|
|
|
if (ini_parse(SYSINV_CFG_FILE, sysinv_config_handler, &mtc_config) < 0)
|
|
{
|
|
elog ("Can't load '%s'\n", SYSINV_CFG_FILE );
|
|
return (FAIL_LOAD_INI);
|
|
}
|
|
|
|
/* Loads key Mtce debug values that can override the defaults */
|
|
if (ini_parse(MTCE_CONF_FILE, debug_config_handler, &mtc_config) < 0)
|
|
{
|
|
elog ("Can't load '%s'\n", MTCE_CONF_FILE );
|
|
return (FAIL_LOAD_INI);
|
|
}
|
|
|
|
/* Loads key Mtce timeout values that can override the defaults */
|
|
if (ini_parse(MTCE_CONF_FILE, timeout_config_handler, &mtc_config) < 0)
|
|
{
|
|
elog ("Can't load '%s'\n", MTCE_CONF_FILE );
|
|
return (FAIL_LOAD_INI);
|
|
}
|
|
/* Loads key Mtce timeout values that can override the defaults */
|
|
if (ini_parse(MTCE_INI_FILE, timeout_config_handler, &mtc_config) < 0)
|
|
{
|
|
elog ("Can't load '%s'\n", MTCE_INI_FILE );
|
|
return (FAIL_LOAD_INI);
|
|
}
|
|
|
|
/* Load the compute enable timeouts */
|
|
if ( mtc_config.compute_mtcalive_timeout )
|
|
mtcInv.compute_mtcalive_timeout = mtc_config.compute_mtcalive_timeout ;
|
|
else
|
|
mtcInv.compute_mtcalive_timeout = DEFAULT_MTCALIVE_TIMEOUT ;
|
|
|
|
/* Load the controller enable timeouts */
|
|
if ( mtc_config.controller_mtcalive_timeout )
|
|
mtcInv.controller_mtcalive_timeout = mtc_config.controller_mtcalive_timeout ;
|
|
else
|
|
mtcInv.controller_mtcalive_timeout = DEFAULT_MTCALIVE_TIMEOUT ;
|
|
|
|
if ( mtc_config.goenabled_timeout )
|
|
mtcInv.goenabled_timeout = mtc_config.goenabled_timeout ;
|
|
else
|
|
mtcInv.goenabled_timeout = DEFAULT_GOENABLE_TIMEOUT ;
|
|
|
|
mtcInv.loc_recovery_timeout = mtc_config.loc_recovery_timeout ;
|
|
mtcInv.mnfa_recovery_timeout = mtc_config.mnfa_recovery_timeout ;
|
|
|
|
if ( mtc_config.node_reinstall_timeout )
|
|
mtcInv.node_reinstall_timeout = mtc_config.node_reinstall_timeout ;
|
|
else
|
|
mtcInv.node_reinstall_timeout = MTC_REINSTALL_TIMEOUT_DEFAULT ;
|
|
|
|
|
|
if ( mtc_config.dor_mode_timeout <= 0 )
|
|
{
|
|
slog ("DOR Mode Timeout is invalid (%d), setting to default (%d)\n",
|
|
mtc_config.dor_mode_timeout,
|
|
DEFAULT_DOR_MODE_TIMEOUT);
|
|
|
|
mtc_config.dor_mode_timeout = DEFAULT_DOR_MODE_TIMEOUT ;
|
|
}
|
|
|
|
/* validate and auto correct manage multi node failure avoidance thresholds */
|
|
if (( mtc_config.mnfa_threshold_type != NULL ) &&
|
|
( !strncmp (mtc_config.mnfa_threshold_type, "percent", strlen("percent"))))
|
|
{
|
|
if ( mtc_config.mnfa_threshold_percent > 100 )
|
|
{
|
|
mtc_config.mnfa_threshold_percent = 100 ;
|
|
}
|
|
mtcInv.mnfa_threshold_type = MNFA_PERCENT ;
|
|
ilog ("mnfAvoidance: %d%c\n", mtc_config.mnfa_threshold_percent, '%' );
|
|
mtcInv.mnfa_threshold_percent = mtc_config.mnfa_threshold_percent ;
|
|
}
|
|
else
|
|
{
|
|
mtcInv.mnfa_threshold_type = MNFA_NUMBER ;
|
|
ilog ("mnfAvoidance: %d hosts\n", mtc_config.mnfa_threshold_number );
|
|
mtcInv.mnfa_threshold_number = mtc_config.mnfa_threshold_number ;
|
|
}
|
|
|
|
if ( mtc_config.swact_timeout )
|
|
{
|
|
if ( mtc_config.swact_timeout < (MTC_SWACT_POLL_TIMER*2))
|
|
mtcInv.swact_timeout = (MTC_SWACT_POLL_TIMER*2);
|
|
else
|
|
mtcInv.swact_timeout = mtc_config.swact_timeout ;
|
|
}
|
|
|
|
/* Allow the token refresh rate to be specified in the config file */
|
|
/* but no bigger than every 8 hours - that's all that has been tested */
|
|
mtcInv.token_refresh_rate = mtc_config.token_refresh_rate ;
|
|
if ( mtc_config.token_refresh_rate > MTC_HRS_8 )
|
|
{
|
|
wlog ("Token refresh rate rounded down to 8 hour maximum\n");
|
|
mtcInv.token_refresh_rate = MTC_HRS_8 ;
|
|
}
|
|
|
|
mtcInv.uptime_period = mtc_config.uptime_period ;
|
|
|
|
if ( mtc_config.online_period < MTC_MIN_ONLINE_PERIOD_SECS )
|
|
mtcInv.online_period = MTC_MIN_ONLINE_PERIOD_SECS ;
|
|
else
|
|
mtcInv.online_period = mtc_config.online_period ;
|
|
|
|
if (( mtc_config.sysinv_timeout == 0 ) || ( mtc_config.sysinv_timeout > 127 ))
|
|
{
|
|
mtc_config.sysinv_timeout = HTTP_SYSINV_CRIT_TIMEOUT ;
|
|
}
|
|
mtcInv.sysinv_timeout = mtc_config.sysinv_timeout ;
|
|
|
|
if (( mtc_config.sysinv_noncrit_timeout == 0 ) || ( mtc_config.sysinv_noncrit_timeout > 127 ))
|
|
{
|
|
mtc_config.sysinv_noncrit_timeout = HTTP_SYSINV_NONC_TIMEOUT ;
|
|
}
|
|
mtcInv.sysinv_noncrit_timeout = mtc_config.sysinv_noncrit_timeout ;
|
|
|
|
if (( mtc_config.work_queue_timeout == 0 ) || ( mtc_config.work_queue_timeout > 500 ))
|
|
{
|
|
mtc_config.work_queue_timeout = MTC_WORKQUEUE_TIMEOUT ;
|
|
}
|
|
mtcInv.work_queue_timeout = mtc_config.work_queue_timeout ;
|
|
|
|
if ( mtcInv.offline_period < MIN_OFFLINE_PERIOD_MSECS )
|
|
{
|
|
ilog ("offline audit too small (%d) ; correcting to %d\n",
|
|
mtcInv.offline_period, MIN_OFFLINE_PERIOD_MSECS );
|
|
|
|
mtcInv.offline_period = MIN_OFFLINE_PERIOD_MSECS ;
|
|
}
|
|
|
|
if ( mtcInv.offline_threshold == MIN_OFFLINE_THRESHOLD )
|
|
{
|
|
ilog ("offline threshold too small (%d) ; correcting to %d\n",
|
|
mtcInv.offline_threshold, MIN_OFFLINE_THRESHOLD );
|
|
|
|
mtcInv.offline_threshold = MIN_OFFLINE_THRESHOLD ;
|
|
}
|
|
|
|
/* Load in the In-Service and Out-Of-Service Test Periods */
|
|
mtcInv.insv_test_period = mtc_config.insv_test_period ;
|
|
mtcInv.oos_test_period = mtc_config.oos_test_period ;
|
|
|
|
ilog ("TokenRefresh: %3d secs\n" , mtcInv.token_refresh_rate);
|
|
ilog ("API Retries : %3d secs\n" , mtcInv.api_retries);
|
|
|
|
/* Verify loaded config against an expected mask
|
|
* as an ini file fault detection method */
|
|
if ( mtc_config.mask != CONFIG_AGENT_MASK )
|
|
{
|
|
elog ("Control configuration failed (%x)\n",
|
|
((-1 ^ mtc_config.mask) & CONFIG_AGENT_MASK));
|
|
return (FAIL_INI_CONFIG);
|
|
}
|
|
|
|
mtc_config.mgmnt_iface = daemon_get_iface_master ( mtc_config.mgmnt_iface );
|
|
ilog("Mgmnt iface : %s\n", mtc_config.mgmnt_iface );
|
|
|
|
/* Fetch the infrastructure interface name.
|
|
* calls daemon_get_iface_master inside so the
|
|
* aggrigated name is returned if it exists */
|
|
get_infra_iface (&mtc_config.infra_iface );
|
|
if ( strlen (mtc_config.infra_iface) )
|
|
{
|
|
string infra_ip = "" ;
|
|
rc = get_iface_address ( mtc_config.infra_iface, infra_ip, false );
|
|
if ( rc )
|
|
{
|
|
elog ("failed to get IP address fron infra interface '%s' (rc:%d)\n", mtc_config.infra_iface, rc );
|
|
}
|
|
else
|
|
{
|
|
ilog ("Infra iface : %s\n", mtc_config.infra_iface );
|
|
ilog ("Infra addr : %s\n", infra_ip.c_str());
|
|
}
|
|
mtcInv.infra_network_provisioned = true ;
|
|
}
|
|
|
|
/* Log the startup settings */
|
|
ilog("Cmd Req Port: %d (tx)\n", mtc_config.cmd_port );
|
|
ilog("Cmd Rsp Port: %d (rx)\n", mtc_config.mtc_agent_port );
|
|
ilog("Events Port: %d (rx)\n", mtc_config.hbs_to_mtc_event_port );
|
|
ilog("Inv Port : %d (tx)\n", mtc_config.sysinv_api_port );
|
|
ilog("Inv Address : %s (tx)\n", mtc_config.sysinv_api_bind_ip );
|
|
ilog("Inv Event : %d (rx)\n", mtc_config.inv_event_port );
|
|
ilog("Keystone Port: %d (rx)\n", mtc_config.keystone_port );
|
|
ilog("Mtce Logger : %d (tx)\n", mtc_config.daemon_log_port );
|
|
ilog("nfv-vim-api : %d (port)\n", mtc_config.vim_cmd_port );
|
|
ilog("hbsAgent : %d (port)\n", mtc_config.mtc_to_hbs_cmd_port );
|
|
ilog("guestAgent : %d (port)\n", mtc_config.mtc_to_guest_cmd_port );
|
|
ilog("hwmond : %d (port)\n", mtc_config.hwmon_cmd_port );
|
|
ilog("auth_host : %s \n", mtc_config.keystone_auth_host );
|
|
|
|
/* Get this Controller Activity State */
|
|
mtc_config.active = daemon_get_run_option ("active") ;
|
|
ilog ("Controller : %s\n",
|
|
mtc_config.active ? "Active" : "In-Active" );
|
|
|
|
/* remove any existing fit */
|
|
daemon_init_fit ();
|
|
|
|
return (PASS);
|
|
}
|
|
|
|
/* Construct the messaging sockets *
|
|
* 1. unicast transmit (to compute) socket *
|
|
* 2. unicast receive (fronm compute) socket */
|
|
int mtc_socket_init ( void )
|
|
{
|
|
int rc = 0 ;
|
|
int socket_size = 0 ;
|
|
char ip_address[INET6_ADDRSTRLEN];
|
|
|
|
/***********************************************************/
|
|
/* Setup UDP Maintenance Command Transmit Socket Mgmnt I/F */
|
|
/***********************************************************/
|
|
|
|
/* Read the port config strings into the socket struct */
|
|
mtc_sock.mtc_agent_port = mtc_config.mtc_agent_port;
|
|
mtc_sock.mtc_cmd_port = mtc_config.cmd_port;
|
|
|
|
/* create transmit socket */
|
|
msgClassAddr::getAddressFromInterface(mtc_config.mgmnt_iface, ip_address, INET6_ADDRSTRLEN);
|
|
sock_ptr->mtc_agent_tx_socket = new msgClassTx(ip_address, mtc_config.mtc_agent_port, IPPROTO_UDP, mtc_config.mgmnt_iface);
|
|
rc = sock_ptr->mtc_agent_tx_socket->return_status;
|
|
if(rc != PASS)
|
|
{
|
|
delete sock_ptr->mtc_agent_tx_socket;
|
|
return rc;
|
|
}
|
|
|
|
/***********************************************************/
|
|
/* Setup UDP Maintenance Command Transmit Socket Infra I/F */
|
|
/***********************************************************/
|
|
if ( strlen( mtc_config.infra_iface ) )
|
|
{
|
|
/* create infra transmit socket only if the interface is provisioned */
|
|
msgClassAddr::getAddressFromInterface(mtc_config.infra_iface, ip_address, INET6_ADDRSTRLEN);
|
|
sock_ptr->mtc_agent_infra_tx_socket = new msgClassTx(ip_address, mtc_config.mtc_agent_port, IPPROTO_UDP, mtc_config.infra_iface);
|
|
rc = sock_ptr->mtc_agent_infra_tx_socket->return_status;
|
|
if(rc != PASS)
|
|
{
|
|
delete sock_ptr->mtc_agent_infra_tx_socket;
|
|
return rc;
|
|
}
|
|
}
|
|
|
|
/*********************************************************************
|
|
* Setup Maintenance Command Reply and Event Receiver Socket
|
|
* - management interface
|
|
*
|
|
* This socket is used to receive command replies over the management
|
|
* interface and asynchronous events from the mtcClient and other
|
|
* maintenance service daemons.
|
|
*********************************************************************/
|
|
sock_ptr->mtc_agent_rx_socket =
|
|
new msgClassRx(CONTROLLER, sock_ptr->mtc_agent_port, IPPROTO_UDP );
|
|
if (( sock_ptr->mtc_agent_rx_socket == NULL ) ||
|
|
( sock_ptr->mtc_agent_rx_socket->return_status ))
|
|
{
|
|
elog("failed to create mtcClient receive socket on port %d for %s\n",
|
|
sock_ptr->mtc_agent_port,
|
|
mtc_config.mgmnt_iface );
|
|
|
|
if ( sock_ptr->mtc_agent_rx_socket )
|
|
{
|
|
delete (sock_ptr->mtc_agent_rx_socket);
|
|
sock_ptr->mtc_agent_rx_socket = NULL ;
|
|
}
|
|
return (FAIL_SOCKET_CREATE);
|
|
}
|
|
|
|
/* Set messaging buffer size */
|
|
/* if we need a bigger then default we can use a sysctl to raise the max */
|
|
socket_size = MTC_AGENT_RX_BUFF_SIZE ;
|
|
if (( rc = sock_ptr->mtc_agent_rx_socket->setSocketMemory ( mtc_config.mgmnt_iface, "mtce command and event receiver (Mgmnt network)", socket_size )) != PASS )
|
|
{
|
|
elog ("setsockopt failed for SO_RCVBUF (%d:%m)\n", errno );
|
|
delete (sock_ptr->mtc_agent_rx_socket);
|
|
sock_ptr->mtc_agent_rx_socket = NULL ;
|
|
return (FAIL_SOCKET_OPTION);
|
|
}
|
|
socklen_t optlen = sizeof(sock_ptr->mtc_agent_rx_socket_size);
|
|
getsockopt ( sock_ptr->mtc_agent_rx_socket->getFD(), SOL_SOCKET, SO_RCVBUF,
|
|
&sock_ptr->mtc_agent_rx_socket_size, &optlen );
|
|
|
|
ilog ("Listening On: 'mtc client receive' socket %d (%d rx bytes - req:%d) (%s)\n",
|
|
sock_ptr->mtc_agent_port,
|
|
sock_ptr->mtc_agent_rx_socket_size, MTC_AGENT_RX_BUFF_SIZE,
|
|
mtc_config.mgmnt_iface);
|
|
|
|
|
|
/*********************************************************************
|
|
* Setup Maintenance message receiver on the infrastructure network
|
|
* if it is provisioned
|
|
*
|
|
*********************************************************************/
|
|
|
|
if ( mtcInv.infra_network_provisioned == true )
|
|
{
|
|
sock_ptr->mtc_agent_infra_rx_socket =
|
|
new msgClassRx(CONTROLLER_NFS, sock_ptr->mtc_agent_port, IPPROTO_UDP );
|
|
if (( sock_ptr->mtc_agent_infra_rx_socket == NULL ) ||
|
|
( sock_ptr->mtc_agent_infra_rx_socket->return_status ))
|
|
{
|
|
elog("failed to create mtcClient receive socket on port %d for %s\n",
|
|
sock_ptr->mtc_agent_port,
|
|
mtc_config.infra_iface );
|
|
|
|
if ( sock_ptr->mtc_agent_infra_rx_socket )
|
|
{
|
|
delete (sock_ptr->mtc_agent_infra_rx_socket);
|
|
sock_ptr->mtc_agent_infra_rx_socket = NULL ;
|
|
}
|
|
return (FAIL_SOCKET_CREATE);
|
|
}
|
|
|
|
/* Set messaging buffer size */
|
|
/* if we need a bigger then default we can use a sysctl to raise the max */
|
|
socket_size = MTC_AGENT_RX_BUFF_SIZE ;
|
|
if (( rc = sock_ptr->mtc_agent_infra_rx_socket->setSocketMemory ( mtc_config.infra_iface, "mtce command and event receiver (Infra network)", socket_size )) != PASS )
|
|
{
|
|
elog ("setsockopt failed for SO_RCVBUF (%d:%m)\n", errno );
|
|
delete (sock_ptr->mtc_agent_infra_rx_socket);
|
|
sock_ptr->mtc_agent_infra_rx_socket = NULL ;
|
|
return (FAIL_SOCKET_OPTION);
|
|
}
|
|
socklen_t optlen = sizeof(sock_ptr->mtc_agent_infra_rx_socket_size);
|
|
getsockopt ( sock_ptr->mtc_agent_infra_rx_socket->getFD(), SOL_SOCKET, SO_RCVBUF,
|
|
&sock_ptr->mtc_agent_infra_rx_socket_size, &optlen );
|
|
|
|
ilog ("Listening On: 'mtc client receive' socket %d (%d rx bytes - req:%d) (%s)\n",
|
|
sock_ptr->mtc_agent_port,
|
|
sock_ptr->mtc_agent_infra_rx_socket_size, MTC_AGENT_RX_BUFF_SIZE,
|
|
mtc_config.infra_iface);
|
|
}
|
|
|
|
|
|
/***********************************************************/
|
|
/* Setup UDP Hardware Monitor Command Transmit socket */
|
|
/***********************************************************/
|
|
|
|
/* Read the port config strings into the socket struct */
|
|
mtc_sock.hwmon_cmd_port = mtc_config.hwmon_cmd_port;
|
|
|
|
/* create transmit socket */
|
|
msgClassAddr::getAddressFromInterface(mtc_config.mgmnt_iface, ip_address, INET6_ADDRSTRLEN);
|
|
sock_ptr->hwmon_cmd_sock = new msgClassTx(ip_address, mtc_config.hwmon_cmd_port, IPPROTO_UDP, mtc_config.mgmnt_iface);
|
|
rc = sock_ptr->hwmon_cmd_sock->return_status;
|
|
if ( rc!=PASS )
|
|
{
|
|
elog("Failed create socket (%d:%s)\n", errno, strerror(errno));
|
|
return (rc);
|
|
}
|
|
|
|
/***********************************************************/
|
|
/* Heartbeat Event Receiver Interface - (UDP over 'lo') */
|
|
/***********************************************************/
|
|
|
|
int port = daemon_get_cfg_ptr()->hbs_to_mtc_event_port ;
|
|
mtc_sock.mtc_event_rx_sock = new msgClassRx(LOOPBACK_IP, port, IPPROTO_UDP);
|
|
rc = mtc_sock.mtc_event_rx_sock->return_status;
|
|
if ( rc )
|
|
{
|
|
elog ("Failed to setup mtce event receive port %d\n", port );
|
|
return (rc) ;
|
|
}
|
|
|
|
/* Setup the maintenance event receiver for sysinv and vim requests */
|
|
memset ( &mtce_event, 0, sizeof(event_type));
|
|
mtce_event.port = mtc_config.inv_event_port ;
|
|
rc = mtcHttpSvr_init ( mtce_event );
|
|
|
|
/***********************************************************/
|
|
/* UDP Transmit Socket for Sending Heartbeat Commands */
|
|
/***********************************************************/
|
|
|
|
port = daemon_get_cfg_ptr()->mtc_to_hbs_cmd_port ;
|
|
sock_ptr->mtc_to_hbs_sock = new msgClassTx(LOOPBACK_IP, port, IPPROTO_UDP);
|
|
rc = sock_ptr->mtc_to_hbs_sock->return_status;
|
|
if ( rc )
|
|
{
|
|
elog ("Failed to setup mtce to hbs transmit command port %d\n", port );
|
|
return (rc) ;
|
|
}
|
|
|
|
sock_ptr->mtclogd.port = port = daemon_get_cfg_ptr()->daemon_log_port ;
|
|
CREATE_REUSABLE_INET_UDP_TX_SOCKET ( LOOPBACK_IP,
|
|
port,
|
|
sock_ptr->mtclogd.sock,
|
|
sock_ptr->mtclogd.addr,
|
|
sock_ptr->mtclogd.port,
|
|
sock_ptr->mtclogd.len,
|
|
"mtc logger message",
|
|
rc );
|
|
if ( rc )
|
|
{
|
|
elog ("Failed to setup mtce logger port %d\n", port );
|
|
return (rc) ;
|
|
}
|
|
|
|
/* Use the base timer to delay for a time to give
|
|
* the heartbeat service time to init */
|
|
// ilog ("Delay 3 secs allowing Inventory & Heartbeat daemons to be ready\n");
|
|
// mtcWait_secs (3);
|
|
|
|
return (rc);
|
|
}
|
|
|
|
int mtc_set_availStatus ( string & hostname, mtc_nodeAvailStatus_enum status )
|
|
{
|
|
return ( mtcInv.set_availStatus ( hostname, status ));
|
|
}
|
|
|
|
/* Get and store my hostname */
|
|
int mtc_hostname_read ( void )
|
|
{
|
|
int rc ;
|
|
|
|
/* declare and init a var to hold the queried local hostname */
|
|
char local_hostname[MAX_HOST_NAME_SIZE+1] ;
|
|
memset (&local_hostname[0], 0, MAX_HOST_NAME_SIZE);
|
|
|
|
/* read the host name */
|
|
rc = gethostname(&local_hostname[0], MAX_HOST_NAME_SIZE );
|
|
if ( rc == PASS )
|
|
{
|
|
string string_hostname = local_hostname ;
|
|
mtcInv.set_my_hostname ( string_hostname );
|
|
|
|
if ( mtcInv.get_my_hostname () == string_hostname )
|
|
return (PASS) ;
|
|
}
|
|
else
|
|
{
|
|
dlog ("gethostname failed (%d)\n", rc );
|
|
}
|
|
return (FAIL);
|
|
}
|
|
|
|
/* The main service loop */
|
|
int daemon_init ( string iface, string nodetype )
|
|
{
|
|
int rc = PASS ;
|
|
|
|
/* Not used presently */
|
|
mtcInv.functions = nodetype ;
|
|
|
|
httpUtil_init ();
|
|
|
|
/* Initialize socket construct and pointer to it */
|
|
memset ( &mtc_sock, 0, sizeof(mtc_sock));
|
|
sock_ptr = &mtc_sock ;
|
|
|
|
/* Assign interface to config */
|
|
mtc_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 ) ;
|
|
}
|
|
|
|
mtcInv.system_type = daemon_system_type ();
|
|
|
|
/* Get and store my hostname */
|
|
if ( mtc_hostname_read () != PASS )
|
|
{
|
|
elog ("Failed hostname setup\n");
|
|
return (FAIL_HOSTNAME_SETUP) ;
|
|
}
|
|
|
|
/* init the base timers */
|
|
mtcTimer_init ( mtcInv.mtcTimer, mtcInv.my_hostname, "mtc timer" ); /* Init general mtc timer */
|
|
mtcAlarm_init ();
|
|
mtc_stages_init ();
|
|
threadUtil_init ( mtcTimer_handler ) ;
|
|
|
|
/* Bind signal handlers */
|
|
rc = daemon_signal_init () ;
|
|
if ( rc )
|
|
{
|
|
elog ("daemon_signal_init failed\n");
|
|
return ( FAIL_SIGNAL_INIT) ;
|
|
}
|
|
|
|
/* Configure the control */
|
|
rc = daemon_configure ();
|
|
if ( rc )
|
|
{
|
|
elog ("Daemon service configuration failed (%i)\n", rc );
|
|
return ( FAIL_DAEMON_CONFIG ) ;
|
|
}
|
|
|
|
daemon_make_dir(IPMITOOL_OUTPUT_DIR) ;
|
|
|
|
#ifdef WANT_FIT_TESTING
|
|
daemon_make_dir(FIT__INFO_FILEPATH);
|
|
#endif
|
|
|
|
return (rc);
|
|
}
|
|
|
|
int _self_provision ( void )
|
|
{
|
|
int rc ;
|
|
int load_retries ;
|
|
bool waiting_msg = false ;
|
|
node_inv_type my_identity ;
|
|
node_inv_type record_info ;
|
|
|
|
node_inv_init ( my_identity );
|
|
node_inv_init ( record_info );
|
|
|
|
ilog ("My Hostname : %s\n", mtcInv.my_hostname.c_str());
|
|
|
|
for ( ;; )
|
|
{
|
|
get_ip_addresses ( mtcInv.my_hostname, mtcInv.my_local_ip , mtcInv.my_float_ip );
|
|
if ( mtcInv.my_float_ip.empty() || mtcInv.my_float_ip.empty() )
|
|
{
|
|
if ( waiting_msg == false )
|
|
{
|
|
ilog ("Waiting on ip address config ...\n");
|
|
waiting_msg = true ;
|
|
}
|
|
mtcWait_secs (3);
|
|
}
|
|
else
|
|
{
|
|
break ;
|
|
}
|
|
daemon_signal_hdlr ();
|
|
}
|
|
|
|
|
|
my_identity.name = mtcInv.my_hostname ;
|
|
my_identity.ip = mtcInv.my_local_ip ;
|
|
get_iface_macaddr ( mtc_config.mgmnt_iface , my_identity.mac );
|
|
|
|
/* Verify interface properties */
|
|
if ( my_identity.mac.empty() ||
|
|
( my_identity.mac.length() != COL_CHARS_IN_MAC_ADDR ) ||
|
|
my_identity.name.empty() ||
|
|
my_identity.ip.empty ())
|
|
{
|
|
elog ("Failed to acquire mgmt interface (%s) properties\n", mtc_config.mgmnt_iface );
|
|
daemon_exit();
|
|
}
|
|
|
|
/* Set the states for the database */
|
|
my_identity.type = "controller";
|
|
my_identity.func = mtcInv.functions ;
|
|
my_identity.admin = "unlocked" ;
|
|
my_identity.oper = "enabled" ;
|
|
my_identity.avail = "available" ;
|
|
|
|
my_identity.avail_subf = "not-installed" ;
|
|
my_identity.oper_subf = "disabled" ;
|
|
|
|
my_identity.uuid = "" ; /* uuid will be learned later */
|
|
|
|
if ( mtcInv.add_host ( my_identity ) )
|
|
{
|
|
elog ("Failed to add (%s) host\n", my_identity.name.c_str());
|
|
daemon_exit();
|
|
}
|
|
|
|
/* Get an Authentication Token */
|
|
ilog ("%s Requesting initial token\n", mtcInv.my_hostname.c_str() );
|
|
do
|
|
{
|
|
rc = tokenUtil_new_token ( mtcInv.tokenEvent, mtcInv.my_hostname );
|
|
if ( rc )
|
|
{
|
|
elog ("Failed to get authentication token (%d)\n", rc );
|
|
}
|
|
|
|
/* Give system inventory some time after start-up.
|
|
* We see frequent first request failures requiring retry when this
|
|
* wait was inside the above if clause. Moving it here ensure there
|
|
* is always a small wait after the token fetch on process startup. */
|
|
daemon_signal_hdlr ();
|
|
sleep (5);
|
|
daemon_signal_hdlr ();
|
|
|
|
} while ( rc != PASS ) ;
|
|
|
|
#ifdef WANT_FIT_TESTING
|
|
if ( daemon_want_fit ( FIT_CODE__CORRUPT_TOKEN, mtcInv.my_hostname ))
|
|
tokenUtil_fail_token ();
|
|
#endif
|
|
|
|
load_retries = 0 ;
|
|
do
|
|
{
|
|
daemon_signal_hdlr ();
|
|
|
|
rc = mtcInv.mtcInvApi_load_host ( my_identity.name, record_info ) ;
|
|
if (( rc == PASS ) || ( rc == HTTP_OK ))
|
|
{
|
|
ilog ("%s found in database (%s)\n",
|
|
record_info.name.c_str(),
|
|
record_info.uuid.c_str());
|
|
|
|
/* load in the uuid, and board management info */
|
|
mtcInv.set_uuid ( my_identity.name, record_info.uuid );
|
|
mtcInv.set_task ( my_identity.name, record_info.task );
|
|
mtcInv.set_bm_un ( my_identity.name, record_info.bm_un );
|
|
mtcInv.set_bm_ip ( my_identity.name, record_info.bm_ip );
|
|
mtcInv.set_bm_type ( my_identity.name, record_info.bm_type );
|
|
|
|
if ( my_identity.name == record_info.name )
|
|
{
|
|
|
|
/* If the active controller was 'locked' and is being auto-corrected
|
|
* to 'unlocked' then ensure that there is no locked alarm set for it */
|
|
if ( record_info.admin != "locked" )
|
|
{
|
|
mtcAlarm_clear ( my_identity.name, MTC_ALARM_ID__LOCK );
|
|
/* this is not required because its already inited to clear */
|
|
// node_ptr->alarms[MTC_ALARM_ID__LOCK] = FM_ALARM_SEVERITY_CLEAR
|
|
}
|
|
|
|
// mtcInv.set_subf_info ( my_identity.name, record_info.func,
|
|
// record_info.oper_subf,
|
|
// record_info.avail_subf );
|
|
if ( my_identity.mac != record_info.mac )
|
|
{
|
|
wlog ("%s mac address mismatch (%s - %s)\n",
|
|
my_identity.name.c_str(),
|
|
my_identity.mac.c_str(),
|
|
record_info.mac.c_str());
|
|
}
|
|
|
|
if ( my_identity.ip != record_info.ip )
|
|
{
|
|
wlog ("%s ip address mismatch (%s - %s)\n",
|
|
my_identity.name.c_str(),
|
|
my_identity.ip.c_str(),
|
|
record_info.ip.c_str());
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if ( rc == HTTP_NOTFOUND )
|
|
{
|
|
wlog ("%s inventory record not found in database, retrying ... \n",
|
|
my_identity.name.c_str());
|
|
}
|
|
else if ( rc == FAIL_HTTP_ZERO_STATUS )
|
|
{
|
|
wlog ("%s inventory record load timeout, retrying ... \n",
|
|
my_identity.name.c_str());
|
|
}
|
|
else if ( rc == FAIL_RETRY )
|
|
{
|
|
wlog ("%s inventory config dependency not met, retrying ...\n",
|
|
my_identity.name.c_str());
|
|
}
|
|
else
|
|
{
|
|
wlog ("%s inventory record load failed (rc:%d), retrying ...\n",
|
|
my_identity.name.c_str(), rc );
|
|
}
|
|
load_retries++ ;
|
|
if ( load_retries > (mtcInv.api_retries+10) )
|
|
{
|
|
elog ("... giving up after %d retries\n", load_retries );
|
|
daemon_exit();
|
|
}
|
|
mtcWait_secs (15);
|
|
}
|
|
} while ( rc != PASS ) ;
|
|
|
|
mtcInv.set_active_controller_hostname ( my_identity.name );
|
|
mtcInv.set_activity_state (true);
|
|
mtcInv.set_adminAction ( my_identity.name, MTC_ADMIN_ACTION__ADD );
|
|
mtcInv.ctl_mtcAlive_gate ( my_identity.name, true );
|
|
|
|
/* Setup the heartbeat service messaging sockets */
|
|
rc = mtc_socket_init ( ) ;
|
|
if ( rc != PASS )
|
|
{
|
|
elog ("Socket initialization failed (rc:%d)\n", rc );
|
|
return (FAIL_SOCKET_INIT) ;
|
|
}
|
|
|
|
daemon_make_dir(IPMITOOL_OUTPUT_DIR) ;
|
|
|
|
#ifdef WANT_FIT_TESTING
|
|
daemon_make_dir(FIT__INFO_FILEPATH);
|
|
#endif
|
|
|
|
return(rc);
|
|
}
|
|
|
|
/* Main FSM Loop */
|
|
void nodeLinkClass::fsm ( void )
|
|
{
|
|
if ( head )
|
|
{
|
|
int rc ;
|
|
daemon_signal_hdlr ();
|
|
this->uptime_handler ();
|
|
for ( struct node * node_ptr = head ; node_ptr != NULL ; node_ptr = node_ptr->next )
|
|
{
|
|
string hn = node_ptr->hostname ;
|
|
rc = fsm ( node_ptr ) ;
|
|
if ( rc )
|
|
{
|
|
dlog ("%s fsm returned error code %d\n", hn.c_str(), rc );
|
|
}
|
|
if ( this->host_deleted == true )
|
|
{
|
|
this->host_deleted = false ;
|
|
return ;
|
|
}
|
|
|
|
daemon_signal_hdlr ();
|
|
mtcHttpSvr_look ( mtce_event );
|
|
}
|
|
}
|
|
}
|
|
|
|
void daemon_service_run ( void )
|
|
{
|
|
int rc ;
|
|
|
|
/* socket descriptor list */
|
|
std::list<int> socks ;
|
|
|
|
/* Set the mode */
|
|
mtcInv_ptr->maintenance = true ;
|
|
mtcInv_ptr->heartbeat = false ;
|
|
|
|
if (( mtc_sock.ioctl_sock = open_ioctl_socket ( )) <= 0 )
|
|
{
|
|
elog ("Failed to create ioctl socket");
|
|
daemon_exit ();
|
|
}
|
|
|
|
/* Not monitoring address changes RTMGRP_IPV4_IFADDR | RTMGRP_IPV6_IFADDR */
|
|
if (( mtc_sock.netlink_sock = open_netlink_socket ( RTMGRP_LINK )) <= 0 )
|
|
{
|
|
elog ("Failed to create netlink listener socket");
|
|
daemon_exit ();
|
|
}
|
|
|
|
/* Init HTTP Messaging */
|
|
mtcHttpUtil_init ();
|
|
|
|
ilog ("SW VERSION : %s\n", daemon_sw_version ().c_str());
|
|
|
|
/* Collect inventory in active state only */
|
|
if ( mtc_config.active == true )
|
|
{
|
|
/* provision this controller */
|
|
if ( _self_provision () != PASS )
|
|
{
|
|
elog ("Failed to self provision active controller\n");
|
|
daemon_exit ();
|
|
}
|
|
|
|
/* The following are base object controller timers ; init them */
|
|
mtcTimer_init ( mtcInv.mtcTimer_token, mtcInv.my_hostname, "token timer" );
|
|
mtcTimer_init ( mtcInv.mtcTimer_uptime,mtcInv.my_hostname, "uptime timer" );
|
|
mtcTimer_init ( mtcInv.mtcTimer_mnfa, mtcInv.my_hostname, "mnfa timer" );
|
|
mtcTimer_init ( mtcInv.mtcTimer_dor, mtcInv.my_hostname, "DOR mode timer" );
|
|
|
|
if ( get_link_state ( mtc_sock.ioctl_sock, mtc_config.mgmnt_iface, &mtcInv.mgmnt_link_up_and_running ) )
|
|
|
|
{
|
|
mtcInv.mgmnt_link_up_and_running = false ;
|
|
wlog ("Failed to query %s operational state ; defaulting to down\n", mtc_config.mgmnt_iface );
|
|
}
|
|
else
|
|
{
|
|
ilog ("Mgmnt %s link is %s\n", mtc_config.mgmnt_iface, mtcInv.mgmnt_link_up_and_running ? "Up" : "Down" );
|
|
}
|
|
|
|
if ( mtcInv.infra_network_provisioned == true )
|
|
{
|
|
if ( get_link_state ( mtc_sock.ioctl_sock, mtc_config.infra_iface, &mtcInv.infra_link_up_and_running ) )
|
|
{
|
|
mtcInv.infra_link_up_and_running = false ;
|
|
wlog ("Failed to query %s operational state ; defaulting to down\n", mtc_config.infra_iface );
|
|
}
|
|
else
|
|
{
|
|
ilog ("Infra %s link is %s\n", mtc_config.infra_iface, mtcInv.infra_link_up_and_running ? "Up" : "Down" );
|
|
}
|
|
}
|
|
|
|
//wlog ("Waiting 15 seconds before talking to inventory ....\n");
|
|
//mtcWait_secs (15);
|
|
//wlog ("Reading Inventory\n");
|
|
|
|
/* start loading inventory */
|
|
int retry_count = 0 ;
|
|
do
|
|
{
|
|
/* Load Inventory */
|
|
rc = mtcInvApi_read_inventory ( MTC_INV_BATCH_MAX );
|
|
if ( rc != PASS )
|
|
{
|
|
retry_count++ ;
|
|
elog ("failed to read inventory records for batch of %d\n", MTC_INV_BATCH_MAX );
|
|
elog ("... retrying in 5 seconds\n");
|
|
mtcWait_secs (5);
|
|
}
|
|
else
|
|
{
|
|
retry_count = 0 ;
|
|
}
|
|
|
|
if ( retry_count > 10 )
|
|
{
|
|
elog ("failed to read inventory after %d retries\n", retry_count );
|
|
elog ("... giving up ; exiting \n");
|
|
daemon_exit ();
|
|
}
|
|
} while ( rc == FAIL ) ;
|
|
|
|
if ( mtcInv_ptr->token_refresh_rate != 0 )
|
|
{
|
|
ilog ("Starting 'Token' Refresh timer (%d minutes)\n",
|
|
(mtcInv_ptr->token_refresh_rate/60) );
|
|
if ( mtcTimer_start ( mtcInv_ptr->mtcTimer_token,
|
|
mtcTimer_handler,
|
|
mtcInv_ptr->token_refresh_rate ) != PASS )
|
|
{
|
|
elog ("Failed to start 'Token' Refresh Timer\n");
|
|
daemon_exit ( ) ;
|
|
}
|
|
}
|
|
|
|
ilog ("Starting 'Uptime' Refresh timer (%d seconds)\n",
|
|
MTC_UPTIME_REFRESH_TIMER );
|
|
/* Start a inventory refresh timer */
|
|
if ( mtcTimer_start ( mtcInv.mtcTimer_uptime,
|
|
mtcTimer_handler,
|
|
MTC_UPTIME_REFRESH_TIMER+(rand()%10)) != PASS )
|
|
{
|
|
elog ("Failed to start 'Uptime' Refresh Timer\n");
|
|
daemon_exit ( ) ;
|
|
}
|
|
}
|
|
|
|
/* Add an inotify watch on the shadow file. */
|
|
set_inotify_watch_file ( SHADOW_FILE,
|
|
mtcInv.inotify_shadow_file_fd ,
|
|
mtcInv.inotify_shadow_file_wd );
|
|
|
|
/* Add this controller to the heartbeat service so that we
|
|
* receive the out-of-band heartbeat 'flags' even though
|
|
* we don't self monitor the active controller specifically
|
|
* This add may be duplicate but covers the initial config case */
|
|
send_hbs_command ( mtcInv.my_hostname, MTC_CMD_ADD_HOST );
|
|
|
|
socks.clear();
|
|
socks.push_front (mtc_sock.mtc_event_rx_sock->getFD()); // service_events
|
|
socks.push_front (mtc_sock.mtc_agent_rx_socket->getFD()); // mtc_service_inbox
|
|
|
|
if ( mtcInv.infra_network_provisioned == true )
|
|
{
|
|
socks.push_front (mtc_sock.mtc_agent_infra_rx_socket->getFD()); // mtc_service_inbox
|
|
}
|
|
|
|
socks.push_front (mtc_sock.netlink_sock);
|
|
|
|
if ( mtce_event.fd )
|
|
socks.push_front( mtce_event.fd ) ;
|
|
|
|
/* Avoid selecting on file descriptors that are 0 */
|
|
if ( mtcInv.inotify_shadow_file_fd )
|
|
socks.push_front (mtcInv.inotify_shadow_file_fd);
|
|
|
|
socks.sort();
|
|
|
|
mtcInv.print_node_info();
|
|
|
|
/* enable the base level signal handler latency monitor */
|
|
daemon_latency_monitor (true);
|
|
|
|
/* DOR Mode Check */
|
|
int enabled_nodes = mtcInv.enabled_nodes();
|
|
struct timespec ts ;
|
|
clock_gettime (CLOCK_MONOTONIC, &ts );
|
|
|
|
#ifdef WANT_FIT_TESTING
|
|
/* Support low uptime FIT for testing */
|
|
if ( daemon_is_file_present ( MTC_CMD_FIT__UPTIME ))
|
|
{
|
|
ts.tv_sec = daemon_get_file_int ( MTC_CMD_FIT__UPTIME );
|
|
slog ("FIT: Uptime %ld secs or %ld min %ld secs\n",
|
|
ts.tv_sec,
|
|
ts.tv_sec/60,
|
|
ts.tv_sec%60);
|
|
}
|
|
#endif
|
|
|
|
if ( ts.tv_sec < MTC_MINS_20 )
|
|
{
|
|
/* CPE DOR window is much greater in CPE since heartbeat
|
|
* cannot start until the inactive CPE has run both manifests */
|
|
int timeout = DEFAULT_DOR_MODE_CPE_TIMEOUT ;
|
|
|
|
/* override the timeout to a smaller value for normal system */
|
|
if ( mtcInv.system_type == SYSTEM_TYPE__NORMAL )
|
|
{
|
|
/* calculate time from config variable and number of enabled hosts */
|
|
timeout = mtc_config.dor_mode_timeout + (enabled_nodes);
|
|
}
|
|
|
|
mtcInv.dor_mode_active = true ;
|
|
mtcInv.dor_start_time = ts.tv_sec ;
|
|
|
|
ilog ("%-12s ---------- ; DOR Recovery ---------------------- -------------------\n", mtcInv.my_hostname.c_str());
|
|
ilog ("%-12s is ACTIVE ; DOR Recovery %2d:%02d mins (%4d secs) (duration %3d secs)\n",
|
|
mtcInv.my_hostname.c_str(),
|
|
mtcInv.dor_start_time/60,
|
|
mtcInv.dor_start_time%60,
|
|
mtcInv.dor_start_time,
|
|
timeout );
|
|
ilog ("%-12s ---------- ; DOR Recovery ---------------------- -------------------\n", mtcInv.my_hostname.c_str());
|
|
ilog ("%-12s host state ; DOR Recovery controller uptime host uptime \n", mtcInv.my_hostname.c_str());
|
|
ilog ("%-12s ---------- ; DOR Recovery ---------------------- -------------------\n", mtcInv.my_hostname.c_str());
|
|
mtcTimer_start ( mtcInv.mtcTimer_dor, mtcTimer_handler, timeout );
|
|
}
|
|
|
|
/* Run Maintenance service forever */
|
|
for ( ; ; )
|
|
{
|
|
/**
|
|
* Can't just run 'mtcHttpSvr_look' off select as it is seen to miss events.
|
|
* Would like to use event_base_loopexit with event_base_loopcontinue
|
|
* but the continue API is not available until 2.1.2-alpha.
|
|
* In the meantime we will have to continue to service it all the time
|
|
* mtcHttpSvr_work ( mtce_event );
|
|
**/
|
|
mtcHttpSvr_look ( mtce_event );
|
|
tokenUtil_log_refresh ();
|
|
|
|
if ( mtcInv_ptr->num_hosts () == 0 )
|
|
{
|
|
// mtcHttpSvr_look ( mtce_event );
|
|
sleep (1);
|
|
continue ;
|
|
}
|
|
|
|
mtcInv.fsm ( );
|
|
|
|
/* Initialize the master fd_set */
|
|
FD_ZERO(&mtc_sock.readfds);
|
|
FD_SET(mtc_sock.mtc_event_rx_sock->getFD(), &mtc_sock.readfds);
|
|
FD_SET(mtc_sock.mtc_agent_rx_socket->getFD(), &mtc_sock.readfds);
|
|
if ( mtcInv.infra_network_provisioned == true )
|
|
{
|
|
FD_SET(mtc_sock.mtc_agent_infra_rx_socket->getFD(),&mtc_sock.readfds);
|
|
}
|
|
|
|
if ( mtce_event.fd )
|
|
{
|
|
FD_SET(mtce_event.fd, &mtc_sock.readfds);
|
|
}
|
|
if ( mtcInv.inotify_shadow_file_fd )
|
|
{
|
|
FD_SET(mtcInv.inotify_shadow_file_fd, &mtc_sock.readfds);
|
|
}
|
|
if ( mtc_sock.netlink_sock )
|
|
{
|
|
FD_SET(mtc_sock.netlink_sock, &mtc_sock.readfds);
|
|
}
|
|
|
|
/* Initialize the timeval struct */
|
|
mtc_sock.waitd.tv_sec = 0;
|
|
if ( mtcInv.system_type == SYSTEM_TYPE__NORMAL )
|
|
mtc_sock.waitd.tv_usec = MTCAGENT_SELECT_TIMEOUT ;
|
|
else
|
|
mtc_sock.waitd.tv_usec = MTCAGENT_CPE_SELECT_TIMEOUT ;
|
|
|
|
/* This is used as a delay up to select_timeout */
|
|
rc = select( socks.back()+1, &mtc_sock.readfds, NULL, NULL, &mtc_sock.waitd);
|
|
|
|
/* If the select time out expired then */
|
|
if (( rc < 0 ) || ( rc == 0 ))
|
|
{
|
|
/* Check to see if the select call failed. */
|
|
/* ... but filter Interrupt signal */
|
|
if (( rc < 0 ) && ( errno != EINTR ))
|
|
{
|
|
elog ( "Select Failed (rc:%d) %s \n", errno, strerror(errno));
|
|
}
|
|
}
|
|
else
|
|
{
|
|
if ( FD_ISSET( mtce_event.fd , &mtc_sock.readfds))
|
|
{
|
|
mtcHttpSvr_look ( mtce_event );
|
|
}
|
|
if (FD_ISSET(mtc_sock.netlink_sock, &mtc_sock.readfds))
|
|
{
|
|
dlog ("netlink socket fired\n");
|
|
if ( mtcInv.service_netlink_events ( mtc_sock.netlink_sock, mtc_sock.ioctl_sock ) != PASS )
|
|
{
|
|
elog ("service_netlink_events failed (rc:%d)\n", rc );
|
|
}
|
|
}
|
|
|
|
if (FD_ISSET(sock_ptr->mtc_event_rx_sock->getFD(), &mtc_sock.readfds))
|
|
{
|
|
if ( (rc = service_events ( &mtcInv, &mtc_sock )) != PASS )
|
|
{
|
|
elog ("service_events failed (rc:%d)\n", rc );
|
|
}
|
|
}
|
|
|
|
if ( FD_ISSET(sock_ptr->mtc_agent_rx_socket->getFD(), &mtc_sock.readfds))
|
|
{
|
|
int cnt = 0 ;
|
|
/* Service up to MAX_RX_MSG_BATCH of messages at once */
|
|
for ( ; cnt < MAX_RX_MSG_BATCH ; cnt++ )
|
|
{
|
|
rc = mtc_service_inbox ( &mtcInv, &mtc_sock , MGMNT_INTERFACE) ;
|
|
if ( rc > RETRY )
|
|
{
|
|
mlog2 ("mtc_service_inbox failed (rc:%d) (Mgmnt)\n", rc );
|
|
break ;
|
|
}
|
|
if ( rc == RETRY )
|
|
break ;
|
|
}
|
|
if ( cnt > 1 )
|
|
{
|
|
mlog2 ("serviced %d messages in one batch (Mgmnt)\n", cnt );
|
|
}
|
|
}
|
|
|
|
if (( mtcInv.infra_network_provisioned == true ) &&
|
|
( sock_ptr->mtc_agent_infra_rx_socket != NULL ) &&
|
|
( FD_ISSET(sock_ptr->mtc_agent_infra_rx_socket->getFD(), &mtc_sock.readfds)))
|
|
{
|
|
int cnt = 0 ;
|
|
/* Service up to MAX_RX_MSG_BATCH of messages at once */
|
|
for ( ; cnt < MAX_RX_MSG_BATCH ; cnt++ )
|
|
{
|
|
rc = mtc_service_inbox ( &mtcInv, &mtc_sock, INFRA_INTERFACE ) ;
|
|
if ( rc > RETRY )
|
|
{
|
|
mlog2 ("mtc_service_inbox failed (rc:%d) (Infra)\n", rc );
|
|
break ;
|
|
}
|
|
if ( rc == RETRY )
|
|
break ;
|
|
}
|
|
if ( cnt > 1 )
|
|
{
|
|
mlog2 ("serviced %d messages in one batch (Infra)\n", cnt ); // ERIC dlog
|
|
}
|
|
}
|
|
if (FD_ISSET(mtcInv.inotify_shadow_file_fd, &mtc_sock.readfds))
|
|
{
|
|
rc = get_inotify_events ( mtcInv.inotify_shadow_file_fd, (IN_MODIFY | IN_CREATE | IN_IGNORED) );
|
|
if ( rc )
|
|
{
|
|
ilog ("Shadow file has changed (%x)\n", rc );
|
|
if ( mtcInv.manage_shadow_change ( mtcInv.my_hostname ) != PASS )
|
|
{
|
|
elog ("failed to manage shadow file change notification (%d)\n", rc );
|
|
}
|
|
if ( rc & IN_IGNORED )
|
|
{
|
|
socks.remove(mtcInv.inotify_shadow_file_fd);
|
|
set_inotify_close ( mtcInv.inotify_shadow_file_fd, mtcInv.inotify_shadow_file_wd );
|
|
set_inotify_watch_file ( SHADOW_FILE,
|
|
mtcInv.inotify_shadow_file_fd ,
|
|
mtcInv.inotify_shadow_file_wd );
|
|
socks.push_back (mtcInv.inotify_shadow_file_fd);
|
|
socks.sort();
|
|
wlog ("Reselecting on %s change (Select:%d)\n", SHADOW_FILE, mtcInv.inotify_shadow_file_fd );
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
daemon_signal_hdlr ();
|
|
|
|
/* If the timer is no longer active and we are in DOR mode
|
|
* then exit DOR mode. We do it here instead of */
|
|
if (( mtcInv.dor_mode_active == true ) && ( mtcInv.mtcTimer_dor.tid == NULL ))
|
|
{
|
|
ilog ("DOR mode disable\n");
|
|
mtcInv.dor_mode_active = false ;
|
|
}
|
|
}
|
|
daemon_exit ();
|
|
}
|
|
|
|
/* Push daemon state to log file */
|
|
void daemon_dump_info ( void )
|
|
{
|
|
daemon_dump_membuf_banner ();
|
|
|
|
mtcTimer_mem_log ();
|
|
mtcInv.print_node_info ();
|
|
|
|
daemon_dump_membuf (); /* write mem_logs to log file and clear log list */
|
|
|
|
//mtcInv.doneQueue_dump_all ();
|
|
mtcInv.mtcCmd_doneQ_dump_all ();
|
|
|
|
daemon_dump_membuf (); /* write mem_logs to log file and clear log list */
|
|
|
|
//mtcInv.workQueue_dump_all ();
|
|
mtcInv.mtcCmd_workQ_dump_all ();
|
|
|
|
daemon_dump_membuf (); /* write mem_logs to log file and clear log list */
|
|
|
|
mtcInv.memDumpAllState ();
|
|
|
|
daemon_dump_membuf (); /* write mem_logs to log file and clear log list */
|
|
}
|
|
|
|
const char MY_DATA [100] = { "eieio\n" } ;
|
|
const char * daemon_stream_info ( void )
|
|
{
|
|
return (&MY_DATA[0]);
|
|
}
|
|
/***************************************************************************
|
|
* *
|
|
* Module Test Head *
|
|
* *
|
|
***************************************************************************/
|
|
|
|
extern int mtcJsonInv_testhead ( void );
|
|
|
|
/** Teat Head Entry */
|
|
int daemon_run_testhead ( void )
|
|
{
|
|
int rc = PASS;
|
|
|
|
mtc_config.testmode = true ;
|
|
|
|
nodeLinkClass * mtcInv_testhead_ptr = new nodeLinkClass ;
|
|
|
|
printf ("\n\n");
|
|
printf (TESTHEAD_BAR);
|
|
|
|
printf ("| Node Class Test Head - Private and Public Member Functions\n");
|
|
printf (TESTHEAD_BAR);
|
|
for ( int i = 0 ; i < 11 ; i++ )
|
|
{
|
|
if ( mtcInv_testhead_ptr->testhead ( i+1 ) )
|
|
{
|
|
FAILED_STR ;
|
|
rc = FAIL ;
|
|
}
|
|
else
|
|
PASSED ;
|
|
}
|
|
|
|
printf (TESTHEAD_BAR);
|
|
printf ("| Maintenance Timer Test Head\n");
|
|
printf (TESTHEAD_BAR);
|
|
return (rc);
|
|
}
|
|
|
|
int send_event ( string & hostname, unsigned int event_cmd, iface_enum iface )
|
|
{
|
|
UNUSED(hostname) ;
|
|
UNUSED(event_cmd) ;
|
|
UNUSED(iface);
|
|
return PASS ;
|
|
}
|
|
|