Sun Cluster: Guía del desarrollador de los servicios de datos del sistema operativo Solaris

Capítulo 8 Ejemplo de implementación del tipo de recurso con DSDL

En este capítulo se describe un tipo de recurso de ejemplo, SUNW.xfnts, implementado con DSDL. El servicio de datos se escribe en C. La aplicación subyacente es el servidor de fuentes X, un servicio basado en TCP/IP.

La información de este capítulo incluye.

Servidor de fuentes X

El servidor de fuentes X es un servicio sencillo basado en TCP/IP que sirve archivos de fuentes a sus 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 binario de servidor /usr/openwin/bin/xfs. El daemon normalmente se inicia desde inetd, sin embargo, para el ejemplo actual, suponemos que la entrada adecuada del archivo /etc/inetd.conf se ha inhabilitado (por ejemplo, con la orden fsadmin -d) así que el daemon está controlado únicamente por Sun Cluster.

Archivo de configuración del servidor de fuentes X

De forma predeterminada, el servidor de fuentes X lee la información de configuración en el archivo /usr/openwin/lib/X11/fontserver.cfg cuya entrada de catálogo contiene una lista de directorios de fuentes disponibles para el daemon a fin que pueda realizar el servicio. El administrador del clúster puede ubicar los directorios de fuentes en el sistema global de archivos (para optimizar la utilización del servidor de fuentes X en Sun Cluster, manteniendo una única copia de la base de datos de las fuentes en el sistema). En ese caso, el administrador debe editar fontserver.cfg para reflejar las nuevas rutas de los directorios de fuentes.

Para facilitar la configuración, el administrador también puede colocar el archivo de configuración en el sistema global de archivos. El daemon xfs proporciona argumentos de línea de órdenes para anular la ubicación integrada y predeterminada de este archivo. El tipo de recurso SUNW.xfnts utiliza la orden siguiente para iniciar el daemon, controlado por Sun Cluster.


/usr/openwin/bin/xfs -config <ubicación_del_archivo_de_configuración>/fontserver.cfg \
-port <número_puerto>

En la implementación del tipo de recurso SUNW.xfnts se puede usar la propiedad Confdir_list para gestionar la ubicación del archivo de configuración fontserver.cfg.

Número del puerto de TCP

El número de puerto TCP en el que el daemon del servidor xfs recibe suele ser el puerto “fs” (definido normalmente como 7100 en el archivo /etc/services). Sin embargo, la opción -port de la línea de órdenes de xfs permite al administrador del sistema anular el valor predeterminado. La propiedad Port_list del tipo de recurso SUNW.xfnts se puede utilizar para establecer el valor predeterminado y admitir la utilización de la opción -port en la línea de órdenes de xfs. Puede definir el valor predeterminado de esta propiedad como 7100/tcp en el archivo RTR. En el método SUNW.xfnts Start se pasa Port_list a la opción -port de la línea de órdenes de xfs. Por tanto, un usuario de este tipo de recurso no tiene que especificar un número de puerto (el puerto predeterminado es 7100/tcp) pero sí puede especificar un puerto diferente si lo desea cuando configure el tipo de recurso, indicando un valor diferente para la propiedad Port_list.

Convenciones de asignación de nombres

Puede identificar los diferentes fragmentos del código de ejemplo si tiene presentes las convenciones siguientes:

Archivo RTR de SUNW.xfnts

En esta sección se describen varias propiedades clave del archivo RTR de SUNW.xfnts, pero no se explica el objetivo de todas ellas. Para conocer estas descripciones, 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), como se indica a continuación.


