[Linux-ha-dev] [PATCH] Proposal SNMP subagent extention (revised)

Dejan Muhamedagic dejanmm at fastmail.fm
Tue Dec 4 16:00:00 MST 2007


Hi,

On Tue, Dec 04, 2007 at 07:53:06PM +0900, Keisuke MORI wrote:
> Hi,
> 
> I'm posting the updated version of the SNMP hbagent extension for V2.
> 
> This patch is reflecting the comments from Andrew and Dejan.
> Thank you very much about that!
> 
> The differences from the previous patch are:
> 
> 1) Add three new fields in the MIB object as below:
>    LHAResourceIsManaged: the managed status of a resource.
>    LHAResourceFailcount: the fail-count value of a resource.
>    LHAResourceParent:    the name of the parent resource if present.
> 
> 2) Add a simple check in SNMPAgentSanityCheck.in
>    for the functionality provided by this patch.
> 
> 3) Revise the code implementation details as advised by Dejan.
> 
> 4) Based on the more recent -dev: f153a9be0bdf 
> 
> 
> I would appreciate if there're any further comments and suggestions,
> particularly about the MIB definition.

Thanks again for the patch. I'll take a look and get back to you.

Cheers,

Dejan

> It is just good enough for our usage, but I would like to know
> if someone still needs more information in the SNMP MIB object
> to be implemented.
> 
> See README in the attachment for details how the current MIB looks like.
> 
> 
> Regards,
> 
> Keisuke MORI
> NTT DATA Intellilink Corporation

Content-Description: README_hbagentv2.txt
>                SNMP Subagent Extention for CRM Resources
> 
> 1. Introduction
> 
>     The purpose of this patch is to extend the SNMP subagent to get and
>     receive a trap about the CRM resource information provided by
>     Heartbeat Version 2.
> 
>     This patch introduces two new SNMP MIB objects.
> 
>     1) LHAResourceTable: resources' name, type, on which node they are
>        running, and their status. On the other words, you can get the
>        information which is provided with crm_mon through the SNMP interface.
> 
>     2) LHAResourceStatusUpdate: when a resource's status changes, you are
>        notified with this SNMP trap.
> 
> 2. Added MIB
> 
>     The following is the added MIB at this patch.
> 
> ---------------------------------------------------------------------------
> | OID         | Object Name             | Value type    | Description     |
> ---------------------------------------------------------------------------
> |4682.8 |     | LHAResourceTable        | table         |                 |
> ---------------------------------------------------------------------------
> |       |.1   |  LHAResourceEntry       |               |                 |
> ---------------------------------------------------------------------------
> |       |.1.1 |   LHAResourceIndex      | Integer32     |                 |
> ---------------------------------------------------------------------------
> |       |.1.2 |   LHAResourceName       | DisplayString |                 |
> ---------------------------------------------------------------------------
> |       |.1.3 |   LHAResourceType       | INTEGER       | unknown(0)      | 
> |       |     |                         |               | primitive(1)    |
> |       |     |                         |               | group(2)        |
> |       |     |                         |               | clone(3)        |
> |       |     |                         |               | masterSlave(4)  |
> ---------------------------------------------------------------------------
> |       |.1.4 |   LHAResourceNode       | DisplayString |                 |
> ---------------------------------------------------------------------------
> |       |.1.5 |   LHAResourceStatus     | INTEGER       | unknown(0)      |
> |       |     |                         |               | stopped(1)      |
> |       |     |                         |               | started(2)      |
> |       |     |                         |               | slave(3)        |
> |       |     |                         |               | master(4)       |
> ---------------------------------------------------------------------------
> |       |.1.6 |   LHAResourceIsManaged  | INTEGER       | unmanaged(0)    |
> |       |     |                         |               | managed(1)      |
> ---------------------------------------------------------------------------
> |       |.1.7 |   LHAResourceFailcount  | Integer32     |                 |
> ---------------------------------------------------------------------------
> |       |.1.8 |   LHAResourceParent     | DisplayString |                 |
> ---------------------------------------------------------------------------
> 
> 
>     NOTE :   "master" status means "promoted", and "slave" means "demoted".
>            All master/slave resources start up as slave at first, and until
>            they are demoted or promoted explicitly, heartbeat only knows
>            they "started".
>            So, LHAResourceStatus's value is according to the crm_mon output.
>     NOTE :   For the present, you can get the information only about *running*
>            resources or the resources that their values of fail-count are 
>            larger than 1. Because it's difficult to decide which node 
>            a resource *stopped* on...
> 
> 3. Added Trap
> 
>     The following is the added Trap at this patch.
> 
> ---------------------------------------------------------------------------
> | OID         | Object Name             | Value type    | Description     |
> ---------------------------------------------------------------------------
> |4682.900.8   | LHAResourceStatusUpdate |               |                 |
> |             |------------------------------------------------------------
> |             |  LHAResourceName        | DisplayString |                 |
> |             |------------------------------------------------------------
> |             |  LHAResourceNode        | DisplayString |                 |
> |             |------------------------------------------------------------
> |             |  LHAResourceStatus      | INTEGER       | 0 : unknown     |
> |             |                         |               | 1 : stopped     |
> |             |                         |               | 2 : started     |
> |             |                         |               | 3 : slave       |
> |             |                         |               | 4 : master      |
> ---------------------------------------------------------------------------
> 
>     NOTE :   This trap is sent only when the resource operation succeeds.
>            Concretely, the extended hbagent gets the cib information when it
>            changes, and parse it. And if the rc_code of the operation (like
>            CRMD_ACTION_START) is "0", then the hbagent sends a trap.
> 
> 4. Demo Output
> 
>     [root at u5node1 ~]# snmpwalk -v 1 \
>                         -c public localhost LINUX-HA-MIB::LHAResourceTable
>     LINUX-HA-MIB::LHAResourceName.1 = STRING: group0
>     LINUX-HA-MIB::LHAResourceName.2 = STRING: prmIp
>     LINUX-HA-MIB::LHAResourceName.3 = STRING: prmApPostgreSQLDB
>     LINUX-HA-MIB::LHAResourceName.4 = STRING: clone0
>     LINUX-HA-MIB::LHAResourceName.5 = STRING: clone0
>     LINUX-HA-MIB::LHAResourceName.6 = STRING: clone0-dummy:0
>     LINUX-HA-MIB::LHAResourceName.7 = STRING: clone0-dummy:1
>     LINUX-HA-MIB::LHAResourceName.8 = STRING: ms-sf
>     LINUX-HA-MIB::LHAResourceName.9 = STRING: ms-sf
>     LINUX-HA-MIB::LHAResourceName.10 = STRING: master_slave_Stateful:0
>     LINUX-HA-MIB::LHAResourceName.11 = STRING: master_slave_Stateful:1
>     LINUX-HA-MIB::LHAResourceType.1 = INTEGER: group(2)
>     LINUX-HA-MIB::LHAResourceType.2 = INTEGER: primitive(1)
>     LINUX-HA-MIB::LHAResourceType.3 = INTEGER: primitive(1)
>     LINUX-HA-MIB::LHAResourceType.4 = INTEGER: clone(3)
>     LINUX-HA-MIB::LHAResourceType.5 = INTEGER: clone(3)
>     LINUX-HA-MIB::LHAResourceType.6 = INTEGER: primitive(1)
>     LINUX-HA-MIB::LHAResourceType.7 = INTEGER: primitive(1)
>     LINUX-HA-MIB::LHAResourceType.8 = INTEGER: masterSlave(4)
>     LINUX-HA-MIB::LHAResourceType.9 = INTEGER: masterSlave(4)
>     LINUX-HA-MIB::LHAResourceType.10 = INTEGER: primitive(1)
>     LINUX-HA-MIB::LHAResourceType.11 = INTEGER: primitive(1)
>     LINUX-HA-MIB::LHAResourceNode.1 = STRING: u5node1
>     LINUX-HA-MIB::LHAResourceNode.2 = STRING: u5node1
>     LINUX-HA-MIB::LHAResourceNode.3 = STRING: u5node1
>     LINUX-HA-MIB::LHAResourceNode.4 = STRING: u5node1
>     LINUX-HA-MIB::LHAResourceNode.5 = STRING: u5node2
>     LINUX-HA-MIB::LHAResourceNode.6 = STRING: u5node2
>     LINUX-HA-MIB::LHAResourceNode.7 = STRING: u5node1
>     LINUX-HA-MIB::LHAResourceNode.8 = STRING: u5node1
>     LINUX-HA-MIB::LHAResourceNode.9 = STRING: u5node2
>     LINUX-HA-MIB::LHAResourceNode.10 = STRING: u5node2
>     LINUX-HA-MIB::LHAResourceNode.11 = STRING: u5node1
>     LINUX-HA-MIB::LHAResourceStatus.1 = INTEGER: started(2)
>     LINUX-HA-MIB::LHAResourceStatus.2 = INTEGER: started(2)
>     LINUX-HA-MIB::LHAResourceStatus.3 = INTEGER: started(2)
>     LINUX-HA-MIB::LHAResourceStatus.4 = INTEGER: started(2)
>     LINUX-HA-MIB::LHAResourceStatus.5 = INTEGER: started(2)
>     LINUX-HA-MIB::LHAResourceStatus.6 = INTEGER: started(2)
>     LINUX-HA-MIB::LHAResourceStatus.7 = INTEGER: started(2)
>     LINUX-HA-MIB::LHAResourceStatus.8 = INTEGER: master(4)
>     LINUX-HA-MIB::LHAResourceStatus.9 = INTEGER: master(4)
>     LINUX-HA-MIB::LHAResourceStatus.10 = INTEGER: started(2)
>     LINUX-HA-MIB::LHAResourceStatus.11 = INTEGER: master(4)
>     LINUX-HA-MIB::LHAResourceIsManaged.1 = INTEGER: managed(1)
>     LINUX-HA-MIB::LHAResourceIsManaged.2 = INTEGER: managed(1)
>     LINUX-HA-MIB::LHAResourceIsManaged.3 = INTEGER: managed(1)
>     LINUX-HA-MIB::LHAResourceIsManaged.4 = INTEGER: managed(1)
>     LINUX-HA-MIB::LHAResourceIsManaged.5 = INTEGER: managed(1)
>     LINUX-HA-MIB::LHAResourceIsManaged.6 = INTEGER: managed(1)
>     LINUX-HA-MIB::LHAResourceIsManaged.7 = INTEGER: managed(1)
>     LINUX-HA-MIB::LHAResourceIsManaged.8 = INTEGER: managed(1)
>     LINUX-HA-MIB::LHAResourceIsManaged.9 = INTEGER: managed(1)
>     LINUX-HA-MIB::LHAResourceIsManaged.10 = INTEGER: managed(1)
>     LINUX-HA-MIB::LHAResourceIsManaged.11 = INTEGER: managed(1)
>     LINUX-HA-MIB::LHAResourceFailCount.1 = INTEGER: 0
>     LINUX-HA-MIB::LHAResourceFailCount.2 = INTEGER: 0
>     LINUX-HA-MIB::LHAResourceFailCount.3 = INTEGER: 0
>     LINUX-HA-MIB::LHAResourceFailCount.4 = INTEGER: 0
>     LINUX-HA-MIB::LHAResourceFailCount.5 = INTEGER: 0
>     LINUX-HA-MIB::LHAResourceFailCount.6 = INTEGER: 0
>     LINUX-HA-MIB::LHAResourceFailCount.7 = INTEGER: 0
>     LINUX-HA-MIB::LHAResourceFailCount.8 = INTEGER: 0
>     LINUX-HA-MIB::LHAResourceFailCount.9 = INTEGER: 0
>     LINUX-HA-MIB::LHAResourceFailCount.10 = INTEGER: 0
>     LINUX-HA-MIB::LHAResourceFailCount.11 = INTEGER: 0
>     LINUX-HA-MIB::LHAResourceParent.1 = STRING:
>     LINUX-HA-MIB::LHAResourceParent.2 = STRING: group0
>     LINUX-HA-MIB::LHAResourceParent.3 = STRING: group0
>     LINUX-HA-MIB::LHAResourceParent.4 = STRING:
>     LINUX-HA-MIB::LHAResourceParent.5 = STRING:
>     LINUX-HA-MIB::LHAResourceParent.6 = STRING: clone0
>     LINUX-HA-MIB::LHAResourceParent.7 = STRING: clone0
>     LINUX-HA-MIB::LHAResourceParent.8 = STRING:
>     LINUX-HA-MIB::LHAResourceParent.9 = STRING:
>     LINUX-HA-MIB::LHAResourceParent.10 = STRING: ms-sf
>     LINUX-HA-MIB::LHAResourceParent.11 = STRING: ms-sf
> 
>     cf.) Then crm_mon's output is...
>     
> ============
> Last updated: Mon Dec  3 17:39:27 2007
> Current DC: u5node2 (7e035df7-607d-42b4-a1e7-e8d9db108e6c)
> 2 Nodes configured.
> 3 Resources configured.
> ============
> 
> Node: u5node1 (77b7c7b1-68ba-4542-9f10-b75de73e9ffd): online
> Node: u5node2 (7e035df7-607d-42b4-a1e7-e8d9db108e6c): online
> 
> Resource Group: group0
>     prmIp       (heartbeat::ocf:IPaddr):        Started u5node1
>     prmApPostgreSQLDB   (heartbeat::ocf:pgsql): Started u5node1
> Clone Set: clone0
>     clone0-dummy:0      (heartbeat::ocf:Dummy): Started u5node2
>     clone0-dummy:1      (heartbeat::ocf:Dummy): Started u5node1
> Master/Slave Set: ms-sf
>     master_slave_Stateful:0     (heartbeat::ocf:Stateful):      Started u5node2
>     master_slave_Stateful:1     (heartbeat::ocf:Stateful):      Master u5node1
> 
> 
>     Sample SNMP traps
> 
>     Dec  3 17:38:31 manager_node snmptrapd[1343]: 2007-12-03 17:38:31 u5node2 [
>     192.168.70.129]: DISMAN-EVENT-MIB::sysUpTimeInstance = Timeticks: (22408) 0
>     :03:44.08   SNMPv2-MIB::snmpTrapOID.0 = OID: LINUX-HA-MIB::LHAResourceStatu
>     sUpdate  LINUX-HA-MIB::LHAResourceName = STRING: master_slave_Stateful:0 LI
>     NUX-HA-MIB::LHAResourceNode = STRING: u5node2 LINUX-HA-MIB::LHAResourceStat
>     us = INTEGER: started(2)
>     Dec  3 17:38:31 manager_node snmptrapd[1343]: 2007-12-03 17:38:31 u5node2 [
>     192.168.70.129]: DISMAN-EVENT-MIB::sysUpTimeInstance = Timeticks: (22420) 0
>     :03:44.20   SNMPv2-MIB::snmpTrapOID.0 = OID: LINUX-HA-MIB::LHAResourceStatu
>     sUpdate  LINUX-HA-MIB::LHAResourceName = STRING: clone0-dummy:0  LINUX-HA-M
>     IB::LHAResourceNode = STRING: u5node2 LINUX-HA-MIB::LHAResourceStatus = INT
>     EGER: started(2)
>     Dec  3 17:38:32 manager_node snmptrapd[1343]: 2007-12-03 17:38:32 u5node1 [
>     192.168.70.128]: DISMAN-EVENT-MIB::sysUpTimeInstance = Timeticks: (19126) 0
>     :03:11.26   SNMPv2-MIB::snmpTrapOID.0 = OID: LINUX-HA-MIB::LHAResourceStatu
>     sUpdate  LINUX-HA-MIB::LHAResourceName = STRING: clone0-dummy:1  LINUX-HA-M
>     IB::LHAResourceNode = STRING: u5node1 LINUX-HA-MIB::LHAResourceStatus = INT
>     EGER: started(2)
>     Dec  3 17:38:32 manager_node snmptrapd[1343]: 2007-12-03 17:38:32 u5node1 [
>     192.168.70.128]: DISMAN-EVENT-MIB::sysUpTimeInstance = Timeticks: (19129) 0
>     :03:11.29   SNMPv2-MIB::snmpTrapOID.0 = OID: LINUX-HA-MIB::LHAResourceStatu
>     sUpdate  LINUX-HA-MIB::LHAResourceName = STRING: master_slave_Stateful:1 LI
>     NUX-HA-MIB::LHAResourceNode = STRING: u5node1 LINUX-HA-MIB::LHAResourceStat
>     us = INTEGER: started(2)
>     Dec  3 17:38:34 manager_node snmptrapd[1343]: 2007-12-03 17:38:34 u5node1 [
>     192.168.70.128]: DISMAN-EVENT-MIB::sysUpTimeInstance = Timeticks: (19314) 0
>     :03:13.14   SNMPv2-MIB::snmpTrapOID.0 = OID: LINUX-HA-MIB::LHAResourceStatu
>     sUpdate  LINUX-HA-MIB::LHAResourceName = STRING: master_slave_Stateful:1 LI
>     NUX-HA-MIB::LHAResourceNode = STRING: u5node1 LINUX-HA-MIB::LHAResourceStat
>     us = INTEGER: master(4)
>     Dec  3 17:38:36 manager_node snmptrapd[1343]: 2007-12-03 17:38:36 u5node1 [
>     192.168.70.128]: DISMAN-EVENT-MIB::sysUpTimeInstance = Timeticks: (19516) 0
>     :03:15.16   SNMPv2-MIB::snmpTrapOID.0 = OID: LINUX-HA-MIB::LHAResourceStatu
>     sUpdate  LINUX-HA-MIB::LHAResourceName = STRING: prmIp   LINUX-HA-MIB::LHAR
>     esourceNode = STRING: u5node1 LINUX-HA-MIB::LHAResourceStatus = INTEGER: st
>     arted(2)
>     Dec  3 17:38:42 manager_node snmptrapd[1343]: 2007-12-03 17:38:42 u5node1 [
>     192.168.70.128]: DISMAN-EVENT-MIB::sysUpTimeInstance = Timeticks: (20067) 0
>     :03:20.67   SNMPv2-MIB::snmpTrapOID.0 = OID: LINUX-HA-MIB::LHAResourceStatu
>     sUpdate  LINUX-HA-MIB::LHAResourceName = STRING: prmApPostgreSQLDB       LI
>     NUX-HA-MIB::LHAResourceNode = STRING: u5node1 LINUX-HA-MIB::LHAResourceStat
>     us = INTEGER: started(2)
> 
> 5. Other changes
> 
>     This patch modifies the following too.
>         1) Make SNMP_CACHE_TIME_OUT variable.
>              apply the value which is specified with -r option.
>         2) Fix some memory leaks.
>              debug with valgrind.
>         3) Update SNMPAgentSanityCheck to keep up with the new functionality.

