Este capítulo describe el tipo de recurso de ejemplo, SUNW.xfnts, implementado con la Biblioteca de desarrollo del servicio de datos (DSDL). Este servicio de datos está escrito en C. La aplicación subyacente es el servidor de fuentes X, un servicio basado en TCP/IP. Apéndice C, Listados de código del tipo de recurso de ejemplo de DSDL contiene el código completo para cada método del tipo de recurso SUNW.xfnts .
En este capítulo se tratan los temas siguientes:
El servidor de fuentes X es un servicio basado en TCP/IP que proporciona archivos de fuentes a los clientes. Éstos se conectan al servidor para solicitar un conjunto de fuentes y el servidor lee los archivos de fuentes del disco y se los sirve a los clientes. El daemon del servidor de fuentes X está formado por un archivo binario de servidor incluido en /usr/openwin/bin/xfs. Normalmente, el daemon se inicia desde inetd. Sin embargo, en el ejemplo actual, supondremos que se ha inhabilitado la entrada correcta del archivo /etc/inetd.conf (por ejemplo, mediante el comando fsadmin -d) para que el daemon sólo esté bajo el control del software de Sun Cluster.
El servidor de fuentes X lee de forma predeterminada la información de configuración desde el archivo /usr/openwin/lib/X11/fontserver.cfg. La entrada de catálogo de este archivo contiene una lista de directorios de fuentes disponibles para que el daemon las sirva. El administrador del clúster puede ubicar estos directorios en el sistema de archivos del clúster. Esta ubicación optimiza el uso del servidor de fuentes X en Sun Cluster, ya que permite mantener una única copia de la base de datos de fuentes en el sistema. Si el administrador del clúster desea cambiar la ubicación, debe editar el archivo fontserver.cfg para especificar las nuevas rutas a los directorios de fuentes.
Para facilitar la configuración, el administrador puede incluir también el archivo de configuración en el sistema de archivos del clúster. El daemon xfs proporciona argumentos de línea de comandos que anulan la ubicación predeterminada de este archivo. El tipo de recurso SUNW.xfnts utiliza el siguiente comando para iniciar el daemon bajo el control del software de Sun Cluster.
/usr/openwin/bin/xfs -config location-of-configuration-file/fontserver.cfg \ -port port-number
En la implementación del tipo de recurso SUNW.xfnts, se puede utilizar la propiedad Confdir_list para administrar la ubicación del archivo de configuración fontserver.cfg.
El número de puerto de TCP de escucha utilizado por el daemon del servidor xfs es normalmente el puerto “fs”, definido generalmente en el número 7100 en el archivo /etc/services. Sin embargo, la opción -port incluida por el administrador del clúster con el comando xfs permite a éste anular la configuración predeterminada.
Puede utilizar la propiedad Port_list del tipo de recurso SUNW.xfnts para establecer el valor predeterminado y permitir al administrador del clúster utilizar la opción -port con el comando xfs. Puede definir el valor predeterminado de esta propiedad como 7100/tcp en el archivo RTR. En el método Start de SUNW.xfnts, se pasa la propiedad Port_list a la opción -port en la línea de comandos de xfs. Por lo tanto, no es necesario que el usuario de este tipo de recurso especifique un número de puerto (se establece de forma predeterminada en 7100/tcp). El administrador del clúster puede especificar un valor diferente para la propiedad Port_list al configurar el tipo de recurso.
Esta sección describe varias de las propiedades principales del archivo RTR de SUNW.xfnts, pero no se explica el objetivo de todas ellas. Para obtener una descripción de las propiedades, consulte Establecimiento del recurso y las propiedades del tipo de recurso.
La propiedad de extensión Confdir_list identifica el directorio de configuración (o una lista de directorios) de la siguiente forma:
{ PROPERTY = Confdir_list; EXTENSION; STRINGARRAY; TUNABLE = AT_CREATION; DESCRIPTION = "Las rutas de los directorios de configuración"; }
La propiedad Confdir_list no especifica un valor predeterminado. El administrador del clúster debe especificar un nombre de directorio al crearse el recurso. Esta valor no puede cambiarse más adelante, ya que la capacidad de ajuste se ha limitado a AT_CREATION .
La propiedad Port_list identifica el puerto de escucha utilizado por el daemon del servidor de la siguiente forma:
{ PROPERTY = Port_list; DEFAULT = 7100/tcp; TUNABLE = ANYTIME; }
Como la propiedad declara un valor predeterminado, el administrador del clúster puede especificar un nuevo valor o aceptar el predeterminado cuando se crea el recurso. No se puede cambiar este valor más adelante porque la capacidad de ajuste se ha limitado a AT_CREATION .
Si conoce estas convenciones, podrá identificar las diversas partes del código de ejemplo:
Las funciones de RMAPI empiezan con scha_.
Las funciones de DSDL empiezan con scds_.
Los métodos de rellamada empiezan con xfnts_.
Las funciones escritas por los usuarios empiezan con svc_.
DSDL requiere que cada método de rellamada invoque la función scds_initialize () al comienzo del método. Esta función realiza las operaciones siguientes:
Comprueba y procesa los argumentos de línea de comandos (argc y argv) que la estructura pasa al método del servicio de datos. Este método no tiene que procesar ningún argumento de línea de comandos adicional.
Configura las estructuras de datos internos para que las utilicen otras funciones de DSDL.
Inicializa el entorno de registro.
Valida los valores de análisis del supervisor de fallos.
Utilice la función scds_close() para reclamar los recursos asignados por scds_initialize().
RGM ejecuta el método Start en un nodo del clúster cuando el grupo de recursos que contiene el recurso del servicio de datos se establece en línea en ese nodo o cuando se inhabilita el recurso. En el tipo de recurso de ejemplo SUNW.xfnts, el método xfnts_start activa el daemon de xfs en ese nodo.
El método xfnts_start llama a scds_pmf_start() para iniciar el daemon bajo el control de PMF. Esta utilidad proporciona funciones de notificación de fallos automática y de reinicio, así como integración con el supervisor de fallos.
La primera llamada de xfnts_start va dirigida a scds_initialize (), que realiza algunas funciones de mantenimiento necesarias. Para obtener más información, consulte Función scds_initialize() y la página de comando man scds_initialize(3HA).
Antes de que el método xfnts_start intente iniciar el servidor de fuentes X, llama a svc_validate() para comprobar que se ha establecido la configuración correcta para admitir el daemon de xfs.
rc = svc_validate(scds_handle); if (rc != 0) { scds_syslog(LOG_ERR, "No se ha podido validar la configuración."); return (rc); }
Consulte Método xfnts_validate para obtener información.
El método xfnts_start llama al método svc_start(), definido en el archivo xfnts.c, para iniciar el daemon de xfs. Esta sección describe svc_start().
A continuación se muestra el comando que permite iniciar el daemon de xfs:
# xfs -config config-directory/fontserver.cfg -port port-number |
La propiedad de extensión Confdir_list identifica el directorio de configuración, config-directory, mientras que la propiedad del sistema Port_list identifica el número de puerto, port-number. El administrador del clúster proporciona valores específicos para estas propiedades al configurar el servicio de datos.
El método xfnts_start declara estas propiedades en forma de matriz de cadenas. El método xfnts_start obtiene los valores establecidos por el administrador del clúster mediante el uso de las funciones scds_get_ext_confdir_list() y scds_get_port_list(). Estas funciones se describen en la página de comando man scds_property_functions(3HA).
scha_str_array_t *confdirs; scds_port_list_t *portlist; scha_err_t err; /* get the configuration directory from the confdir_list property */ confdirs = scds_get_ext_confdir_list(scds_handle); (void) sprintf(xfnts_conf, "%s/fontserver.cfg", confdirs->str_array[0]); /* obtain the port to be used by XFS from the Port_list property */ err = scds_get_port_list(scds_handle, &portlist); if (err != SCHA_ERR_NOERR) { scds_syslog(LOG_ERR, "Could not access property Port_list."); return (1); }
Observe que la variable confdirs señala al primer elemento (0) de la matriz.
El método xfnts_start utiliza sprintf() para formar la línea de comandos de xfs.
/* Construct the command to start the xfs daemon. */ (void) sprintf(cmd, "/usr/openwin/bin/xfs -config %s -port %d 2>/dev/null", xfnts_conf, portlist->ports[0].port);
Tenga en cuenta que el resultado se redirige a /dev/null para suprimir los mensajes generados por el daemon.
El método xfnts_start pasa la línea de comandos de xfs a scds_pmf_start() para iniciar el servicio de datos bajo el control de PMF.
scds_syslog(LOG_INFO, "Issuing a start request."); err = scds_pmf_start(scds_handle, SCDS_PMF_TYPE_SVC, SCDS_PMF_SINGLE_INSTANCE, cmd, -1); if (err == SCHA_ERR_NOERR) { scds_syslog(LOG_INFO, "Start command completed successfully."); } else { scds_syslog(LOG_ERR, "Failed to start HA-XFS "); }
Tenga en cuenta los siguientes puntos acerca de la llamada a scds_pmf_start():
El argumento SCDS_PMF_TYPE_SVC identifica el programa que debe iniciarse como aplicación del servicio de datos. Este método también puede iniciar un supervisor de fallos o cualquier otro tipo de aplicación.
El argumento SCDS_PMF_SINGLE_INSTANCE identifica ésta como un recurso de una sola instancia.
El argumento cmd es la línea de comandos generada anteriormente.
El argumento final, -1, especifica el nivel de supervisión secundario. El valor -1 indica que PMF supervisa todos los elementos secundarios, así como el proceso original.
Antes de volver, svc_pmf_start() libera la memoria asignada para la estructura portlist.
scds_free_port_list(portlist); return (err);
Aunque svc_start() devuelva un mensaje satisfactorio, es posible que la aplicación subyacente no haya podido ejecutarse. Por tanto, svc_start() debe analizar la aplicación para verificar si se está ejecutando antes de devolver un mensaje satisfactorio. El análisis debe tener en cuenta también que la aplicación puede no estar disponible inmediatamente, ya que el proceso de inicio tarda algún tiempo. El método svc_start() llama a svc_wait(), que se define en archivo xfnts.c, para verificar que la aplicación se esté ejecutando.
/* Wait for the service to start up fully */ scds_syslog_debug(DBG_LEVEL_HIGH, "Calling svc_wait to verify that service has started."); rc = svc_wait(scds_handle); scds_syslog_debug(DBG_LEVEL_HIGH, "Returned from svc_wait"); if (rc == 0) { scds_syslog(LOG_INFO, "Successfully started the service."); } else { scds_syslog(LOG_ERR, "Failed to start the service."); }
La función svc_wait() llama a scds_get_netaddr_list () para obtener el recurso de dirección de red necesario para analizar la aplicación.
/* obtain the network resource to use for probing */ if (scds_get_netaddr_list(scds_handle, &netaddr)) { scds_syslog(LOG_ERR, "No network address resources found in resource group."); return (1); } /* Return an error if there are no network resources */ if (netaddr == NULL || netaddr->num_netaddrs == 0) { scds_syslog(LOG_ERR, "No network address resource in resource group."); return (1); }
La función svc_wait() obtiene los valores de Start_timeout y Stop_timeout.
svc_start_timeout = scds_get_rs_start_timeout(scds_handle) probe_timeout = scds_get_ext_probe_timeout(scds_handle)
Para contabilizar el tiempo que necesita el servidor para iniciarse, svc_wait() llama a scds_svc_wait() y pasa un valor de tiempo de espera equivalente al tres por ciento del valor de Start_timeout. La función svc_wait() llama a svc_probe() para comprobar que la aplicación se ha iniciado. El método svc_probe() realiza una conexión de socket sencilla con el servidor en el puerto especificado. Si no se puede conectar al puerto, svc_probe() devuelve el valor 100, que indica un fallo completo. Si se establece la conexión, pero falla la desconexión del puerto, svc_probe() devuelve el valor 50.
Cuando se produce un fallo parcial o total de svc_probe(), svc_wait() invoca scds_svc_wait() con un valor de tiempo de espera de 5. El método scds_svc_wait() limita la frecuencia de los análisis a cada 5 segundos. Este método cuenta también el número de intentos hechos para iniciar el servicio. Si el número de intentos supera el valor de la propiedad Retry_count del recurso en el periodo especificado en la propiedad Retry_interval , la función scds_svc_wait() devuelve un fallo. En ese caso, la función svc_start() también devuelve un fallo.
#define SVC_CONNECT_TIMEOUT_PCT 95 #define SVC_WAIT_PCT 3 if (scds_svc_wait(scds_handle, (svc_start_timeout * SVC_WAIT_PCT)/100) != SCHA_ERR_NOERR) { scds_syslog(LOG_ERR, "Service failed to start."); return (1); } do { /* * probe the data service on the IP address of the * network resource and the portname */ rc = svc_probe(scds_handle, netaddr->netaddrs[0].hostname, netaddr->netaddrs[0].port_proto.port, probe_timeout); if (rc == SCHA_ERR_NOERR) { /* Success. Free up resources and return */ scds_free_netaddr_list(netaddr); return (0); } /* Call scds_svc_wait() so that if service fails too if (scds_svc_wait(scds_handle, SVC_WAIT_TIME) != SCHA_ERR_NOERR) { scds_syslog(LOG_ERR, "Service failed to start."); return (1); } /* Rely on RGM to timeout and terminate the program */ } while (1);
Antes de salir, el método xfnts_start llama a scds_close() para reclamar los recursos asignados por scds_initialize (). Para obtener más información, consulte Función scds_initialize() y la página de comando man scds_close(3HA).
Como el método xfnts_start utiliza scds_pmf_start() para iniciar el servicio bajo el control de PMF, xfnts_stop utiliza scds_pmf_stop() para detener el servicio.
La primera llamada de xfnts_stop va dirigida a scds_initialize (), que realiza algunas funciones de mantenimiento necesarias. Para obtener más información, consulte Función scds_initialize() y la página de comando man scds_initialize(3HA).
El método xfnts_stop llama al método svc_stop(), que se define en el archivo xfnts.c, de la siguiente forma:
scds_syslog(LOG_ERR, "Issuing a stop request."); err = scds_pmf_stop(scds_handle, SCDS_PMF_TYPE_SVC, SCDS_PMF_SINGLE_INSTANCE, SIGTERM, scds_get_rs_stop_timeout(scds_handle)); if (err != SCHA_ERR_NOERR) { scds_syslog(LOG_ERR, "Failed to stop HA-XFS."); return (1); } scds_syslog(LOG_INFO, "Successfully stopped HA-XFS."); return (SCHA_ERR_NOERR); /* Successfully stopped */
Tenga en cuenta los siguientes puntos acerca de la llamada de svc_stop() a la función scds_pmf_stop():
El argumento SCDS_PMF_TYPE_SVC identifica el programa que debe detenerse como aplicación del servicio de datos. Este método también puede detener un supervisor de fallos o cualquier otro tipo de aplicación.
El argumento SCDS_PMF_SINGLE_INSTANCE identifica la señal.
El argumento SIGTERM identifica la señal que se utilizará para detener la instancia del recurso. Si la señal no logra detener la instancia, scds_pmf_stop() envía SIGKILL para detenerla y, si esto también falla, retorna un error de tiempo de espera agotado. Consulte la página de comando man scds_pmf_stop(3HA) para obtener más información.
El valor de tiempo de espera es el que indica la propiedad Stop_timeout del recurso.
Antes de salir, el método xfnts_stop llama a scds_close() para reclamar los recursos asignados por scds_initialize (). Para obtener más información, consulte Función scds_initialize() y la página de comando man scds_close(3HA).
RGM llama al método Monitor_start en un nodo para iniciar el supervisor de fallos después de iniciar el recurso en ese nodo. El método xfnts_start utiliza scds_pmf_start() para iniciar el daemon del supervisor bajo el control de PMF.
La primera llamada de xfnts_monitor_start va dirigida a scds_initialize(), que realiza algunas funciones de mantenimiento necesarias. Para obtener más información, consulte Función scds_initialize() y la página de comando man scds_initialize(3HA).
El método xfnts_monitor_start llama al método mon_start , que se define en el archivo xfnts.c, de la siguiente forma:
scds_syslog_debug(DBG_LEVEL_HIGH, "Calling Monitor_start method for resource <%s>.", scds_get_resource_name(scds_handle)); /* Call scds_pmf_start and pass the name of the probe. */ err = scds_pmf_start(scds_handle, SCDS_PMF_TYPE_MON, SCDS_PMF_SINGLE_INSTANCE, "xfnts_probe", 0); if (err != SCHA_ERR_NOERR) { scds_syslog(LOG_ERR, "Failed to start fault monitor."); return (1); } scds_syslog(LOG_INFO, "Started the fault monitor."); return (SCHA_ERR_NOERR); /* Successfully started Monitor */ }
Tenga en cuenta los siguientes puntos acerca de la llamada de svc_mon_start() a la función scds_pmf_start():
El argumento SCDS_PMF_TYPE_MON identifica el programa que se va a iniciar como supervisor de fallos. Este método también puede iniciar un servicio de datos o cualquier otro tipo de aplicación.
El argumento SCDS_PMF_SINGLE_INSTANCE identifica ésta como un recurso de una sola instancia.
El argumento xfnts_probe identifica el daemon del supervisor que se va a iniciar. Se supone que el daemon del supervisor debe encontrarse en el mismo directorio que los demás programas de rellamada.
El argumento final, 0, especifica el nivel de supervisión secundario. En este caso, este valor especifica que PMF sólo supervisa el daemon.
Antes de salir, el método xfnts_monitor_start llama a scds_close() para reclamar los recursos asignados por scds_initialize (). Para obtener más información, consulte Función scds_initialize() y la página de comando man scds_close(3HA).
Como el método xfnts_monitor_start utiliza scds_pmf_start() para iniciar el daemon del supervisor bajo el control de PMF, xfnts_monitor_stop utiliza scds_pmf_stop() para detenerlo.
La primera llamada de xfnts_monitor_stop va dirigida a scds_initialize(), que realiza algunas funciones de mantenimiento necesarias. Para obtener más información, consulte Función scds_initialize() y la página de comando man scds_initialize(3HA).
El método xfnts_monitor_stop() llama al método mon_stop , que se define en el archivo xfnts.c, de la siguiente forma:
scds_syslog_debug(DBG_LEVEL_HIGH, "Calling scds_pmf_stop method"); err = scds_pmf_stop(scds_handle, SCDS_PMF_TYPE_MON, SCDS_PMF_SINGLE_INSTANCE, SIGKILL, scds_get_rs_monitor_stop_timeout(scds_handle)); if (err != SCHA_ERR_NOERR) { scds_syslog(LOG_ERR, "Failed to stop fault monitor."); return (1); } scds_syslog(LOG_INFO, "Stopped the fault monitor."); return (SCHA_ERR_NOERR); /* Successfully stopped monitor */ }
Tenga en cuenta los siguientes puntos acerca de la llamada de svc_mon_stop() a la función scds_pmf_stop():
El argumento SCDS_PMF_TYPE_MON identifica el programa que se va a detener como supervisor de fallos. Este método también puede detener un servicio de datos o cualquier otro tipo de aplicación.
El argumento SCDS_PMF_SINGLE_INSTANCE identifica ésta como un recurso de una sola instancia.
El argumento SIGKILL la señal que se utilizará para detener la instancia del recurso. Si esta señal no puede detener la instancia, scds_pmf_stop() devuelve un error de tiempo de espera agotado. Consulte la página de comando man scds_pmf_stop(3HA) para obtener más información.
El valor de tiempo de espera es el que se ha definido en la propiedad Monitor_stop_timeout del recurso.
Antes de salir, el método xfnts_monitor_stop llama a scds_close() para reclamar los recursos asignados por scds_initialize (). Para obtener más información, consulte Función scds_initialize() y la página de comando man scds_close(3HA)
RGM llama al método Monitor_check cada vez que el supervisor de fallos intenta realizar una recuperación ante fallos del grupo de recursos que contiene el recurso en otro nodo. El método xfnts_monitor_check llama a svc_validate() para comprobar si se ha establecido la configuración correcta para admitir el daemon de xfs. Consulte Método xfnts_validate para obtener información. A continuación se muestra el código de xfnts_monitor_check:
/* Process the arguments passed by RGM and initialize syslog */ if (scds_initialize(&scds_handle, argc, argv) != SCHA_ERR_NOERR) { scds_syslog(LOG_ERR, "Failed to initialize the handle."); return (1); } rc = svc_validate(scds_handle); scds_syslog_debug(DBG_LEVEL_HIGH, "monitor_check method " "was called and returned <%d>.", rc); /* Free up all the memory allocated by scds_initialize */ scds_close(&scds_handle); /* Return the result of validate method run as part of monitor check */ return (rc); }
RGM no llama directamente al método PROBE, sino que llama a Monitor_start para iniciar el supervisor una vez iniciado un recurso en el nodo. El método xfnts_monitor_start inicia el supervisor de fallos bajo el control de PMF. El método xfnts_monitor_stop detiene el supervisor de fallos.
El supervisor de fallos SUNW.xfnts realiza las operaciones siguientes:
Supervisa periódicamente el estado del daemon del servidor xfs mediante las utilidades diseñadas específicamente para comprobar servicios simples basados en TCP, como xfs.
Realiza un seguimiento de los problemas que encuentra la aplicación en un intervalo de tiempo (mediante las propiedades Retry_count y Retry_interval) y decide si se debe reiniciar el servicio de datos o realizar una recuperación ante fallos en caso de que falle por completo la aplicación. Las funciones scds_fm_action() y scds_fm_sleep() proporcionan soporte integrado para este mecanismo de rastreo y toma de decisiones.
Implementa el reinicio o la recuperación ante fallos utilizando scds_fm_action ().
Actualiza el estado del recurso y lo facilita a las herramientas administrativas e interfaces gráficas de usuario.
El método xfonts_probe implementa un bucle. Antes de implementar el bucle, xfonts_probe realiza las siguientes operaciones:
Recupera los recursos de dirección de red para el recurso xfnts de la siguiente forma:
/* Get the ip addresses available for this resource */ if (scds_get_netaddr_list(scds_handle, &netaddr)) { scds_syslog(LOG_ERR, "No network address resource in resource group."); scds_close(&scds_handle); return (1); } /* Return an error if there are no network resources */ if (netaddr == NULL || netaddr->num_netaddrs == 0) { scds_syslog(LOG_ERR, "No network address resource in resource group."); return (1); }
Llama a scds_fm_sleep() y pasa el valor de Thorough_probe_interval como valor de tiempo de espera. El análisis permanece inactivo durante el tiempo indicado en Thorough_probe_interval, como se indica a continuación:
timeout = scds_get_ext_probe_timeout(scds_handle); for (;;) { /* * sleep for a duration of thorough_probe_interval between * successive probes. */ (void) scds_fm_sleep(scds_handle, scds_get_rs_thorough_probe_interval(scds_handle));
El método xfnts_probe implementa el siguiente bucle:
for (ip = 0; ip < netaddr->num_netaddrs; ip++) { /* * Grab the hostname and port on which the * health has to be monitored. */ hostname = netaddr->netaddrs[ip].hostname; port = netaddr->netaddrs[ip].port_proto.port; /* * HA-XFS supports only one port and * hence obtain the port value from the * first entry in the array of ports. */ ht1 = gethrtime(); /* Latch probe start time */ scds_syslog(LOG_INFO, "Probing the service on port: %d.", port); probe_result = svc_probe(scds_handle, hostname, port, timeout); /* * Update service probe history, * take action if necessary. * Latch probe end time. */ ht2 = gethrtime(); /* Convert to milliseconds */ dt = (ulong_t)((ht2 - ht1) / 1e6); /* * Compute failure history and take * action if needed */ (void) scds_fm_action(scds_handle, probe_result, (long)dt); } /* Each net resource */ } /* Keep probing forever */
La función svc_probe() implementa la lógica del análisis. El valor de devolución de svc_probe() se pasa a scds_fm_action (), que determina si se debe reiniciar la aplicación, realizar una recuperación ante fallos del grupo de recurso o no realizar ninguna acción.
La función svc_probe () establece una conexión de socket simple al puerto especificado mediante una llamada a scds_fm_tcp_connect(). Si falla la conexión, svc_probe() devuelve el valor 100, que indica la existencia de un fallo completo. Si la conexión se establece con éxito, pero falla la desconexión, svc_probe() devuelve el valor 50, que indica la existencia de un fallo parcial. Si la conexión y desconexión se realizan satisfactoriamente, svc_probe() devuelve el valor 0, que indica que no hay fallos.
A continuación se muestra el código de svc_probe():
int svc_probe(scds_handle_t scds_handle, char *hostname, int port, int timeout) { int rc; hrtime_t t1, t2; int sock; char testcmd[2048]; int time_used, time_remaining; time_t connect_timeout; /* * probe the data service by doing a socket connection to the port * specified in the port_list property to the host that is * serving the XFS data service. If the XFS service which is configured * to listen on the specified port, replies to the connection, then * the probe is successful. Else we will wait for a time period set * in probe_timeout property before concluding that the probe failed. */ /* * Use the SVC_CONNECT_TIMEOUT_PCT percentage of timeout * to connect to the port */ connect_timeout = (SVC_CONNECT_TIMEOUT_PCT * timeout)/100; t1 = (hrtime_t)(gethrtime()/1E9); /* * the probe makes a connection to the specified hostname and port. * The connection is timed for 95% of the actual probe_timeout. */ rc = scds_fm_tcp_connect(scds_handle, &sock, hostname, port, connect_timeout); if (rc) { scds_syslog(LOG_ERR, "Failed to connect to port <%d> of resource <%s>.", port, scds_get_resource_name(scds_handle)); /* this is a complete failure */ return (SCDS_PROBE_COMPLETE_FAILURE); } t2 = (hrtime_t)(gethrtime()/1E9); /* * Compute the actual time it took to connect. This should be less than * or equal to connect_timeout, the time allocated to connect. * If the connect uses all the time that is allocated for it, * then the remaining value from the probe_timeout that is passed to * this function will be used as disconnect timeout. Otherwise, the * the remaining time from the connect call will also be added to * the disconnect timeout. * */ time_used = (int)(t2 - t1); /* * Use the remaining time(timeout - time_took_to_connect) to disconnect */ time_remaining = timeout - (int)time_used; /* * If all the time is used up, use a small hardcoded timeout * to still try to disconnect. This will avoid the fd leak. */ if (time_remaining <= 0) { scds_syslog_debug(DBG_LEVEL_LOW, "svc_probe used entire timeout of " "%d seconds during connect operation and exceeded the " "timeout by %d seconds. Attempting disconnect with timeout" " %d ", connect_timeout, abs(time_used), SVC_DISCONNECT_TIMEOUT_SECONDS); time_remaining = SVC_DISCONNECT_TIMEOUT_SECONDS; } /* * Return partial failure in case of disconnection failure. * Reason: The connect call is successful, which means * the application is alive. A disconnection failure * could happen due to a hung application or heavy load. * If it is the later case, don't declare the application * as dead by returning complete failure. Instead, declare * it as partial failure. If this situation persists, the * disconnect call will fail again and the application will be * restarted. */ rc = scds_fm_tcp_disconnect(scds_handle, sock, time_remaining); if (rc != SCHA_ERR_NOERR) { scds_syslog(LOG_ERR, "Failed to disconnect to port %d of resource %s.", port, scds_get_resource_name(scds_handle)); /* this is a partial failure */ return (SCDS_PROBE_COMPLETE_FAILURE/2); } t2 = (hrtime_t)(gethrtime()/1E9); time_used = (int)(t2 - t1); time_remaining = timeout - time_used; /* * If there is no time left, don't do the full test with * fsinfo. Return SCDS_PROBE_COMPLETE_FAILURE/2 * instead. This will make sure that if this timeout * persists, server will be restarted. */ if (time_remaining <= 0) { scds_syslog(LOG_ERR, "Probe timed out."); return (SCDS_PROBE_COMPLETE_FAILURE/2); } /* * The connection and disconnection to port is successful, * Run the fsinfo command to perform a full check of * server health. * Redirect stdout, otherwise the output from fsinfo * ends up on the console. */ (void) sprintf(testcmd, "/usr/openwin/bin/fsinfo -server %s:%d > /dev/null", hostname, port); scds_syslog_debug(DBG_LEVEL_HIGH, "Checking the server status with %s.", testcmd); if (scds_timerun(scds_handle, testcmd, time_remaining, SIGKILL, &rc) != SCHA_ERR_NOERR || rc != 0) { scds_syslog(LOG_ERR, "Failed to check server status with command <%s>", testcmd); return (SCDS_PROBE_COMPLETE_FAILURE/2); } return (0); }
Una vez finalizado, svc_probe() devuelve un valor que indica que el proceso se ha realizado con éxito (0), o que se ha producido un fallo parcial (50) o uno completo (100). El método xfnts_probe pasa este valor a scds_fm_action().
El método xfnts_probe llama a scds_fm_action() para determinar la acción que debe realizarse. La lógica de scds_fm_action() es la siguiente:
Mantiene un historial de fallos acumulativos en el intervalo especificado en la propiedad Retry_interval.
Si el fallo acumulativo alcanza el valor (fallo completo), debe reiniciarse el servicio de datos. Si se supera Retry_interval, hay que poner a cero el historial.
Si el número de reinicios supera el valor de la propiedad Retry_count durante el tiempo especificado por Retry_interval, debe realizarse una recuperación ante fallos del servicio de datos.
Por ejemplo, supongamos que el análisis establece una conexión con el servidorxfs, pero no logra desconectarse satisfactoriamente. Esto indica que el servidor está en ejecución, pero que es posible que esté bloqueado o bajo una carga temporal. Al fallar la desconexión, se envía un fallo parcial ( 50) a scds_fm_action(). Este valor está por debajo del umbral para reiniciar el servicio de datos, pero se mantiene el valor en el historial de fallos.
Si, durante el siguiente análisis, el servidor no puede desconectarse otra vez, el valor 50 se agrega al historial de fallos que mantiene scds_fm_action (). El valor de fallo acumulativo es ahora de 100, por lo que scds_fm_action() reinicia el servicio de datos.
RGM llama al método Validate cuando se crea un recurso y el administrador del clúster actualiza las propiedades del recurso o del grupo que lo contiene. RGM invoca Validate antes de que se apliquen la creación o la actualización y un código de salida fallido del método en cualquier nodo provoque la cancelación de la creación o actualización.
RGM sólo llama a Validate cuando el administrador del clúster cambia las propiedades de un recurso o un grupo de recursos, o cuando un supervisor establece las propiedades de recursos Status y Status_msg. RGM no llama a Validate cuando esta herramienta establece las propiedades.
El método Monitor_check también llama de forma explícita a Validate cada vez que el método PROBE intenta realizar una recuperación ante fallos del servicio de datos en un nuevo nodo.
RGM llama a Validate con argumentos adicionales a aquéllos transferidos a otros métodos, incluidos los valores y las propiedades que se están actualizando. La llamada a scds_initialize() al comienzo de xfnts_validate analiza todos los argumentos que RGM pasa a xfnts_validate y almacena la información en el argumento scds_handle. La subrutinas invocadas por xfnts_validate utilizan esta información.
El método xfnts_validate llama a svc_validate(), que comprueba las siguientes condiciones:
La propiedad Confdir_list del recurso se ha configurado y define un único directorio.
scha_str_array_t *confdirs; confdirs = scds_get_ext_confdir_list(scds_handle); /* Return error if there is no confdir_list extension property */ if (confdirs == NULL || confdirs->array_cnt != 1) { scds_syslog(LOG_ERR, "Property Confdir_list is not set properly."); return (1); /* Validation failure */ }
El directorio especificado por Confdir_list contiene el archivo fontserver.cfg.
(void) sprintf(xfnts_conf, "%s/fontserver.cfg", confdirs->str_array[0]); if (stat(xfnts_conf, &statbuf) != 0) { /* * suppress lint error because errno.h prototype * is missing void arg */ scds_syslog(LOG_ERR, "Failed to access file <%s> : <%s>", xfnts_conf, strerror(errno)); /*lint !e746 */ return (1); }
El binario del daemon de servidor está accesible en el nodo del clúster.
if (stat("/usr/openwin/bin/xfs", &statbuf) != 0) { scds_syslog(LOG_ERR, "Cannot access XFS binary : <%s> ", strerror(errno)); return (1); }
La propiedad Port_list especifica un solo puerto.
scds_port_list_t *portlist; err = scds_get_port_list(scds_handle, &portlist); if (err != SCHA_ERR_NOERR) { scds_syslog(LOG_ERR, "Could not access property Port_list: %s.", scds_error_string(err)); return (1); /* Validation Failure */ } #ifdef TEST if (portlist->num_ports != 1) { scds_syslog(LOG_ERR, "Property Port_list must have only one value."); scds_free_port_list(portlist); return (1); /* Validation Failure */ } #endif
El grupo de recursos que contiene el servicio de datos debe contener también, al menos, un recurso de dirección de red.
scds_net_resource_list_t *snrlp; if ((err = scds_get_rs_hostnames(scds_handle, &snrlp)) != SCHA_ERR_NOERR) { scds_syslog(LOG_ERR, "No network address resource in resource group: %s.", scds_error_string(err)); return (1); /* Validation Failure */ } /* Return an error if there are no network address resources */ if (snrlp == NULL || snrlp->num_netresources == 0) { scds_syslog(LOG_ERR, "No network address resource in resource group."); rc = 1; goto finished; }
Antes de retornar, svc_validate() libera todos los recursos asignados.
finished: scds_free_net_list(snrlp); scds_free_port_list(portlist); return (rc); /* return result of validation */
Antes de salir, el método xfnts_validate llama a scds_close() para reclamar los recursos asignados por scds_initialize (). Para obtener más información, consulte Función scds_initialize() y la página de comando man scds_close(3HA)
RGM llama al método Update para notificar a un recurso en ejecución que sus propiedades han cambiado. Las únicas propiedades que se pueden cambiar para el servicio de datos de xfnts corresponden al supervisor de fallos. Por lo tanto, cada vez que se actualiza una propiedad, el método xfnts_update llama a scds_pmf_restart_fm() para reiniciar el supervisor de fallos.
/* check if the Fault monitor is already running and if so stop * and restart it. The second parameter to scds_pmf_restart_fm() * uniquely identifies the instance of the fault monitor that needs * to be restarted. */ scds_syslog(LOG_INFO, "Restarting the fault monitor."); result = scds_pmf_restart_fm(scds_handle, 0); if (result != SCHA_ERR_NOERR) { scds_syslog(LOG_ERR, "Failed to restart fault monitor."); /* Free up all the memory allocated by scds_initialize */ scds_close(&scds_handle); return (1); } scds_syslog(LOG_INFO, "Completed successfully.");
El segundo argumento de scds_pmf_restart_fm() identifica de forma exclusiva la instancia del supervisor de fallos que debe reiniciarse en caso de existir varias. El valor 0 del ejemplo indica que sólo hay una instancia del supervisor de fallos.