{
        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 directorio en el momento de la creación del recurso. Este valor no se puede modificar más adelante, porque la posibilidad de ajuste está limitada al momento AT_CREATION.

La propiedad Port_list identifica el puerto en el que recibe el daemon del servidor, como sigue:


{
        PROPERTY = Port_list;
        DEFAULT = 7100/tcp;
        TUNABLE = AT_CREATION;
}

Dado que la propiedad declara un valor predeterminado, el administrador del clúster puede especificar un valor nuevo o aceptar el predeterminado en el momento de la creación del recurso. Este valor no se puede modificar más adelante, porque la posibilidad de ajuste está limitada al momento AT_CREATION.

Función scds_initialize()

DSDL requiere que todos los métodos de rellamada invoquen la función scds_initialize(3HA) al principio del método. Esta función realiza las operaciones siguientes:

Utilice la función scds_close() para reclamar los recursos asignados por scds_initialize().

Método xfnts_start

RGM invoca el método Start en un nodo del clúster cuando el grupo de recursos que contiene el recurso del servicio de datos se pone en línea en ese nodo o cuando se habilita el nodo. En el tipo de recurso de ejemplo, SUNW.xfnts, el método xfnts_start activa el daemon xfs en ese nodo.

El método xfnts_start invoca scds_pmf_start() para iniciar el daemon en PMF. PMF proporciona funciones automáticas de notificación de fallo y reinicio, además de integración con el supervisor de fallos.


Nota –

La primera llamada de xfnts_start es a scds_initialize(), que ejecuta ciertas tareas domésticas necesarias (Función scds_initialize() y la página de comando man scds_initialize(3HA) ofrecen información más detallada).


Validación del servicio antes de empezar

Antes de iniciar el servidor de fuentes X, el método xfnts_start invoca svc_validate() para verificar que haya una configuración adecuada para admitir el daemon xfs (consulte Método xfnts_validate para obtener más detalles), como se indica a continuación:


rc = svc_validate(scds_handle);
   if (rc != 0) {
      scds_syslog(LOG_ERR,
          "No se ha podido validar la configuración.");
      return (rc);
   }

Inicio del servicio

El método xfnts_start invoca el método svc_start(), definido en xfnts.c para iniciar el daemon xfs. Esta sección describe svc_start().

La orden para ejecutar el daemon xfs es la siguiente:


xfs -config directorio_config/fontserver.cfg -port número_puerto

La propiedad de extensión Confdir_list identifica el directorio_config y la propiedad de sistema Port_list identifica el número_puerto. Cuando el administrador del clúster configura el servicio de datos, proporciona valores específicos para estas propiedades.

El método xfnts_start declara estas propiedades como matrices de secuencias y obtiene los valores que fija el administrador con las funciones scds_get_ext_confdir_list() y scds_get_port_list() (descritas en scds_property_functions(3HA)), como sigue:


scha_str_array_t *confdirs;
scds_port_list_t *portlist;
scha_err_t   err;

   /* obtener el directorio de configuración de la propiedad confdir_list */
   confdirs = scds_get_ext_confdir_list(scds_handle);

   (void) sprintf(xfnts_conf, "%s/fontserver.cfg", confdirs->str_array[0]);

   /* obtener el puerto que va a usar XFS de la propiedad Port_list */
   err = scds_get_port_list(scds_handle, &portlist);
   if (err != SCHA_ERR_NOERR) {
      scds_syslog(LOG_ERR,
          "No se puede acceder a la propiedad Port_list.");
      return (1);
   }

Observe que la variable confdirs apunta al primer elemento (0) de la matriz.

El método xfnts_start utiliza sprintf para formar la línea de órdenes para xfs como se muestra a continuación.


/* Construir la orden para que inicie el daemon xfs. */
   (void) sprintf(cmd,
       "/usr/openwin/bin/xfs -config %s -port %d 2>/dev/null",
       xfnts_conf, portlist->ports[0].port);

Observe que la salida se redirige a dev/null para suprimir los mensajes que genera el daemon.

El método xfnts_start pasa la línea de órdenes xfs a scds_pmf_start() para iniciar el servicio de datos controlado por PMF, como se indica a continuación.


scds_syslog(LOG_INFO, "Emitir una solicitud de inicio.");
   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,
          "Orden de inicio completada satisfactoriamente.");
   } else {
      scds_syslog(LOG_ERR,
          "No se ha podido iniciar HA-XFS ");
   }

Observe los siguientes aspectos de la llamada a scds_pmf_start().