Content-Description: hbagent_v2resource.patch
> diff -urN org/snmp_subagent/LHAIFStatusTable.c mod/snmp_subagent/LHAIFStatusTable.c
> --- org/snmp_subagent/LHAIFStatusTable.c	2007-11-02 17:35:27.000000000 +0900
> +++ mod/snmp_subagent/LHAIFStatusTable.c	2007-11-21 10:19:55.000000000 +0900
> @@ -50,6 +50,7 @@
>  #include "hbagent.h"
>  
>  static GPtrArray * gIFInfo = NULL;
> +extern const int snmp_cache_time_out;
>  
>  int LHAIFStatusTable_load(netsnmp_cache *cache, void *vmagic); 
>  void LHAIFStatusTable_free(netsnmp_cache *cache, void *vmagic); 
> @@ -123,7 +124,7 @@
>       * .... with a local cache
>       */
>      netsnmp_inject_handler(my_handler,
> -	 netsnmp_get_cache_handler(CACHE_TIME_OUT, 
> +	 netsnmp_get_cache_handler(snmp_cache_time_out, 
>  				   LHAIFStatusTable_load,
>  				   LHAIFStatusTable_free,
>  				   LHAIFStatusTable_oid,
> diff -urN org/snmp_subagent/LHAMembershipTable.c mod/snmp_subagent/LHAMembershipTable.c
> --- org/snmp_subagent/LHAMembershipTable.c	2007-11-02 17:35:27.000000000 +0900
> +++ mod/snmp_subagent/LHAMembershipTable.c	2007-11-21 10:20:00.000000000 +0900
> @@ -50,6 +50,7 @@
>  #include "hbagent.h"
>  
>  static GPtrArray * gMembershipInfo = NULL;
> +extern const int snmp_cache_time_out;
>  
>  int LHAMembershipTable_load(netsnmp_cache *cache, void *vmagic);
>  void LHAMembershipTable_free(netsnmp_cache *cache, void *vmagic);
> @@ -112,7 +113,7 @@
>       * .... with a local cache
>       */
>      netsnmp_inject_handler(my_handler,
> -	 netsnmp_get_cache_handler(CACHE_TIME_OUT, 
> +	 netsnmp_get_cache_handler(snmp_cache_time_out, 
>  				   LHAMembershipTable_load,
>  				   LHAMembershipTable_free,
>  				   LHAMembershipTable_oid,
> diff -urN org/snmp_subagent/LHANodeTable.c mod/snmp_subagent/LHANodeTable.c
> --- org/snmp_subagent/LHANodeTable.c	2007-11-02 17:35:27.000000000 +0900
> +++ mod/snmp_subagent/LHANodeTable.c	2007-11-21 10:20:05.000000000 +0900
> @@ -50,6 +50,7 @@
>  #include "hbagent.h"
>  
>  static GPtrArray * gNodeInfo = NULL;
> +extern const int snmp_cache_time_out;
>  
>  int LHANodeTable_load(netsnmp_cache *cache, void *vmagic);
>  void LHANodeTable_free(netsnmp_cache *cache, void *vmagic);
> @@ -113,7 +114,7 @@
>       * .... with a local cache
>       */
>      netsnmp_inject_handler(my_handler,
> -	 netsnmp_get_cache_handler(CACHE_TIME_OUT, 
> +	 netsnmp_get_cache_handler(snmp_cache_time_out, 
>  				   LHANodeTable_load,
>  				   LHANodeTable_free,
>  				   LHANodeTable_oid,
> diff -urN org/snmp_subagent/LHAResourceGroupTable.c mod/snmp_subagent/LHAResourceGroupTable.c
> --- org/snmp_subagent/LHAResourceGroupTable.c	2007-11-02 17:35:27.000000000 +0900
> +++ mod/snmp_subagent/LHAResourceGroupTable.c	2007-11-21 10:20:17.000000000 +0900
> @@ -50,6 +50,7 @@
>  #include "hbagent.h"
>  
>  static GPtrArray * gResourceGroupInfo = NULL;
> +extern const int snmp_cache_time_out;
>  
>  int LHAResourceGroupTable_load(netsnmp_cache *cache, void *vmagic); 
>  void LHAResourceGroupTable_free(netsnmp_cache *cache, void *vmagic); 
> @@ -122,7 +123,7 @@
>       * .... with a local cache
>       */
>      netsnmp_inject_handler(my_handler,
> -	 netsnmp_get_cache_handler(CACHE_TIME_OUT, 
> +	 netsnmp_get_cache_handler(snmp_cache_time_out, 
>  				   LHAResourceGroupTable_load,
>  				   LHAResourceGroupTable_free,
>  				   LHAResourceGroupTable_oid,
> diff -urN org/snmp_subagent/LHAResourceStatusUpdate.c mod/snmp_subagent/LHAResourceStatusUpdate.c
> --- org/snmp_subagent/LHAResourceStatusUpdate.c	1970-01-01 09:00:00.000000000 +0900
> +++ mod/snmp_subagent/LHAResourceStatusUpdate.c	2007-11-20 10:07:36.000000000 +0900
> @@ -0,0 +1,85 @@
> +/*
> + * Note: this file originally auto-generated by mib2c using
> + *        : mib2c.notify.conf,v 5.2.2.1 2004/04/15 12:29:06 dts12 Exp $
> + */
> +#include <lha_internal.h>
> +
> +#include "hbagent.h"
> +#include "hbagentv2.h"
> +
> +#include <net-snmp/net-snmp-config.h>
> +#include <net-snmp/net-snmp-includes.h>
> +#include <net-snmp/agent/net-snmp-agent-includes.h>
> +#include "LHAResourceStatusUpdate.h"
> +
> +
> +
> +static oid      snmptrap_oid[] = { 1, 3, 6, 1, 6, 3, 1, 1, 4, 1, 0 };
> +
> +int
> +send_LHAResourceStatusUpdate_trap(struct hb_rsinfov2 *resource)
> +{
> +    netsnmp_variable_list *var_list = NULL;
> +    oid             LHAResourceStatusUpdate_oid[] =
> +        { 1, 3, 6, 1, 4, 1, 4682, 900, 11 };
> +    oid             LHAResourceName_oid[] =
> +        { 1, 3, 6, 1, 4, 1, 4682, 8, 1, 2, /* insert index here */  };
> +    oid             LHAResourceNode_oid[] =
> +        { 1, 3, 6, 1, 4, 1, 4682, 8, 1, 4, /* insert index here */  };
> +    oid             LHAResourceStatus_oid[] =
> +        { 1, 3, 6, 1, 4, 1, 4682, 8, 1, 5, /* insert index here */  };
> +
> +
> +    /*
> +     * Set the snmpTrapOid.0 value
> +     */
> +    snmp_varlist_add_variable(&var_list,
> +                              snmptrap_oid, OID_LENGTH(snmptrap_oid),
> +                              ASN_OBJECT_ID,
> +                              (u_char *)LHAResourceStatusUpdate_oid,
> +                               sizeof(LHAResourceStatusUpdate_oid));
> +
> +    /*
> +     * Add any objects from the trap definition
> +     */
> +    snmp_varlist_add_variable(&var_list,
> +                              LHAResourceName_oid,
> +                              OID_LENGTH(LHAResourceName_oid),
> +                              ASN_OCTET_STR,
> +                              /*
> +                               * Set an appropriate value for LHAResourceName 
> +                               */
> +                                (u_char *)resource->resourceid,
> +                                strlen(resource->resourceid));
> +    snmp_varlist_add_variable(&var_list,
> +                              LHAResourceNode_oid,
> +                              OID_LENGTH(LHAResourceNode_oid),
> +                              ASN_OCTET_STR,
> +                              /*
> +                               * Set an appropriate value for LHAResourceNode 
> +                               */
> +                                (u_char *)resource->node,
> +                                strlen(resource->node));
> +    snmp_varlist_add_variable(&var_list,
> +                              LHAResourceStatus_oid,
> +                              OID_LENGTH(LHAResourceStatus_oid),
> +                              ASN_INTEGER,
> +                              /*
> +                               * Set an appropriate value for LHAResourceStatus 
> +                               */
> +                                (u_char *)&(resource->status),
> +                                sizeof(resource->status));
> +
> +    /*
> +     * Add any extra (optional) objects here
> +     */
> +
> +    /*
> +     * Send the trap to the list of configured destinations
> +     *  and clean up
> +     */
> +    send_v2trap(var_list);
> +    snmp_free_varbind(var_list);
> +
> +    return SNMP_ERR_NOERROR;
> +}
> diff -urN org/snmp_subagent/LHAResourceStatusUpdate.h mod/snmp_subagent/LHAResourceStatusUpdate.h
> --- org/snmp_subagent/LHAResourceStatusUpdate.h	1970-01-01 09:00:00.000000000 +0900
> +++ mod/snmp_subagent/LHAResourceStatusUpdate.h	2007-11-20 10:07:36.000000000 +0900
> @@ -0,0 +1,14 @@
> +/*
> + * Note: this file originally auto-generated by mib2c using
> + *        : mib2c.notify.conf,v 5.2.2.1 2004/04/15 12:29:06 dts12 Exp $
> + */
> +#ifndef LHARESOURCESTATUSUPDATE_H
> +#define LHARESOURCESTATUSUPDATE_H
> +
> +
> +/*
> + * function declarations 
> + */
> +int             send_LHAResourceStatusUpdate_trap(struct hb_rsinfov2 *resource);
> +
> +#endif                          /* LHARESOURCESTATUSUPDATE_H */
> diff -urN org/snmp_subagent/LHAResourceTable.c mod/snmp_subagent/LHAResourceTable.c
> --- org/snmp_subagent/LHAResourceTable.c	1970-01-01 09:00:00.000000000 +0900
> +++ mod/snmp_subagent/LHAResourceTable.c	2007-11-26 18:25:05.000000000 +0900
> @@ -0,0 +1,343 @@
> +/*
> + * Note: this file originally auto-generated by mib2c using
> + *        : mib2c.iterate.conf,v 5.9 2003/06/04 00:14:41 hardaker Exp $
> + */
> +
> +#include <lha_internal.h>
> +
> +
> +#include <net-snmp/net-snmp-config.h>
> +#include <net-snmp/net-snmp-includes.h>
> +#include <net-snmp/agent/net-snmp-agent-includes.h>
> +#include "LHAResourceTable.h"
> +
> +#include "hbagent.h"
> +#include "hbagentv2.h"
> +#include "hb_api.h"
> +/*#include "heartbeat.h"*/
> +/*#include "clplumbing/cl_log.h"*/
> +
> +static GPtrArray * gResourceTableV2 = NULL;
> +extern const int snmp_cache_time_out;
> +
> +static int LHAResourceTable_load(netsnmp_cache *cache, void *vmagic); 
> +static void LHAResourceTable_free(netsnmp_cache *cache, void *vmagic); 
> +
> +/** Initialize the LHAResourceTable table by defining its contents and how it's structured */
> +void
> +initialize_table_LHAResourceTable(void)
> +{
> +    static oid      LHAResourceTable_oid[] = { 1, 3, 6, 1, 4, 1, 4682, 8 };
> +    netsnmp_table_registration_info *table_info;
> +    netsnmp_handler_registration *my_handler;
> +    netsnmp_iterator_info *iinfo;
> +
> +    /** create the table registration information structures */
> +    table_info = SNMP_MALLOC_TYPEDEF(netsnmp_table_registration_info);
> +    iinfo = SNMP_MALLOC_TYPEDEF(netsnmp_iterator_info);
> +
> +    /** if your table is read only, it's easiest to change the
> +        HANDLER_CAN_RWRITE definition below to HANDLER_CAN_RONLY */
> +    my_handler = netsnmp_create_handler_registration("LHAResourceTable",
> +                                                     LHAResourceTable_handler,
> +                                                     LHAResourceTable_oid,
> +                                                     OID_LENGTH
> +                                                     (LHAResourceTable_oid),
> +                                                     HANDLER_CAN_RONLY);
> +
> +    if (!my_handler || !table_info || !iinfo) {
> +        snmp_log(LOG_ERR,
> +                 "malloc failed in initialize_table_LHAResourceTable");
> +        SNMP_FREE(iinfo);
> +        SNMP_FREE(table_info);
> +        return;                 /* Serious error. */
> +    }
> +
> +    /***************************************************
> +     * Setting up the table's definition
> +     */
> +    netsnmp_table_helper_add_indexes(table_info, ASN_INTEGER,   /* index: LHAResourceIndex */
> +                                     0);
> +
> +    /** Define the minimum and maximum accessible columns.  This
> +        optimizes retrival. */
> +    table_info->min_column = 2;
> +    table_info->max_column = 8;
> +
> +    /*
> +     * iterator access routines 
> +     */
> +    iinfo->get_first_data_point = LHAResourceTable_get_first_data_point;
> +    iinfo->get_next_data_point = LHAResourceTable_get_next_data_point;
> +
> +    /** you may wish to set these as well */
> +#ifdef MAYBE_USE_THESE
> +    iinfo->make_data_context = LHAResourceTable_context_convert_function;
> +    iinfo->free_data_context = LHAResourceTable_data_free;
> +
> +    /** pick *only* one of these if you use them */
> +    iinfo->free_loop_context = LHAResourceTable_loop_free;
> +    iinfo->free_loop_context_at_end = LHAResourceTable_loop_free;
> +#endif
> +
> +    /** tie the two structures together */
> +    iinfo->table_reginfo = table_info;
> +
> +    /***************************************************
> +     * registering the table with the master agent
> +     */
> +    DEBUGMSGTL(("initialize_table_LHAResourceTable",
> +                "Registering table LHAResourceTable as a table iterator\n"));
> +    netsnmp_register_table_iterator(my_handler, iinfo);
> +
> +    /*
> +     * enable local cache
> +     */
> +    netsnmp_inject_handler(my_handler,
> +               netsnmp_get_cache_handler(snmp_cache_time_out,
> +                             LHAResourceTable_load,
> +                             LHAResourceTable_free,
> +                             LHAResourceTable_oid,
> +                             OID_LENGTH
> +                             (LHAResourceTable_oid)));
> +                                 
> +
> +    snmp_log(LOG_INFO,
> +             "LHAResourceTable initialization completed.\n");
> +}
> +
> +/** Initializes the LHAResourceTable module */
> +void
> +init_LHAResourceTable(void)
> +{
> +
> +  /** here we initialize all the tables we're planning on supporting */
> +    initialize_table_LHAResourceTable();
> +}
> +
> +/** returns the first data point within the LHAResourceTable table data.
> +
> +    Set the my_loop_context variable to the first data point structure
> +    of your choice (from which you can find the next one).  This could
> +    be anything from the first node in a linked list, to an integer
> +    pointer containing the beginning of an array variable.
> +
> +    Set the my_data_context variable to something to be returned to
> +    you later (in your main LHAResourceTable_handler routine) that will provide
> +    you with the data to return in a given row.  This could be the
> +    same pointer as what my_loop_context is set to, or something
> +    different.
> +
> +    The put_index_data variable contains a list of snmp variable
> +    bindings, one for each index in your table.  Set the values of
> +    each appropriately according to the data matching the first row
> +    and return the put_index_data variable at the end of the function.
> +*/
> +netsnmp_variable_list *
> +LHAResourceTable_get_first_data_point(void **my_loop_context,
> +                                      void **my_data_context,
> +                                      netsnmp_variable_list *
> +                                      put_index_data,
> +                                      netsnmp_iterator_info *mydata)
> +{
> +    if (gResourceTableV2 && gResourceTableV2->len == 0) {
> +        return NULL;
> +    }
> +
> +    *my_loop_context = NULL;
> +    return LHAResourceTable_get_next_data_point(my_loop_context,
> +                                                my_data_context,
> +                                                put_index_data,
> +                                                mydata);
> +}
> +
> +/** functionally the same as LHAResourceTable_get_first_data_point, but
> +   my_loop_context has already been set to a previous value and should
> +   be updated to the next in the list.  For example, if it was a
> +   linked list, you might want to cast it to your local data type and
> +   then return my_loop_context->next.  The my_data_context pointer
> +   should be set to something you need later (in your main
> +   LHAResourceTable_handler routine) and the indexes in put_index_data updated
> +   again. */
> +netsnmp_variable_list *
> +LHAResourceTable_get_next_data_point(void **my_loop_context,
> +                                     void **my_data_context,
> +                                     netsnmp_variable_list *
> +                                     put_index_data,
> +                                     netsnmp_iterator_info *mydata)
> +{
> +    static size_t i = 0;
> +    netsnmp_variable_list *vptr;
> +    struct hb_rsinfov2 *info;
> +
> +    if (*my_loop_context != NULL) {
> +        i = *((size_t *) *my_loop_context);
> +    } else {
> +        i = 0;
> +    }
> +
> +    if (!gResourceTableV2 || i >= gResourceTableV2->len) {
> +        return NULL;
> +    }
> +
> +    vptr = put_index_data;
> +    info = (struct hb_rsinfov2 *)g_ptr_array_index(gResourceTableV2, i);
> +
> +    snmp_set_var_value(vptr, (u_char *)&info->index, sizeof(size_t));
> +    vptr = vptr->next_variable;
> +
> +    i++;
> +    *my_loop_context = (void *)&i;
> +    *my_data_context = (void *)info;
> +    
> +    return put_index_data;
> +}
> +
> +/** handles requests for the LHAResourceTable table, if anything else needs to be done */
> +int
> +LHAResourceTable_handler(netsnmp_mib_handler *handler,
> +                         netsnmp_handler_registration *reginfo,
> +                         netsnmp_agent_request_info *reqinfo,
> +                         netsnmp_request_info *requests)
> +{
> +
> +    netsnmp_request_info *request;
> +    netsnmp_table_request_info *table_info;
> +    netsnmp_variable_list *var;
> +
> +    struct hb_rsinfov2 *entry;
> +
> +    for (request = requests; request; request = request->next) {
> +        var = request->requestvb;
> +        if (request->processed != 0)
> +            continue;
> +
> +        /** perform anything here that you need to do before each
> +           request is processed. */
> +
> +        /** the following extracts the my_data_context pointer set in
> +           the loop functions above.  You can then use the results to
> +           help return data for the columns of the LHAResourceTable table in question */
> +        entry = 
> +            (struct hb_rsinfov2 *)netsnmp_extract_iterator_context(request);
> +        if (entry == NULL) {
> +            if (reqinfo->mode == MODE_GET) {
> +                netsnmp_set_request_error(reqinfo, request,
> +                                          SNMP_NOSUCHINSTANCE);
> +                continue;
> +            }
> +            /** XXX: no row existed, if you support creation and this is a
> +               set, start dealing with it here, else continue */
> +        }
> +
> +        /** extracts the information about the table from the request */
> +        table_info = netsnmp_extract_table_info(request);
> +        /** table_info->colnum contains the column number requested */
> +        /** table_info->indexes contains a linked list of snmp variable
> +           bindings for the indexes of the table.  Values in the list
> +           have been set corresponding to the indexes of the
> +           request */
> +        if (table_info == NULL) {
> +            continue;
> +        }
> +
> +        switch (reqinfo->mode) {
> +            /** the table_iterator helper should change all GETNEXTs
> +               into GETs for you automatically, so you don't have to
> +               worry about the GETNEXT case.  Only GETs and SETs need
> +               to be dealt with here */
> +        case MODE_GET:
> +            switch (table_info->colnum) {
> +            case COLUMN_LHARESOURCENAME:
> +                snmp_set_var_typed_value(var, ASN_OCTET_STR,
> +                                         (u_char *)entry->resourceid,
> +                                         strlen(entry->resourceid) + 1
> +                                         );
> +                break;
> +
> +            case COLUMN_LHARESOURCETYPE:
> +                snmp_set_var_typed_value(var, ASN_INTEGER,
> +                                         (u_char *)&entry->type,
> +                                         sizeof(entry->type)
> +                                         );
> +                break;
> +
> +            case COLUMN_LHARESOURCESTATUS:
> +                snmp_set_var_typed_value(var, ASN_INTEGER,
> +                                         (u_char *)&entry->status,
> +                                         sizeof(entry->status)
> +                                         );
> +                break;
> +
> +            case COLUMN_LHARESOURCENODE:
> +                snmp_set_var_typed_value(var, ASN_OCTET_STR,
> +                                         (u_char *)entry->node,
> +                                         strlen(entry->node) + 1
> +                                         );
> +                break;
> +
> +            case COLUMN_LHARESOURCEISMANAGED:
> +                snmp_set_var_typed_value(var, ASN_INTEGER,
> +                                         (u_char *)&entry->is_managed,
> +                                         sizeof(entry->is_managed)
> +                                         );
> +                break;
> +
> +            case COLUMN_LHARESOURCEFAILCOUNT:
> +                snmp_set_var_typed_value(var, ASN_INTEGER,
> +                                         (u_char *)&entry->failcount,
> +                                         sizeof(entry->failcount)
> +                                         );
> +                break;
> +
> +            case COLUMN_LHARESOURCEPARENT:
> +                snmp_set_var_typed_value(var, ASN_OCTET_STR,
> +                                         (u_char *)entry->parent,
> +                                         strlen(entry->parent) + 1
> +                                         );
> +                break;
> +
> +            default:
> +                        /** We shouldn't get here */
> +                snmp_log(LOG_ERR,
> +                         "problem encountered in LHAResourceTable_handler: unknown column\n");
> +            }
> +            break;
> +
> +        case MODE_SET_RESERVE1:
> +                /** set handling... */
> +
> +        default:
> +            snmp_log(LOG_ERR,
> +                     "problem encountered in LHAResourceTable_handler: unsupported mode\n");
> +        }
> +    }
> +    return SNMP_ERR_NOERROR;
> +}
> +
> +static int LHAResourceTable_load(netsnmp_cache *cache, void *vmagic)
> +{
> +    LHAResourceTable_free(cache, vmagic);
> +
> +    gResourceTableV2 = get_resource_table_v2();
> +
> +    return 0;
> +}
> +
> +static void LHAResourceTable_free(netsnmp_cache *cache, void *vmagic)
> +{
> +    /* do nothing. */
> +    return;
> +}
> +
> +
> +
> +/**
> + * Emacs stuff:
> + * Local Variables:
> + * mode: C
> + * c-basic-offset: 4
> + * indent-tabs-mode: nil
> + * End:
> + *
> + */
> diff -urN org/snmp_subagent/LHAResourceTable.h mod/snmp_subagent/LHAResourceTable.h
> --- org/snmp_subagent/LHAResourceTable.h	1970-01-01 09:00:00.000000000 +0900
> +++ mod/snmp_subagent/LHAResourceTable.h	2007-11-20 10:07:36.000000000 +0900
> @@ -0,0 +1,28 @@
> +/*
> + * Note: this file originally auto-generated by mib2c using
> + *        : mib2c.iterate.conf,v 5.9 2003/06/04 00:14:41 hardaker Exp $
> + */
> +#ifndef LHARESOURCETABLE_H
> +#define LHARESOURCETABLE_H
> +
> +/*
> + * function declarations 
> + */
> +void            init_LHAResourceTable(void);
> +void            initialize_table_LHAResourceTable(void);
> +Netsnmp_Node_Handler LHAResourceTable_handler;
> +
> +Netsnmp_First_Data_Point LHAResourceTable_get_first_data_point;
> +Netsnmp_Next_Data_Point LHAResourceTable_get_next_data_point;
> +
> +/*
> + * column number definitions for table LHAResourceTable 
> + */
> +#include "LHAResourceTable_columns.h"
> +
> +/*
> + * enum definions 
> + */
> +#include "LHAResourceTable_enums.h"
> +
> +#endif                          /* LHARESOURCETABLE_H */
> diff -urN org/snmp_subagent/LHAResourceTable_columns.h mod/snmp_subagent/LHAResourceTable_columns.h
> --- org/snmp_subagent/LHAResourceTable_columns.h	1970-01-01 09:00:00.000000000 +0900
> +++ mod/snmp_subagent/LHAResourceTable_columns.h	2007-11-26 18:01:20.000000000 +0900
> @@ -0,0 +1,19 @@
> +/*
> + * Note: this file originally auto-generated by mib2c using
> + *  : mib2c.column_defines.conf,v 5.1 2002/05/08 05:42:47 hardaker Exp $
> + */
> +#ifndef LHARESOURCETABLE_COLUMNS_H
> +#define LHARESOURCETABLE_COLUMNS_H
> +
> +/*
> + * column number definitions for table LHAResourceTable 
> + */
> +#define COLUMN_LHARESOURCEINDEX		1
> +#define COLUMN_LHARESOURCENAME		2
> +#define COLUMN_LHARESOURCETYPE		3
> +#define COLUMN_LHARESOURCENODE		4
> +#define COLUMN_LHARESOURCESTATUS		5
> +#define COLUMN_LHARESOURCEISMANAGED           6
> +#define COLUMN_LHARESOURCEFAILCOUNT           7
> +#define COLUMN_LHARESOURCEPARENT              8
> +#endif                          /* LHARESOURCETABLE_COLUMNS_H */
> diff -urN org/snmp_subagent/LHAResourceTable_enums.h mod/snmp_subagent/LHAResourceTable_enums.h
> --- org/snmp_subagent/LHAResourceTable_enums.h	1970-01-01 09:00:00.000000000 +0900
> +++ mod/snmp_subagent/LHAResourceTable_enums.h	2007-11-27 18:32:49.000000000 +0900
> @@ -0,0 +1,32 @@
> +/*
> + * Note: this file originally auto-generated by mib2c using
> + *  : mib2c.column_enums.conf,v 5.2 2003/02/22 04:09:25 hardaker Exp $
> + */
> +#ifndef LHARESOURCETABLE_ENUMS_H
> +#define LHARESOURCETABLE_ENUMS_H
> +
> +/*
> + * enums for column LHAResourceType 
> + */
> +#define LHARESOURCETYPE_UNKNOWN		0
> +#define LHARESOURCETYPE_PRIMITIVE		1
> +#define LHARESOURCETYPE_GROUP		2
> +#define LHARESOURCETYPE_CLONE		3
> +#define LHARESOURCETYPE_MASTERSLAVE		4
> +
> +/*
> + * enums for column LHAResourceStatus 
> + */
> +#define LHARESOURCESTATUS_UNKNOWN		0
> +#define LHARESOURCESTATUS_STOPPED		1
> +#define LHARESOURCESTATUS_STARTED		2
> +#define LHARESOURCESTATUS_SLAVE		3
> +#define LHARESOURCESTATUS_MASTER		4
> +
> +/*
> + * enums for column LHAResourceIsManaged
> + */
> +#define LHARESOURCEISMANAGED_UNMANAGED                0
> +#define LHARESOURCEISMANAGED_MANAGED          1
> +
> +#endif                          /* LHARESOURCETABLE_ENUMS_H */
> diff -urN org/snmp_subagent/LINUX-HA-MIB.mib mod/snmp_subagent/LINUX-HA-MIB.mib
> --- org/snmp_subagent/LINUX-HA-MIB.mib	2007-11-02 17:35:27.000000000 +0900
> +++ mod/snmp_subagent/LINUX-HA-MIB.mib	2007-12-03 16:58:46.000000000 +0900
> @@ -32,7 +32,7 @@
>  	FROM SNMPv2-CONF;
>  
>  LinuxHA	MODULE-IDENTITY
> -    LAST-UPDATED "200211040000Z"	-- Nov. 4, 2002
> +    LAST-UPDATED "200711260000Z"	-- Nov. 26, 2007
>      ORGANIZATION "High-Availability Linux Project"
>      CONTACT-INFO
>  	"Alan Robertson
> @@ -64,7 +64,7 @@
>  	and memberships accessible through SNMP. Hopefully more
>  	things can be added as Linux-HA matures."
>  
> -    REVISION "200211040000Z"	    -- Nov. 4, 2002
> +    REVISION "200711260000Z"	-- Nov. 26, 2007
>      DESCRIPTION
>  	"The original version of this MIB."
>      ::= { enterprises 4682 }
> @@ -76,6 +76,7 @@
>  --  LHAResourceGroupTable     OBJECT IDENTIFIER ::= { LinuxHA 4 }
>  --  LHAMembershipTable	      OBJECT IDENTIFIER ::= { LinuxHA 6 }
>  --  LHAHeartbeatConfigInfo    OBJECT IDENTIFIER ::= { LinuxHA 7 }
> +--  LHAResourceTable          OBJECT IDENTIFIER ::= { LinuxHA 8 }
>  --  LHATrapTable	      OBJECT IDENTIFIER ::= { LinuxHA 900 }
>  
>  LHAUUIDString ::= TEXTUAL-CONVENTION
> @@ -541,6 +542,128 @@
>  	"The other services that got respawned by heartbeat daemon."
>      ::= { LHAHeartbeatConfigInfo 15 }
>  
> +LHAResourceTable OBJECT-TYPE
> +    SYNTAX	SEQUENCE OF lhaResourceEntry
> +    MAX-ACCESS	not-accessible
> +    STATUS	current
> +    DESCRIPTION
> +	"A table containing information of all the resource for V2."
> +    ::= { LinuxHA 8 }
> +
> +LHAResourceEntry OBJECT-TYPE
> +    SYNTAX	lhaResourceEntry
> +    MAX-ACCESS	not-accessible
> +    STATUS	current
> +    DESCRIPTION
> +	"An entry that describes the resource and its status for V2."
> +    INDEX	{ LHAResourceIndex }
> +    ::= { LHAResourceTable 1 }
> +
> +lhaResourceEntry ::= SEQUENCE	{
> +    LHAResourceIndex	Integer32,
> +    LHAResourceName	DisplayString,
> +    LHAResourceType     INTEGER,
> +    LHAResourceNode	DisplayString,
> +    LHAResourceStatus	INTEGER,
> +    LHAResourceIsManaged	INTEGER,
> +    LHAResourceFailCount	Integer32,
> +    LHAResourceParent	DisplayString,
> +}
> +
> +LHAResourceIndex OBJECT-TYPE
> +    SYNTAX	Integer32 (0..65535)
> +    MAX-ACCESS	not-accessible
> +    STATUS	current
> +    DESCRIPTION
> +	"A unique integer that identifies this resource."
> +    ::= { LHAResourceEntry 1 }
> +
> +LHAResourceName OBJECT-TYPE
> +    SYNTAX	DisplayString
> +    MAX-ACCESS	read-only
> +    STATUS	current
> +    DESCRIPTION
> +	"The name of this resource."
> +    ::= { LHAResourceEntry 2 }
> +
> +LHAResourceType OBJECT-TYPE
> +    SYNTAX	INTEGER {
> +	    	    unknown (0),
> +		    primitive (1),
> +		    group (2),
> +		    clone (3),
> +		    masterSlave (4)
> +    		}
> +    MAX-ACCESS	read-only
> +    STATUS	current
> +    DESCRIPTION
> +	"The type of this resource.
> +	 0       unknown type
> +	 1       primitive resource.
> +	 2       group resource.
> +	 3       clone resource.
> +	 4	     master/slave resource.
> +	 "
> +    ::= { LHAResourceEntry 3 }
> +
> +LHAResourceNode OBJECT-TYPE
> +    SYNTAX	DisplayString
> +    MAX-ACCESS	read-only
> +    STATUS	current
> +    DESCRIPTION
> +	"The node name that this resource resides on."
> +    ::= { LHAResourceEntry 4 }
> +
> +LHAResourceStatus OBJECT-TYPE
> +    SYNTAX	INTEGER {
> +	    	    unknown (0),
> +		    stopped (1),
> +		    started (2),
> +		    slave (3),
> +		    master (4)
> +    		}
> +    MAX-ACCESS	read-only
> +    STATUS	current
> +    DESCRIPTION
> +	"The status of this resource.
> +	 0       unknown status
> +	 1       program is stopped.
> +	 2       program is started.
> +	 3       program is started in slave state.
> +	 4	 program is started in master state.
> +	 "
> +    ::= { LHAResourceEntry 5 }
> +
> +LHAResourceIsManaged OBJECT-TYPE
> +    SYNTAX	INTEGER {
> +		    unmanaged (0),
> +		    managed (1)
> +    		}
> +    MAX-ACCESS	read-only
> +    STATUS	current
> +    DESCRIPTION
> +	"The status of this resource.
> +	 0       resource is not managed.
> +	 1       resource is managed.
> +	 "
> +    ::= { LHAResourceEntry 6 }
> +
> +LHAResourceFailCount OBJECT-TYPE
> +    SYNTAX	Integer32 (0..65535)
> +    MAX-ACCESS	read-only
> +    STATUS	current
> +    DESCRIPTION
> +	"The value of this resource's fail-count."
> +    ::= { LHAResourceEntry 7 }
> +
> +LHAResourceParent OBJECT-TYPE
> +    SYNTAX	DisplayString
> +    MAX-ACCESS	read-only
> +    STATUS	current
> +    DESCRIPTION
> +	"The name of this resource's parent resource."
> +    ::= { LHAResourceEntry 8 }
> +
>  LHATrapTable                    OBJECT IDENTIFIER ::= { LinuxHA 900 }
>  
>  LHANodeStatusUpdate NOTIFICATION-TYPE
> @@ -578,4 +701,11 @@
>      	"The heartbeat agent for this node is offline. "
>      ::= { LHATrapTable 9 }
>  
> +LHAResourceStatusUpdate NOTIFICATION-TYPE
> +    OBJECTS { LHAResourceName LHAResourceNode LHAResourceStatus }
> +    STATUS  current
> +    DESCRIPTION
> +    	"A resource status change event just happened."
> +    ::= { LHATrapTable 11 }
> +
>  END
> diff -urN org/snmp_subagent/Makefile.am mod/snmp_subagent/Makefile.am
> --- org/snmp_subagent/Makefile.am	2007-11-02 17:35:27.000000000 +0900
> +++ mod/snmp_subagent/Makefile.am	2007-11-20 10:07:36.000000000 +0900
> @@ -22,6 +22,8 @@
>  hbagent_srces  = snmp-config-resolve.h	\
>  	hbagent.h			\
>  	hbagent.c			\
> +	hbagentv2.h			\
> +	hbagentv2.c			\
>  	LHANodeTable.h			\
>  	LHANodeTable_columns.h		\
>  	LHANodeTable_enums.h		\
> @@ -41,7 +43,13 @@
>  	LHAResourceGroupTable_columns.h	\
>  	LHAResourceGroupTable_enums.h	\
>  	LHAResourceGroupTable.h		\
> -	LHAResourceGroupTable.c	
> +	LHAResourceGroupTable.c		\
> +	LHAResourceTable_columns.h \
> +	LHAResourceTable_enums.h \
> +	LHAResourceTable.h		\
> +	LHAResourceTable.c		\
> +	LHAResourceStatusUpdate.h \
> +	LHAResourceStatusUpdate.c 
>  
>  test_scrs	=	SNMPAgentSanityCheck
>  
> @@ -69,8 +77,12 @@
>  hbagent_LDADD	 	= \
>                          $(top_builddir)/lib/clplumbing/libplumb.la \
>  			$(top_builddir)/lib/hbclient/libhbclient.la \
> +			$(top_builddir)/lib/crm/common/libcrmcommon.la \
> +			$(top_builddir)/lib/crm/cib/libcib.la \
> +			$(top_builddir)/lib//crm/pengine/libpe_status.la \
>  			$(top_builddir)/membership/ccm/libccmclient.la \
>  			$(top_builddir)/membership/ccm/libclm.la \
> +			$(CURSESLIBS) \
>  			$(GLIBLIB)
>  
>  hbagent_LDFLAGS		= @SNMPAGENTLIB@ 
> diff -urN org/snmp_subagent/SNMPAgentSanityCheck.in mod/snmp_subagent/SNMPAgentSanityCheck.in
> --- org/snmp_subagent/SNMPAgentSanityCheck.in	2007-11-02 17:35:27.000000000 +0900
> +++ mod/snmp_subagent/SNMPAgentSanityCheck.in	2007-11-26 09:41:14.000000000 +0900
> @@ -59,7 +59,7 @@
>  
>  # start the linux-ha snmp subagent
>  @libdir@/heartbeat/hbagent -d &
> -sleep 1
> +sleep 5
>  
>  # get the nodename for node0 and node1
>  # node0 should be the value of the localhost
> @@ -96,11 +96,81 @@
>  
>  if test $ret2 = 0; then
>  	echo "BasicSanityCheck for SNMP Subagent passed."
> -	exit 0
> +#	exit 0
>  else 
>  	echo "BasicSanityCheck for SNMP Subagent failed."
> +#	exit 1
> +fi
> +
> +#
> +# BasicSanityCheck for SNMP Subagent about CRM resources.
> +#
> +# NOTE:    Heartbeat service for this test has to run without cib.xml.
> +
> +# add CRM resource.
> +RSC0NAME="prmDummy"
> +RSC0TYPE="primitive(1)"
> +RSC0NODE="$NODE0"
> +RSC0STATUS="started(2)"
> +cibadmin --cib_create -o resources \
> +  -X '<primitive id="prmDummy" class="ocf" type="Dummy" provider="heartbeat"/>'
> +sleep 3
> +
> +# get resource's information with snmp subagent.
> +rsc0name=`snmpget -v2c localhost -c public LHAResourceName.1 \
> +  | sed -ne 's/LINUX-HA-MIB::LHAResourceName.1 = STRING: //p'`
> +rsc0type=`snmpget -v2c localhost -c public LHAResourceType.1 \
> +  | sed -ne 's/LINUX-HA-MIB::LHAResourceType.1 = INTEGER: //p'`
> +rsc0node=`snmpget -v2c localhost -c public LHAResourceNode.1 \
> +  | sed -ne 's/LINUX-HA-MIB::LHAResourceNode.1 = STRING: //p'`
> +rsc0status=`snmpget -v2c localhost -c public LHAResourceStatus.1 \
> +  | sed -ne 's/LINUX-HA-MIB::LHAResourceStatus.1 = INTEGER: //p'`
> +
> +# check for LHAResourceName
> +ret=0
> +echo "rsc0name = $rsc0name, RSC0NAME = $RSC0NAME" 
> +if test "$rsc0name" != "$RSC0NAME"; then
> +	echo "failed to get resource name." >&2
> +	ret=1
> +fi
> +
> +# check for LHAResourceType
> +if test $ret = 0; then
> +	echo "rsc0type = $rsc0type, RSC0TYPE = $RSC0TYPE" 
> +	if test "$rsc0type" != "$RSC0TYPE"; then
> +		echo "failed to get resource type." >&2
> +		ret=1
> +	fi
> +fi
> +
> +# check for LHAResourceNode
> +if test $ret = 0; then
> +	echo "rsc0node = $rsc0node, RSC0NODE = $RSC0NODE" 
> +	if test "$rsc0node" != "$RSC0NODE"; then
> +		echo "failed to get resource node." >&2
> +		ret=1
> +	fi
> +fi
> +
> +# check for LHAResourceStatus
> +if test $ret = 0; then
> +	echo "rsc0status = $rsc0status, RSC0STATUS = $RSC0STATUS" 
> +	if test "$rsc0status" != "$RSC0STATUS"; then
> +		echo "failed to get resource status." >&2
> +		ret=1
> +	fi
> +fi
> +
> +# show the result.
> +if test $ret = 0; then
> +	echo "BasicSanityCheck for SNMP Subagent about CRM resources passed."
> +	exit 0
> +else 
> +	echo "BasicSanityCheck for SNMP Subagent about CRM resources failed."
>  	exit 1
>  fi
> +
> +
>  if
>    [ -f $SNMPPIDFILE -a ! -z $SNMPPIDFILE ]
>  then
> diff -urN org/snmp_subagent/hbagent.c mod/snmp_subagent/hbagent.c
> --- org/snmp_subagent/hbagent.c	2007-11-19 15:15:07.000000000 +0900
> +++ mod/snmp_subagent/hbagent.c	2007-11-21 10:16:35.000000000 +0900
> @@ -24,6 +24,7 @@
>  #include <lha_internal.h>
>  
>  #include "hbagent.h"
> +#include "hbagentv2.h"
>  
>  #include "hb_api.h"
>  #include "heartbeat.h"
> @@ -66,13 +67,12 @@
>  #include <errno.h>
>  
>  #include "saf/ais.h"
> -
> -#define DEFAULT_TIME_OUT 5 /* default timeout value for snmp in sec. */
> -#define LHAAGENTID "lha-snmpagent"
> +#include "clplumbing/cl_uuid.h" /* UU_UNPARSE_SIZEOF */
>  
>  static unsigned long hbInitialized = 0;
>  static ll_cluster_t * hb = NULL; /* heartbeat handle */
> -static char * myid = NULL; /* my node id */
> +char * myid = NULL; /* my node id */
> +char * myuuid = NULL; /* my node uuid */
>  static SaClmHandleT clm = 0;
>  static unsigned long clmInitialized = 0;
>  
> @@ -82,6 +82,7 @@
>  static GPtrArray * gResourceTable = NULL;
>  
>  static int keep_running;
> +int snmp_cache_time_out = CACHE_TIME_OUT;
>  
>  int init_heartbeat(void);
>  int get_heartbeat_fd(void);
> @@ -559,6 +560,7 @@
>  init_heartbeat(void)
>  {
>  	char * parameter;
> +	cl_uuid_t uuid;
>  	hb = NULL;
>  
>  	cl_log_set_entity("lha-snmpagent");
> @@ -589,6 +591,18 @@
>  		return HA_FAIL;
>  	}
>  
> +	/*
> +	 * get uuid for trap message.
> +	 *   see: hbagentv2_update_diff() in hbagentv2.c
> +	 */
> +	if (hb->llc_ops->get_uuid_by_name(hb, myid, &uuid) == HA_FAIL) {
> +		cl_log(LOG_ERR, "Cannot get mynodeid");
> +		cl_log(LOG_ERR, "REASON: %s", hb->llc_ops->errmsg(hb));
> +		return HA_FAIL;
> +	}
> +	myuuid = cl_malloc(UU_UNPARSE_SIZEOF);
> +	cl_uuid_unparse(&uuid, myuuid);
> +
>  	if (hb->llc_ops->set_nstatus_callback(hb, NodeStatus, NULL) !=HA_OK){
>  	        cl_log(LOG_ERR, "Cannot set node status callback");
>  	        cl_log(LOG_ERR, "REASON: %s", hb->llc_ops->errmsg(hb));
> @@ -1307,6 +1321,7 @@
>  	struct timeval tv, *tvp;
>  	int flag, block = 0, numfds, hb_fd = 0, mem_fd = 0, debug = 0;
>  	int hb_already_dead = 0;
> +	int cib_fd = 0;
>  
>  	/* change this if you want to be a SNMP master agent */
>  	int agentx_subagent=1; 
> @@ -1314,9 +1329,6 @@
>  	/* change this if you want to run in the background */
>  	int background = 0; 
>  
> -	/* change this if you want to use syslog */
> -	int syslog = 1; 
> -
>  	/* LHAHeartbeatConfigInfo partial-mode */
>  	int hbconfig_refresh_timing = 0;
>  	int hbconfig_refresh_cnt;
> @@ -1335,6 +1347,7 @@
>  				hbconfig_refresh_timing = i / DEFAULT_TIME_OUT;
>  			else
>  				hbconfig_refresh_timing = DEFAULT_REFRESH_TIMING;
> +			snmp_cache_time_out = i;
>  			break;
>  		    case 'h':
>  			usage();
> @@ -1345,16 +1358,13 @@
>  		}
>  	}
>  
> -	if (debug) 
> +	if (debug) {
>  		cl_log_enable_stderr(TRUE);
> -	else 
> +		snmp_enable_stderrlog();
> +	} else {
>  		cl_log_enable_stderr(FALSE);
> -
> -	/* print log errors to syslog or stderr */
> -	if (syslog)
>  		snmp_enable_calllog();
> -	else
> -		snmp_enable_stderrlog();
> +	}
>  
>  	/* we're an agentx subagent? */
>  	if (agentx_subagent) {
> @@ -1364,7 +1374,7 @@
>  	}
>  
>  	/* run in background, if requested */
> -	if (background && netsnmp_daemonize(1, !syslog))
> +	if (background && netsnmp_daemonize(1, debug))
>  		exit(1);
>  
>  	/* initialize the agent library */
> @@ -1415,6 +1425,13 @@
>  	init_LHAMembershipTable();
>  	init_LHAHeartbeatConfigInfo();
>  
> +
> +	/* now implementing: hbagentv2 */
> +	if ((ret = init_hbagentv2()) != HA_OK ||
> +	    (cib_fd = get_cib_fd()) <= 0) {
> +		return -4;
> +	}
> +
>  	/* LHA-agent will be used to read LHA-agent.conf files. */
>  	init_snmp("LHA-agent");
>  
> @@ -1450,6 +1467,10 @@
>  			if (mem_fd > hb_fd)
>  				numfds = mem_fd + 1;
>  		}
> +		FD_SET(cib_fd, &fdset);
> +		if (numfds < (cib_fd + 1)) {
> +			numfds = cib_fd + 1;
> +		}
>  
>  		tv.tv_sec = DEFAULT_TIME_OUT;
>  		tv.tv_usec = 0;
> @@ -1487,6 +1508,7 @@
>  		} else if (ret == 0) {
>  			/* timeout */
>  			ping_membership(&mem_fd);
> +
>  			/* LHAHeartbeatConfigInfo partial-mode */
>  			if (hbconfig_refresh_timing
>  			&& ++hbconfig_refresh_cnt >= hbconfig_refresh_timing) {
> @@ -1513,6 +1535,12 @@
>  			    	cl_log(LOG_DEBUG, "unrecoverable membership error. quit now.");
>  				break;
>  			}
> +		} else  if (FD_ISSET(cib_fd, &fdset)) {
> +			/* change cib info events */
> +			if ((ret = handle_cib_msg()) == HA_FAIL) {
> +		  		cl_log(LOG_DEBUG, "unrecoverable CIB error. quit now.");
> +				break;
> +			}
>  		} else {
>  
>  			/* snmp request */
> @@ -1530,8 +1558,10 @@
>  	hbagent_trap(0, myid);
>  	snmp_shutdown("LHA-agent");
>  
> -	free_hbconfig();
> +	free_hbagentv2();
> + 	free_hbconfig();
>  	cl_free(myid);
> +	cl_free(myuuid);
>  	free_storage();
>  
>          if (!hb_already_dead && hb->llc_ops->signoff(hb, TRUE) != HA_OK) {
> @@ -1548,4 +1578,3 @@
>  	return 0;
>  }
>  
> -
> diff -urN org/snmp_subagent/hbagent.h mod/snmp_subagent/hbagent.h
> --- org/snmp_subagent/hbagent.h	2007-11-02 17:35:27.000000000 +0900
> +++ mod/snmp_subagent/hbagent.h	2007-12-03 16:48:19.000000000 +0900
> @@ -35,6 +35,8 @@
>  #include <clplumbing/cl_uuid.h>
>  
>  #define CACHE_TIME_OUT 5
> +#define LHAAGENTID "lha-snmpagent"
> +#define DEFAULT_TIME_OUT 5 /* default timeout value for snmp in sec. */
>  
>  typedef enum lha_group {
>  	LHA_CLUSTERINFO,
> diff -urN org/snmp_subagent/hbagentv2.c mod/snmp_subagent/hbagentv2.c
> --- org/snmp_subagent/hbagentv2.c	1970-01-01 09:00:00.000000000 +0900
> +++ mod/snmp_subagent/hbagentv2.c	2007-12-03 17:08:03.000000000 +0900
> @@ -0,0 +1,657 @@
> +#include <lha_internal.h>
> +
> +#include "hbagent.h"
> +#include "hbagentv2.h"
> +
> +
> +#include "hb_api.h"
> +#include "heartbeat.h"
> +#include "clplumbing/cl_log.h"
> +#include "clplumbing/coredumps.h"
> +
> +#include "crm/crm.h"
> +#include "crm/cib.h"
> +#include "crm/pengine/status.h"
> +#include "crm/msg_xml.h"
> +#include "crm/transition.h"
> +
> +#include <net-snmp/net-snmp-config.h>
> +#include <net-snmp/net-snmp-includes.h>
> +#include <net-snmp/agent/net-snmp-agent-includes.h>
> +#include <sys/wait.h>
> +
> +#include <unistd.h>
> +
> +#include <errno.h>
> +
> +#include "LHAResourceTable.h"
> +#include "LHAResourceStatusUpdate.h"
> +
> +
> +/*
> + * Agent MIB value conversion macros from the internal value
> + */
> +/* ref. crm/pengine/complex.h:enum pe_obj_types */
> +#define PE_OBJ_TYPES2AGENTTYPE(variant) ((int)(variant) + 1)
> +/* ref. crm/pengine/common.h:enum rsc_role_e */
> +#define RSC_ROLE_E2AGENTSTATUS(role) ((int)(role)) /* the value is identical */
> +
> +/* need more than (RID_LEN + sizeof(CRMD_ACTION_xxx) + sizeof(rc_code) */
> +#define MAX_OP_STR_LEN 256
> +/* need more than sizeof(rc_code). ref. UNIFORM_RET_EXECRA in lrm/raexec.h */
> +#define MAX_RCCODE_STR_LEN 4
> +
> +static cib_t *cib_conn = NULL;
> +static GPtrArray * gResourceTableV2 = NULL;
> +static int err_occurs = 0; /* the flag which means an error occurs in callback func. */
> +extern const char *myid;
> +extern const char *myuuid;
> +
> +/* for debug */
> +void debugPrint(HA_Message *msg, int depth, FILE *fp);
> +
> +/**
> + * Initialize of resource table v2.
> + */
> +int
> +init_resource_table_v2(void)
> +{
> +    
> +    if (gResourceTableV2) {
> +        free_resource_table_v2();
> +    }
> +
> +    return HA_OK;
> +}
> +
> +/**
> + * This is the main function to update resource table v2.
> + * Return the number of resources.
> + */
> +static int
> +update_resources_recursively(GListPtr reslist, int index)
> +{
> +
> +    if (reslist == NULL) {
> +        return index;
> +    }
> +    /*
> +     * Set resource info to resource table v2 from data_set,
> +     * and add it to Glib's array.
> +     */
> +    slist_iter(rsc, resource_t, reslist, lpc1,
> +    {
> +        cl_log(LOG_DEBUG, "resource %s processing.", rsc->id);
> +        slist_iter(node, node_t, rsc->allowed_nodes, lpc2,
> +        {
> +            struct hb_rsinfov2 *rsinfo;
> +            enum rsc_role_e rsstate;
> +
> +            rsinfo = (struct hb_rsinfov2 *) cl_malloc(sizeof(struct hb_rsinfov2));
> +            if (!rsinfo) {
> +                cl_log(LOG_CRIT, "malloc resource info v2 failed.");
> +                return HA_FAIL;
> +            }
> +
> +            rsinfo->resourceid = cl_strdup(rsc->id);
> +            rsinfo->type = PE_OBJ_TYPES2AGENTTYPE(rsc->variant);
> +
> +            /* using a temp var to suppress casting warning of the compiler */
> +            rsstate = rsc->fns->state(rsc, TRUE);
> +            if (pe_find_node_id(rsc->running_on, node->details->id) == NULL) {
> +                /*
> +                 * if the resource is not running on current node,
> +                 * its status is "stopped(1)".
> +                 */
> +                rsstate = RSC_ROLE_STOPPED;
> +            }
> +            rsinfo->status = RSC_ROLE_E2AGENTSTATUS(rsstate);
> +            rsinfo->node = cl_strdup(node->details->uname);
> +
> +            if (is_not_set(rsc->flags, pe_rsc_managed)) {
> +                rsinfo->is_managed = LHARESOURCEISMANAGED_UNMANAGED;
> +            } else {
> +                rsinfo->is_managed = LHARESOURCEISMANAGED_MANAGED;
> +            }
> +
> +            /* get fail-count from <status> */
> +            {
> +                char *attr_name = NULL;
> +                char *attr_value = NULL;
> +                crm_data_t *tmp_xml = NULL;
> +
> +                attr_name = crm_concat("fail-count", rsinfo->resourceid, '-');
> +                attr_value = g_hash_table_lookup(node->details->attrs,
> +                    attr_name); 
> +                rsinfo->failcount = crm_parse_int(attr_value, "0");
> +                crm_free(attr_name);
> +                free_xml(tmp_xml);
> +             }
> +
> +            if (rsc->parent != NULL) {
> +                rsinfo->parent = cl_strdup(rsc->parent->id);
> +            } else {
> +                rsinfo->parent = cl_strdup("");
> +            }
> +
> +            /*
> +             * if the resource stops, and its fail-count is 0,
> +             * don't list it up.
> +             */ 
> +            if (rsinfo->status != LHARESOURCESTATUS_STOPPED || 
> +                   rsinfo->failcount > 0) {
> +                rsinfo->index = index++;
> +                g_ptr_array_add(gResourceTableV2, (gpointer *)rsinfo);
> +            } else {
> +                cl_free(rsinfo->resourceid);
> +                cl_free(rsinfo->node);
> +                cl_free(rsinfo->parent);
> +                cl_free(rsinfo);
> +            }
> +
> +        }); /* end slist_iter(node) */
> +
> +        /* add resources recursively for group/clone/master */
> +        index = update_resources_recursively(rsc->fns->children(rsc), index);
> +
> +    }); /* end slist_iter(rsc) */
> +
> +    return index;
> +}
> +
> +/**
> + * Send query to the CIB and update the information of resource table v2.
> + */
> +int
> +update_resource_table_v2(void)
> +{
> +    crm_data_t *cib_object = NULL;
> +    pe_working_set_t data_set;
> +    int rc = cib_ok;
> +    int options =  cib_scope_local|cib_sync_call;
> +    int index;
> +
> +    if (!gResourceTableV2) {
> +        cl_log(LOG_ERR, "resource table v2 is NULL.");
> +        return HA_FAIL;
> +    }
> +    free_resource_table_v2();
> +
> +    rc = cib_conn->cmds->query(cib_conn, NULL, &cib_object, options);
> +    if (rc != cib_ok) {
> +        cl_log(LOG_ERR, "CIB query failed: %s", cib_error2string(rc));
> +        return HA_FAIL;
> +    }
> +    if (cib_object == NULL) {
> +        cl_log(LOG_ERR, "CIB query failed: empty result.");
> +        return HA_FAIL;
> +    }
> +
> +    cl_log(LOG_DEBUG, "CIB query done. Updating resource table v2.");
> +
> +    set_working_set_defaults(&data_set);
> +    data_set.input = cib_object;
> +    /* parse cib xml info (cib_object). */
> +    cluster_status(&data_set);
> +
> +    index = update_resources_recursively(data_set.resources, 1);
> +    if (index == HA_FAIL) {
> +        cl_log(LOG_ERR, "Update resources failed.");
> +
> +        data_set.input = NULL;
> +        cleanup_calculations(&data_set);
> +        free_xml(cib_object);
> +        return HA_FAIL;
> +    }
> +
> +    cl_log(LOG_DEBUG, "Updated %d resources.", index-1);
> +
> +
> +    data_set.input = NULL;
> +    cleanup_calculations(&data_set);
> +    free_xml(cib_object);
> +    return HA_OK;
> +}
> +
> +/**
> + * Update resource table v2 and return it's pointer.
> + * To get latest information of resources.
> + * This function is called in LHAResourceTable_load(),
> + * only when snmp cache timeout occurs.
> + */
> +GPtrArray *
> +get_resource_table_v2(void)
> +{
> +    update_resource_table_v2();
> +    return gResourceTableV2;
> +}
> +
> +/**
> + * Free resource table v2.
> + */
> +void
> +free_resource_table_v2(void)
> +{
> +    struct hb_rsinfov2 *resource;
> +
> +    if (!gResourceTableV2) {
> +        return;
> +    }
> +
> +    cl_log(LOG_DEBUG, "Freeing %d resources.", gResourceTableV2->len);
> +    while (gResourceTableV2->len) {
> +        resource = (struct hb_rsinfov2 *) g_ptr_array_remove_index_fast(gResourceTableV2, 0);
> +        cl_free(resource->resourceid);
> +        cl_free(resource->node);
> +        cl_free(resource->parent);
> +        cl_free(resource);
> +    }
> +    
> +    return;
> +}
> +
> +/**
> + * This is the main function to send a trap to tell a resource's status is changed.
> + * This function is called when a change occurs on the cib information.
> + * First, it parses a received xml message, and if the msg tells that the status of
> + * a resource changes, it sends a trap to SNMP manager via Net-SNMP daemon.
> + * Note1: It sends a trap when the resouce [stopped|started|been Slave|been Master].
> + *        And it sends a trap only when the execution of RA method is succeeded.
> + * Note2: If an error occurs in this function, set the variable "err_occurs" to tell
> + *        that to the handler. (see: handle_cib_msg())
> + */
> +static void
> +hbagentv2_update_diff(const char *event, HA_Message *msg)
> +{
> +
> +    /*implement parsing the diff and send a trap */
> +    const char *op = NULL;
> +    crm_data_t *diff = NULL;
> +    const char *set_name = NULL;
> +
> +    crm_data_t *change_set = NULL;
> +    crm_data_t *lrm_rsc = NULL;
> +    const char *node_id    = NULL;
> +    const char *rsc_id    = NULL;
> +    const char *rsc_op_id    = NULL;
> +    const char *rc_code = NULL;
> +    const char *t_magic = NULL;
> +    const char *operation = NULL;
> +    char tmp_op_str[MAX_OP_STR_LEN];
> +    char tmp_rc_str[MAX_RCCODE_STR_LEN];
> +    char *tmp = tmp_op_str;
> +
> +    /* Initialize err flag. */
> +    err_occurs = 0;
> +
> +    if (!msg) {
> +        cl_log(LOG_ERR, "cib message is NULL.");
> +        err_occurs = 1;
> +        return;
> +    }
> +    op = cl_get_string(msg, F_CIB_OPERATION);
> +    diff = get_message_xml(msg, F_CIB_UPDATE_RESULT);
> +    if (!diff) {
> +        cl_log(LOG_ERR, "update result is NULL.");
> +        return;
> +    }
> +
> +    /* for debug */
> +    /*
> +    {
> +        FILE * fp;
> +        fp = fopen("/tmp/msgdiff.out", "a");
> +        debugPrint(diff, 0, fp);
> +        fclose(fp);
> +    }
> +    */
> +
> +    /*
> +     * start to get the following information from difference of cib xml.
> +     *   <lrm_rsc_op operation="xxx" rc_code="yyy">
> +     */
> +
> +    /* get the head pointer of <status> */
> +    set_name = "diff-added"; /* we need the cib info only which have been updated. */
> +    change_set = find_xml_node(diff, set_name, FALSE);
> +    change_set = find_xml_node(change_set, XML_TAG_CIB, FALSE);
> +    change_set = find_xml_node(change_set, XML_CIB_TAG_STATUS, FALSE);
> +    if (!change_set) {
> +        /* There is no information of <status> */
> +        free_xml(diff);
> +        return;
> +    }
> +
> +    xml_child_iter_filter(
> +        change_set, node_state, XML_CIB_TAG_STATE,
> +
> +        /* get the node id at which the resources changed */
> +        node_id = crm_element_value(node_state, XML_ATTR_ID);
> +        if (!node_id) {
> +            /* There is no information of <node_status> */
> +            free_xml(diff);
> +            return;
> +        }
> +        if (STRNCMP_CONST(node_id, myuuid) != 0) {
> +            /* This change is not at my node */
> +            free_xml(diff);
> +            return;
> +        }
> +
> +        /* get the head pointer of <lrm_resource>  */
> +        lrm_rsc = find_xml_node(node_state, XML_CIB_TAG_LRM, FALSE);
> +        lrm_rsc = find_xml_node(lrm_rsc, XML_LRM_TAG_RESOURCES, FALSE);
> +        if (!lrm_rsc) {
> +            /* There is no information of <lrm_resources> */
> +            free_xml(diff);
> +            return; 
> +        }
> +        lrm_rsc = find_xml_node(lrm_rsc, XML_LRM_TAG_RESOURCE, FALSE);
> +        if (!lrm_rsc) {
> +            /* There is no information of <lrm_resource> */
> +            free_xml(diff);
> +            return; 
> +        }
> +
> +        /*
> +         * now, get the head pointer of <lrm_rsc_op>,
> +         * and parse it's resource id, operation,  and rc_code.
> +         */
> +        xml_child_iter_filter(
> +            lrm_rsc, lrm_rsc_op, XML_LRM_TAG_RSC_OP,
> +
> +            rsc_id = crm_element_value(lrm_rsc, XML_ATTR_ID);
> +            operation = crm_element_value(lrm_rsc_op, XML_LRM_ATTR_TASK);
> +            rc_code = crm_element_value(lrm_rsc_op, XML_LRM_ATTR_RC);
> +            rsc_op_id = crm_element_value(lrm_rsc_op, XML_ATTR_ID);
> +            t_magic = crm_element_value(lrm_rsc_op, XML_ATTR_TRANSITION_MAGIC);
> +            ); /* end of xml_child_iter_filter(lrm_rsc) */
> +        ); /* end of xml_child_iter_filter(change_set) */
> +
> +
> +    /*
> +     * Sometimes, the difference of cib infomation doesn't include operation and rc_code.
> +     * Like when you move resources by hand (ex. crm_resource -M, or -F), or
> +     * resources move according to <rule> and so on.
> +     * In these cases, get them from other attributes' value.
> +     */
> +    /* get operation from lrm_rsc_op's id */
> +    if (!operation) {
> +        strcpy(tmp_op_str, rsc_op_id);
> +        tmp = strrchr(tmp_op_str, '_');
> +        *tmp = '\0';    
> +        operation = strrchr(tmp_op_str, '_') + 1;
> +    }
> +    /* get rc_code from transition magic number */
> +    if (!rc_code) {
> +        if (t_magic != NULL) {
> +            int transition_num = -1;
> +            int action_id = -1;
> +            int status = -1;
> +            int rc = -1;
> +            char *uuid = NULL;
> +
> +            if (!decode_transition_magic(
> +                    t_magic, &uuid, &transition_num, &action_id, &status, &rc)) {
> +                cl_log(LOG_ERR, "decode_transition_magic() is failed.");
> +                free_xml(diff);
> +                return;
> +            }
> +            crm_free(uuid);
> +            sprintf(tmp_rc_str, "%d\n", rc);
> +            rc_code = tmp_rc_str;
> +        }
> +    }
> +
> +    /* now, send a trap. */
> +    if (operation != NULL && rc_code != NULL) {
> +        if (atoi(rc_code) == EXECRA_OK) {
> +            struct hb_rsinfov2 resource;
> +
> +            resource.resourceid = cl_strdup(rsc_id);
> +            resource.node = cl_strdup(myid);
> +
> +            /* LHAResourceStatus is ... */
> +            if (safe_str_eq(operation, CRMD_ACTION_STOP)) {
> +                /* 1: Stopped */
> +                resource.status = LHARESOURCESTATUS_STOPPED;
> +            } else if (safe_str_eq(operation, CRMD_ACTION_START)) {
> +                /* 2: Started */
> +                resource.status = LHARESOURCESTATUS_STARTED;
> +            } else if (safe_str_eq(operation, CRMD_ACTION_DEMOTE)) {
> +                /* 3: Slave */
> +                resource.status = LHARESOURCESTATUS_SLAVE;
> +            } else if (safe_str_eq(operation, CRMD_ACTION_PROMOTE)) {
> +                /* 4: Master */
> +                resource.status = LHARESOURCESTATUS_MASTER;
> +            } else {
> +                /* other action. send no trap. */
> +                cl_free(resource.resourceid);
> +                cl_free(resource.node);
> +                free_xml(diff);
> +                return;
> +            }
> +    
> +            send_LHAResourceStatusUpdate_trap(&resource);
> +            cl_free(resource.resourceid);
> +            cl_free(resource.node);
> +        } else {
> +            /* operation does not succeed.  */
> +            /* do nothing (for the present) */
> +        }
> +    }
> +
> +    free_xml(diff);
> +    return;    
> +
> +}
> +
> +/**
> + * Initialization of connection to the CIB.
> + * Have a connection made newly. And set callback function, hbagentv2_update_diff(),
> + * that is called when cib infomation message changes.
> + */
> +static int
> +init_cib(void)
> +{
> +    int rc;
> +
> +    
> +    cib_conn = cib_new();
> +    if (cib_conn == NULL) {
> +        cl_log(LOG_ERR, "CIB connection initialization failed.");
> +        return HA_FAIL;
> +    }
> +    rc = cib_conn->cmds->signon(cib_conn, LHAAGENTID, cib_query);
> +    if (rc != cib_ok) {
> +        cl_log(LOG_ERR, "CIB connection signon failed.");
> +        return HA_FAIL;
> +    }
> +
> +    rc = cib_conn->cmds->add_notify_callback(cib_conn, T_CIB_DIFF_NOTIFY,
> +                                             hbagentv2_update_diff);
> +    if (rc != cib_ok) {
> +        cl_log(LOG_ERR, "CIB connection adding callback failed.");
> +        return HA_FAIL;
> +    }
> +
> +    cl_log(LOG_INFO, "CIB connection initialization completed.");
> +    return HA_OK;
> +}
> +
> +/**
> + * Sign off and clean the connection to the CIB.
> + */
> +static void
> +free_cib(void)
> +{
> +    if (cib_conn) {
> +        if (cib_conn->cmds->signoff(cib_conn) != cib_ok) {
> +            cl_log(LOG_WARNING, "CIB connection signoff failed(ignored).");
> +        }
> +        cib_delete(cib_conn);
> +        cib_conn = NULL;
> +    }
> +
> +    return;
> +}
> +
> +/**
> + * Returns a file discripter of the connection to the CIB.
> + *   -1   : error occurs.
> + *   else : cib conn's fd.
> + */
> +int
> +get_cib_fd(void)
> +{
> +    int fd;
> +    if (!cib_conn) {
> +        cl_log(LOG_ERR, "CIB is not initialized.");
> +        return -1;
> +    }
> +    if ((fd = cib_conn->cmds->inputfd(cib_conn)) < 0) {
> +        cl_log(LOG_ERR, "Can not get CIB inputfd.");
> +        return -1;
> +    }
> +    return fd;
> +}
> +
> +/**
> + * Handler of cib information message changes.
> + * Set this function in the select loop to send a trap.
> + */
> +int
> +handle_cib_msg(void)
> +{
> +
> +    /* TODO: this prototype is not exported in any headers */
> +    gboolean cib_native_dispatch(IPC_Channel *channel, gpointer user_data);
> +
> +    if (cib_conn->cmds->msgready(cib_conn)) {
> +        IPC_Channel * chan;
> +
> +        /* get IPC Channel. */
> +        chan = cib_conn->cmds->channel(cib_conn);
> +        if (!chan) {
> +            cl_log(LOG_ERR, "CIB connection's channel is NULL.");
> +            return HA_FAIL;
> +        }
> +        /* check CIB connection. */
> +        if (chan->ch_status == IPC_DISCONNECT) {
> +            cl_log(LOG_ERR, "Lost connection to the CIB.");
> +            return HA_FAIL;
> +        }
> +        /* call callback function. */
> +        if (!cib_native_dispatch(NULL, cib_conn)) {
> +            cl_log(LOG_ERR, "cib_native_dispatch() failed.");
> +            return HA_FAIL;
> +        }
> +        /* check if an error occurs in callback function. */
> +        if (err_occurs) {
> +            return HA_FAIL;
> +        }
> +
> +    }
> +    return HA_OK;
> +}
> +
> +/**
> + * Initialization of hbagentv2.
> + *   hbagentv2 is agent which keeps watching on operation of resources.
> + *   (see: LHAResourceTable and LHAResourceStatusUpdate)
> + */
> +int
> +init_hbagentv2(void)
> +{
> +    int ret;
> +
> +    gResourceTableV2 = g_ptr_array_new();
> +    if (gResourceTableV2 == NULL) {
> +        cl_log(LOG_ERR, "Storage allocation failure for hbagentv2.");
> +        return HA_FAIL;
> +    }
> +
> +    ret = init_cib();
> +    if (ret != HA_OK) {
> +        cl_log(LOG_ERR, "init_cib() failed.");
> +        return ret;
> +    }
> +    ret = init_resource_table_v2();
> +    if (ret != HA_OK) {
> +        cl_log(LOG_ERR, "resource table v2 initialization failure.");    
> +    }
> +
> +    init_LHAResourceTable();
> +
> +    cl_log(LOG_INFO, "hbagentv2 initialization completed.");
> +
> +    return HA_OK;
> +}
> +
> +/**
> + * Free and clear resource table v2 and cib connection.
> + * Disposer which is called before stopping agent.
> + */
> +void
> +free_hbagentv2(void)
> +{
> +    free_resource_table_v2();
> +    g_ptr_array_free(gResourceTableV2, 1);
> +    gResourceTableV2 = NULL;
> +    free_cib();
> +}
> +
> +/*
> + * debug print for cib info.
> + */
> +void
> +debugPrint(HA_Message *msg, int depth, FILE *fp)
> +{
> +    int i;
> +
> +    if (msg == NULL) {
> +        return;
> +    }
> +
> +    if (fp == NULL) {
> +        fp = stdout;
> +    }
> +
> +    for (i = 0; i < msg->nfields; i++) {
> +        int j;
> +        for (j = 0; j < depth; j++) {
> +            fprintf(fp, "    ");
> +            fflush(fp);
> +        }
> +        if (msg->types[i] == FT_STRING) {
> +            fprintf(fp, "[%2d] %s = %s\n", i, msg->names[i], (char*)msg->values[i]);
> +            fflush(fp);
> +        }
> +        else if (msg->types[i] == FT_STRUCT || msg->types[i] == FT_UNCOMPRESS) {
> +            fprintf(fp, "[%2d] %s {\n", i, msg->names[i]);
> +            fflush(fp);
> +            debugPrint(msg->values[i], depth + 1, fp);
> +
> +            for (j = 0; j < depth; j++) {
> +                fprintf(fp, "    ");
> +                fflush(fp);
> +            }
> +            fprintf(fp, "}\n");
> +            fflush(fp);
> +        }
> +        else {
> +            fprintf(fp, "[%2d] %s is [%d] TYPE.\n", i, msg->names[i], msg->types[i]);
> +            fflush(fp);
> +        }
> +    }
> +}
> +
> +/**
> + * Emacs stuff:
> + * Local Variables:
> + * mode: C
> + * c-basic-offset: 4
> + * indent-tabs-mode: nil
> + * End:
> + *
> + */
> diff -urN org/snmp_subagent/hbagentv2.h mod/snmp_subagent/hbagentv2.h
> --- org/snmp_subagent/hbagentv2.h	1970-01-01 09:00:00.000000000 +0900
> +++ mod/snmp_subagent/hbagentv2.h	2007-11-26 17:59:46.000000000 +0900
> @@ -0,0 +1,28 @@
> +#ifndef _HBAGENTV2_H 
> +#define _HBAGENTV2_H 
> +
> +
> +
> +struct hb_rsinfov2 {
> +    size_t index;
> +    char * resourceid;
> +    uint32_t type;
> +    uint32_t status;
> +    char * node;
> +    uint32_t is_managed;
> +    uint32_t failcount;
> +    char * parent;
> +};
> +
> +int init_hbagentv2(void);
> +void free_hbagentv2(void);
> +
> +int get_cib_fd(void);
> +int handle_cib_msg(void);
> +
> +int init_resource_table_v2(void);
> +int update_resource_table_v2(void);
> +GPtrArray *get_resource_table_v2(void);
> +void free_resource_table_v2(void);
> +
> +#endif  /* _HBAGENTV2_H */

> _______________________________________________________
> Linux-HA-Dev: Linux-HA-Dev at lists.linux-ha.org
> http://lists.linux-ha.org/mailman/listinfo/linux-ha-dev
> Home Page: http://linux-ha.org/



More information about the Linux-HA-Dev mailing list