Antes de volver, svc_pmf_start() libera la memoria asignada para la estructura portlist como se muestra a continuación.


scds_free_port_list(portlist);
return (err);

Retorno desde svc_start()

Aún cuando la función svc_start() dé un retorno satisfactorio, es posible que la aplicación subyacente no se haya iniciado correctamente. 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 es posible que la aplicación no esté disponible inmediatamente porque tarda un tiempo en iniciarse. El método svc_start() invoca svc_wait(), que se define en xfnts.c, para verificar que la aplicación está en ejecución, como se indica a continuación:


/* Esperar a que el servicio se inicie completamente */
   scds_syslog_debug(DBG_LEVEL_HIGH,
       "Llamar a svc_wait para verificar que se haya iniciado el servicio.");

   rc = svc_wait(scds_handle);

   scds_syslog_debug(DBG_LEVEL_HIGH,
       "Devuelto desde svc_wait");

   if (rc == 0) {
      scds_syslog(LOG_INFO, "El servicio se ha iniciado satisfactoriamente.");
   } else {
      scds_syslog(LOG_ERR, "No se ha podido iniciar el servicio.");
   }

La función svc_wait() invoca scds_get_netaddr_list(3HA) para obtener los recursos de dirección de red necesarios para analizar la aplicación, como se indica a continuación:


/* obtener el recurso de red para el análisis */
   if (scds_get_netaddr_list(scds_handle, &netaddr)) {
      scds_syslog(LOG_ERR,
          "No se han encontrado recursos de dirección de red en grupo de recursos.");
      return (1);
   }

   /* Devolver un error si no hay recursos de red */
   if (netaddr == NULL || netaddr->num_netaddrs == 0) {
      scds_syslog(LOG_ERR,
          "No hay recursos de dirección de red en el grupo de recursos.");
      return (1);
   }

Después, svc_wait() obtiene los valores start_timeout y stop_timeout como se indica a continuación.


svc_start_timeout = scds_get_rs_start_timeout(scds_handle)
   probe_timeout = scds_get_ext_probe_timeout(scds_handle)

Para justificar el tiempo que puede tardar en iniciarse el servidor, svc_wait() invoca scds_svc_wait() y pasa un valor de tiempo de espera equivalente a un tres por ciento del valor start_timeout. A continuación, svc_wait() invoca svc_probe() para verificar si la aplicación se ha iniciado. El método svc_probe() realiza una conexión de zócalo sencilla con el servidor en el puerto especificado. Si no puede conectarse con el puerto, svc_probe() devuelve un valor de 100, que indica un fallo total. Si la conexión pasa, pero la desconexión del puerto falla, svc_probe() devuelve un valor de 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 por la propiedad Retry_interval del recurso, 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, "No se ha podido iniciar el servicio.");
      return (1);
   }

   do {
      /*
       * analizar el servicio de datos en la dirección IP del
       * recurso de red y el nombre de puerto
       */
      rc = svc_probe(scds_handle,
          netaddr->netaddrs[0].hostname,
          netaddr->netaddrs[0].port_proto.port, probe_timeout);
      if (rc == SCHA_ERR_NOERR) {
         /* Satisfactorio. Liberar recursos y retornar */
         scds_free_netaddr_list(netaddr);
         return (0);
      }

       /* Invocar scds_svc_wait() por si el servicio también falla */
      if (scds_svc_wait(scds_handle, SVC_WAIT_TIME)
         != SCHA_ERR_NOERR) {
         scds_syslog(LOG_ERR, "No se ha podido iniciar el servicio.");
         return (1);
      }

   /* Confiar en el tiempo de espera de RGM y terminar el programa */
   } while (1);


Nota –

Antes de salir, el método xfnts_start invoca scds_close() para reclamar recursos asignados por scds_initialize (). Consulte Función scds_initialize() y la página de comando man scds_close(3HA) para obtener más detalles.


Método xfnts_stop

Dado que el método xfnts_start utiliza scds_pmf_start() para iniciar el servicio bajo PMF, xfnts_stop emplea scds_pmf_stop() para detenerlo.


Nota –

La primera llamada en xfnts_stop es a scds_initialize(), que ejecuta ciertas tareas domésticas necesarias (Función scds_initialize() y la página de comando man de scds_initialize(3HA) ofrecen información más detallada).


El método xfnts_stop invoca el método svc_stop(), definido en xfnts.c como sigue:


scds_syslog(LOG_ERR, "Emitir una solicitud de inicio.");
   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,
          "No se ha podido detener HA-XFS.");
      return (1);
   }

   scds_syslog(LOG_INFO,
       "HA-XFS detenido satisfactoriamente.");
   return (SCHA_ERR_NOERR); /* Detenido satisfactoriamente */

Observe lo siguiente sobre la llamada de svc_stop() a la función scds_pmf_stop().


Nota –

Antes de salir, el método xfnts_stop invoca scds_close() para reclamar los recursos asignados por scds_initialize(). Consulte Función scds_initialize() y la página de comando man scds_close(3HA) para obtener más detalles.


Método xfnts_monitor_start

RGM invoca el método Monitor_start en un nodo para iniciar el supervisor de fallos después de que se inicie un recurso en el nodo. El método xfnts_monitor_start utiliza scds_pmf_start() para iniciar el daemon del supervisor bajo PMF.


Nota –

La primera llamada de xfnts_monitor_start es a scds_initialize(), que ejecuta ciertas tareas domésticas necesarias (Función scds_initialize() y la página de comando man scds_initialize(3HA) ofrecen información más detallada).


El método xfnts_monitor_start invoca el método mon_start, definido en xfnts.c como sigue:


scds_syslog_debug(DBG_LEVEL_HIGH,
      "Llamar al método Monitor_start para el recurso <%s>.",
      scds_get_resource_name(scds_handle));

    /* Invocar scds_pmf_start y pasar el nombre del analizador. */
   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,
          "No se ha podido iniciar el supervisor de fallos.");
      return (1);
   }

   scds_syslog(LOG_INFO,
       "Se ha iniciado el supervisor de fallos.");

   return (SCHA_ERR_NOERR); /* Supervisor de fallos iniciado satisfactoriamente */
}

Observe lo siguiente sobre la llamada de svc_mon_start() a la función scds_pmf_start().


Nota –

Antes de salir, el método xfnts_monitor_start invoca scds_close() para reclamar recursos asignados por scds_initialize(). Consulte Función scds_initialize() y la página de comando man scds_close(3HA) para obtener más detalles.


Método xfnts_monitor_stop

Dado que el método xfnts_monitor_start utiliza scds_pmf_start() para iniciar el daemon del supervisor bajo PMF, xfnts_monitor_stop emplea scds_pmf_stop() para detener el daemon.


Nota –

La primera llamada de xfnts_monitor_stop es a scds_initialize(), que ejecuta ciertas tareas domésticas necesarias (Función scds_initialize() y la página de comando man scds_initialize(3HA) ofrecen información más detallada.


El método xfnts_monitor_stop() invoca el método mon_stop, que se define en xfnts.c como se indica a continuación.


scds_syslog_debug(DBG_LEVEL_HIGH,
      "Llamar al método scds_pmf_stop");

   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,
          "No se ha podido detener el supervisor de fallos.");
      return (1);
   }

   scds_syslog(LOG_INFO,
       "Se ha detenido el supervisor de fallos.");

   return (SCHA_ERR_NOERR); /* Supervisor de fallos detenido satisfactoriamente */
}

Observe lo siguiente sobre la llamada de svc_mon_stop() a la función scds_pmf_stop().


Nota –

Antes de salir, el método xfnts_monitor_stop invoca scds_close() para reclamar recursos asignados por scds_initialize(). Consulte Función scds_initialize() y la página de comando man scds_close(3HA) para obtener más detalles.


Método xfnts_monitor_check

RGM invoca el método Monitor_check siempre que el supervisor de fallos intenta realizar una operación de recuperación de fallos a otro nodo con el grupo de recursos donde se encuentra el recurso en cuestión. El método xfnts_monitor_check invoca el método svc_validate() para verificar que exista una configuración adecuada para admitir el daemon xfs (consulte Método xfnts_validate para obtener más información). El código de xfnts_monitor_check es el siguiente.


   /* Procesar los argumentos que pasa RGM e inicializar syslog */
   if (scds_initialize(&scds_handle, argc, argv) != SCHA_ERR_NOERR)
{
      scds_syslog(LOG_ERR, "No se ha podido iniciar el manejo.");
      return (1);
   }

   rc =  svc_validate(scds_handle);
   scds_syslog_debug(DBG_LEVEL_HIGH,
       "método monitor_check "
       "se ha llamado y ha devuelto <%d>.", rc);

   /* Liberar toda la memoria asignada por scds_initialize */
   scds_close(&scds_handle);

   /* Devolver el resultado de la ejecución del método de validación
    * dentro de la comprobación del supervisor */
   return (rc);
}

Supervisor de fallos SUNW.xfnts

RGM no invoca directamente el método PROBE, sino que invoca el método Monitor_start para iniciar el supervisor después de que se inicie un recurso en un 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:

Bucle principal de xfonts_probe

El método xfonts_probe implementa un bucle. Antes de hacerlo, xfonts_probe ejecuta estas acciones:

El método xfnts_probe implementa el bucle como sigue:


for (ip = 0; ip < netaddr->num_netaddrs; ip++) {
         /*
          * Tomar el nombre de sistema y puerto en el que se va a
          * supervisar el estado.
          */
         hostname = netaddr->netaddrs[ip].hostname;
         port = netaddr->netaddrs[ip].port_proto.port;
         /*
          * HA-XFS admite un solo puerto y obtiene el
          * valor del puerto de la primera
          * entrada de la matriz de puertos.
          */
         ht1 = gethrtime(); /* Bloquear el tiempo de inicio del análisis */
         scds_syslog(LOG_INFO, "Analizar el servicio en el puerto: %d.", port);

         probe_result =
         svc_probe(scds_handle, hostname, port, timeout);

         /*
          * Actualizar historial de análisis de servicio,
          * tomar medidas si fuera necesario.
          * Bloquear el tiempo de finalización del análisis.
          */
         ht2 = gethrtime();

         /* Convertir a milisegundos */
         dt = (ulong_t)((ht2 - ht1) / 1e6);

         /*
          * Calcular el historial de fallos y tomar
          * medidas si corresponde
          */
         (void) scds_fm_action(scds_handle,
             probe_result, (long)dt);
      }   /* Cada recurso de red */
   }    /* Seguir analizando indefinidamente */

La función svc_probe() implementa la lógica del análisis. El valor de retorno de svc_probe() se pasa a scds_fm_action(), que determina si debe reiniciar la aplicación, realizar una recuperación de fallos del grupo de recursos o si no debe hacer nada.

Función svc_probe()

La función svc_probe() establece una conexión de zócalo simple al puerto especificado, mediante una llamada a scds_fm_tcp_connect(). Si falla la conexión, svc_probe() retorna un valor de 100 que indica que el fallo es total. Si la conexión es satisfactoria, pero falla la desconexión, svc_probe() devuelve un valor de 50, lo que indica un fallo parcial. Si la conexión y la desconexión son satisfactorias, svc_probe() devuelve un valor de 0, que indica que la operación ha sido satisfactoria.

El código de svc_probe() es el siguiente.


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;


   /*
    * analizar el servicio de datos mediante una conexión de zócalo al
    * puerto especificado en la propiedad port_list property del sistema
    * que sirve al servicio de datos de XFS. Si el servicio XFS que se ha
    * configurado para recibir en el puerto especificado responde a la
    * conexión, el análisis es satisfactorio. En caso contrario, esperar
    * durante un tiempo definido en la propiedad probe_timeout antes de
    * determinar que el análisis ha fallado.
    */

   /*
    * Utilizar el porcentaje SVC_CONNECT_TIMEOUT_PCT de tiempo de
    * espera para conectarse al puerto
    */
   connect_timeout = (SVC_CONNECT_TIMEOUT_PCT * timeout)/100;
   t1 = (hrtime_t)(gethrtime()/1E9);

   /*
    * el análisis realiza una conexión al nombre de sistema y puerto
    * especificados. La conexión tiene un 95% del valor real de probe_timeout.
    */
   rc = scds_fm_tcp_connect(scds_handle, &sock, hostname, port,
       connect_timeout);
   if (rc) {
      scds_syslog(LOG_ERR,
          "No se ha podido conectar con el puerto <%d> "
          "del recurso <%s>.",
          port, scds_get_resource_name(scds_handle));
      /* es un fallo total */
      return (SCDS_PROBE_COMPLETE_FAILURE);
   }

   t2 = (hrtime_t)(gethrtime()/1E9);

   /*
    * Calcular el tiempo real que tardó en conectarse. Debe ser
    * menor o igual que connect_timeout, el tiempo asignado
    * para la conexión. Si la conexión utiliza todo el tiempo que se
    * le asigna, el valor restante de probe_timeout que se pasa a
    * esta función se utilizará como tiempo de desconexión. En
    * caso contrario, el tiempo restante de la llamada de conexión
    * se agregará también al tiempo de espera de desconexión.
    *
    */

   time_used = (int)(t2 - t1);

   /*
    * Usar el tiempo restante (timeout - time_took_to_connect)
    * para la desconexión
    */

   time_remaining = timeout - (int)time_used;

   /*
    * Si se ha usado todo el tiempo, utilice un tiempo de espera
    * reducido y no modificable para seguir intentando la desconexión.
    * Así se evitará la fuga de fd.
    */
   if (time_remaining <= 0) {
      scds_syslog_debug(DBG_LEVEL_LOW,
          "svc_probe ha usado el tiempo total de espera de "
          "%d segundos durante la operación de conexión y ha"
          "sobrepasado el tiempo de espera en %d segundos."
          "Intentado desconectar con el tiempo de espera"
          " %d ",
          connect_timeout,
          abs(time_used),
          SVC_DISCONNECT_TIMEOUT_SECONDS);

      time_remaining = SVC_DISCONNECT_TIMEOUT_SECONDS;
   }

   /*
    * Devolver fallo parcial en caso de fallo de desconexión.
    * Motivo: la llamada de conexión es satisfactoria, lo que
    * significa que la aplicación está activa. Un fallo de
    * desconexión se puede producir debido a una aplicación
    * bloqueada o a una carga excesiva.
    * Si fuera este último caso, no declarar la aplicación
    * terminada devolviendo un fallo completo. En su lugar,
    * declararlo fallo parcial. Si la situación persiste, la llamada
    * de desconexión volverá a fallar y se reiniciará la aplicación.
    */
   rc = scds_fm_tcp_disconnect(scds_handle, sock, time_remaining);
   if (rc != SCHA_ERR_NOERR) {
      scds_syslog(LOG_ERR,
          "No se ha podido desconectar el puerto %d del recurso %s.",
          port, scds_get_resource_name(scds_handle));
      /* es un fallo parcial */
      return (SCDS_PROBE_COMPLETE_FAILURE/2);
   }

   t2 = (hrtime_t)(gethrtime()/1E9);
   time_used = (int)(t2 - t1);
   time_remaining = timeout - time_used;

   /*
    * Si no queda tiempo, no realizar la prueba completa con
    * fsinfo. Devolver SCDS_PROBE_COMPLETE_FAILURE/2
    * en su lugar. Así se asegurará que si el tiempo de espera
    * agotado persiste, se reiniciará el servidor.
    */
   if (time_remaining <= 0) {
      scds_syslog(LOG_ERR, "Tiempo de espera de análisis agotado.");
      return (SCDS_PROBE_COMPLETE_FAILURE/2);
   }

   /*
    * La conexión y desconexión del puerto han sido satisfactorias.
    * Ejecutar la orden fsinfo para realizar una comprobación
    * completa del estado del servidor.
    * Redirigir stdout o la salida de fsinfo terminará en la consola.
    */
   (void) sprintf(testcmd,
       "/usr/openwin/bin/fsinfo -server %s:%d > /dev/null",
       hostname, port);
   scds_syslog_debug(DBG_LEVEL_HIGH,
       "Comprobar el estado del servidor con %s.", testcmd);
   if (scds_timerun(scds_handle, testcmd, time_remaining,
      SIGKILL, &rc) != SCHA_ERR_NOERR || rc != 0) {

      scds_syslog(LOG_ERR,
         "No se ha podido comprobar el estado del servidor "
         "con la orden <%s>",
         testcmd);
      return (SCDS_PROBE_COMPLETE_FAILURE/2);
   }
   return (0);
}

Al terminar, svc_probe() devuelve un valor de éxito (0), fallo parcial (50) o fallo total (100). El método xfnts_probe pasa este valor a scds_fm_action().

Selección de la acción del supervisor de fallos

El método xfnts_probe invoca scds_fm_action() para determinar qué acción debe tomar. La lógica de scds_fm_action() es la siguiente:

Por ejemplo, supongamos que el análisis establece una conexión con el servidor xfs, 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. El fallo de desconexión 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 análisis siguiente, el servidor vuelve a fallar en la desconexión, se añadirá un valor de 50 al historial de fallos que mantiene scds_fm_action(). El valor acumulado de fallos es de 100, por lo que scds_fm_action() reiniciará el servicio de datos.

Método xfnts_validate

RGM invoca el método Validate cuando se crea un recurso y cuando una acción administrativa 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 invoca Validate sólo cuando se cambian las propiedades del recurso o del grupo mediante una acción administrativa, no cuando RGM establece las propiedades ni cuando un supervisor establece las propiedades de recurso Status y Status_msg.


Nota –

El método Monitor_check invoca también explícitamente el método Validate cuando el método PROBE intenta realizar una operación de recuperación de fallos del servicio de datos a otro nodo.


RGM invoca Validate con argumentos adicionales a los que se pasan a otros métodos, incluidos las propiedades y los valores que se están actualizando. La llamada a scds_initialize() al principio de xfnts_validate analiza todos los argumentos que RGM pasa a xfnts_validate y guarda la información en el parámetro scds_handle. Las subrutinas que invoca xfnts_validate utilizan esta información.

El método xfnts_validate invoca svc_validate(), que verifica lo siguiente.

Antes de retornar, svc_validate() libera todos los recursos asignados.


finished:
   scds_free_net_list(snrlp);
   scds_free_port_list(portlist);

   return (rc); /* devolver el resultado de la validación */


Nota –

Antes de salir, el método xfnts_validate invoca scds_close() para reclamar los recursos asignados por scds_initialize(). Consulte Función scds_initialize() y la página de comando man scds_close(3HA) para obtener más detalles.


Método xfnts_update

RGM invoca el 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 tanto, siempre que se actualiza una propiedad, el método xfnts_update invoca scds_pmf_restart_fm() para reiniciar el supervisor de fallos.


* comprobar si el supervisor de fallos está ya en ejecución y, en caso
   * afirmativo, detenerlo y reiniciarlo. El segundo parámetro de
   * scds_pmf_restart_fm() sólo identifica la instancia del supervisor
   * de fallos que hay que reiniciar.
   */

   scds_syslog(LOG_INFO, "Reiniciar el supervisor de fallos.");
   result = scds_pmf_restart_fm(scds_handle, 0);
   if (result != SCHA_ERR_NOERR) {
      scds_syslog(LOG_ERR,
          "No se ha podido reiniciar el supervisor de fallos.");
      /* Liberar toda la memoria asignada por scds_initialize */
      scds_close(&scds_handle);
      return (1);
   }

   scds_syslog(LOG_INFO,
   "Se ha terminado satisfactoriamente.");


Nota –

El segundo parámetro de scds_pmf_restart_fm() sólo identifica la instancia del supervisor de fallos que se va a reiniciar, en caso de que haya varias instancias. El valor 0 del ejemplo indica que sólo hay una instancia del supervisor de fallos.