Logo Search packages:      
Sourcecode: heartbeat-2 version File versions  Download package

apcmastersnmp.c

/* $Id: apcmastersnmp.c,v 1.24 2005/05/20 17:50:32 msoffen Exp $ */
/*
 * Stonith module for APC Masterswitch (SNMP)
 * Copyright (c) 2001 Andreas Piesk <a.piesk@gmx.net>
 * Mangled by Sun Jiang Dong <sunjd@cn.ibm.com>, IBM, 2005
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2.1 of the License, or (at your option) any later version.*
 *
 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.
 *
 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 *
 */

/* device ID */
#define     DEVICE                        "APC MasterSwitch (SNMP)"

#include "stonith_plugin_common.h"
#undef FREE /* defined by snmp stuff */

#ifdef PACKAGE_BUGREPORT
#undef PACKAGE_BUGREPORT
#endif
#ifdef PACKAGE_NAME
#undef PACKAGE_NAME
#endif
#ifdef PACKAGE_STRING
#undef PACKAGE_STRING
#endif
#ifdef PACKAGE_TARNAME
#undef PACKAGE_TARNAME
#endif
#ifdef PACKAGE_VERSION
#undef PACKAGE_VERSION
#endif

#ifdef HAVE_NET_SNMP_NET_SNMP_CONFIG_H
#       include <net-snmp/net-snmp-config.h>
#       include <net-snmp/net-snmp-includes.h>
#       include <net-snmp/agent/net-snmp-agent-includes.h>
#       define  INIT_AGENT()    init_master_agent()
#else
#       include <ucd-snmp/ucd-snmp-config.h>
#       include <ucd-snmp/ucd-snmp-includes.h>
#       include <ucd-snmp/ucd-snmp-agent-includes.h>
#       ifndef NETSNMP_DS_APPLICATION_ID
#               define NETSNMP_DS_APPLICATION_ID        DS_APPLICATION_ID
#       endif
#       ifndef NETSNMP_DS_AGENT_ROLE
#               define NETSNMP_DS_AGENT_ROLE    DS_AGENT_ROLE
#       endif
#       define netsnmp_ds_set_boolean   ds_set_boolean
#       define  INIT_AGENT()    init_master_agent(161, NULL, NULL)
#endif

#define PIL_PLUGIN              apcmastersnmp
#define PIL_PLUGIN_S            "apcmastersnmp"
#define PIL_PLUGINLICENSE     LICENSE_LGPL
#define PIL_PLUGINLICENSEURL  URL_LGPL
#include <pils/plugin.h>

#define     DEBUGCALL                           \
    if (Debug) {                          \
      LOG(PIL_DEBUG, "%s: called.", __FUNCTION__);    \
    }

static StonithPlugin *  apcmastersnmp_new(const char *);
static void apcmastersnmp_destroy(StonithPlugin *);
static const char **    apcmastersnmp_get_confignames(StonithPlugin *);
static int  apcmastersnmp_set_config(StonithPlugin *, StonithNVpair *);
static const char *     apcmastersnmp_getinfo(StonithPlugin * s, int InfoType);
static int  apcmastersnmp_status(StonithPlugin * );
static int  apcmastersnmp_reset_req(StonithPlugin * s, int request, const char * host);
static char **    apcmastersnmp_hostlist(StonithPlugin  *);

static struct stonith_ops apcmastersnmpOps ={
      apcmastersnmp_new,            /* Create new STONITH object  */
      apcmastersnmp_destroy,        /* Destroy STONITH object     */
      apcmastersnmp_getinfo,        /* Return STONITH info string */
      apcmastersnmp_get_confignames,      /* Get configuration parameters     */
      apcmastersnmp_set_config,     /* Set configuration */
      apcmastersnmp_status,         /* Return STONITH device status     */
      apcmastersnmp_reset_req,      /* Request a reset */
      apcmastersnmp_hostlist,       /* Return list of supported hosts */
};

PIL_PLUGIN_BOILERPLATE2("1.0", Debug)
static const PILPluginImports*  PluginImports;
static PILPlugin*               OurPlugin;
static PILInterface*          OurInterface;
static StonithImports*        OurImports;
static void*                  interfprivate;

PIL_rc
PIL_PLUGIN_INIT(PILPlugin*us, const PILPluginImports* imports);

PIL_rc
PIL_PLUGIN_INIT(PILPlugin*us, const PILPluginImports* imports)
{
      /* Force the compiler to do a little type checking */
      (void)(PILPluginInitFun)PIL_PLUGIN_INIT;
      DEBUGCALL;

      PluginImports = imports;
      OurPlugin = us;

      /* Register ourself as a plugin */
      imports->register_plugin(us, &OurPIExports);  

      /*  Register our interface implementation */
      return imports->register_interface(us, PIL_PLUGINTYPE_S
      ,     PIL_PLUGIN_S
      ,     &apcmastersnmpOps
      ,     NULL        /*close */
      ,     &OurInterface
      ,     (void*)&OurImports
      ,     &interfprivate); 
}

/*
 * APCMaster tested with APC Masterswitch 9212
 */

/* outlet commands / status codes */
#define OUTLET_ON             1
#define OUTLET_OFF                  2
#define OUTLET_REBOOT               3
#define OUTLET_NO_CMD_PEND          2

/* oids */
#define OID_IDENT             ".1.3.6.1.4.1.318.1.1.4.1.4.0"
#define OID_NUM_OUTLETS             ".1.3.6.1.4.1.318.1.1.4.4.1.0"
#define OID_OUTLET_NAMES            ".1.3.6.1.4.1.318.1.1.4.5.2.1.3.%i"
#define OID_OUTLET_STATE            ".1.3.6.1.4.1.318.1.1.4.4.2.1.3.%i"
#define OID_OUTLET_COMMAND_PENDING  ".1.3.6.1.4.1.318.1.1.4.4.2.1.2.%i"
#define OID_OUTLET_REBOOT_DURATION  ".1.3.6.1.4.1.318.1.1.4.5.2.1.5.%i"

/* own defines */
#define MAX_STRING            128
#define ST_PORT               "port"

/* structur of stonith object */
struct pluginDevice {
      StonithPlugin           sp;         /* StonithPlugin object */
      const char*       pluginid;   /* id of object         */
      const char*       idinfo;           /* type of device */
      struct snmp_session*    sptr;       /* != NULL->session created */
      char *                  hostname;   /* masterswitch's hostname  */
                                    /* or  ip addr          */
      int               port;       /* snmp port            */
      char *                  community;  /* snmp community (r/w) */
      int               num_outlets;      /* number of outlets    */
};

/* for checking hardware (issue a warning if mismatch) */
static const char* APC_tested_ident[] = {"AP9606","AP7920","AP_other_well_tested"};

/* constant strings */
static const char *pluginid = "APCMS-SNMP-Stonith";
static const char *NOTpluginID = "APCMS SNMP device has been destroyed";

#include "stonith_config_xml.h"

#define XML_PORT_SHORTDESC \
      XML_PARM_SHORTDESC_BEGIN("en") \
      ST_PORT \
      XML_PARM_SHORTDESC_END

#define XML_PORT_LONGDESC \
      XML_PARM_LONGDESC_BEGIN("en") \
      "The port number on which the SNMP server is running on the STONITH device" \
      XML_PARM_LONGDESC_END

#define XML_PORT_PARM \
      XML_PARAMETER_BEGIN(ST_PORT, "string") \
        XML_PORT_SHORTDESC \
        XML_PORT_LONGDESC \
      XML_PARAMETER_END

static const char *apcmastersnmpXML = 
  XML_PARAMETERS_BEGIN
    XML_IPADDR_PARM
    XML_PORT_PARM
    XML_COMMUNITY_PARM
  XML_PARAMETERS_END;

/*
 * own prototypes 
 */

static void APC_error(struct snmp_session *sptr, const char *fn
,     const char *msg);
static struct snmp_session *APC_open(char *hostname, int port
,     char *community);
static void *APC_read(struct snmp_session *sptr, const char *objname
,     int type);
static int APC_write(struct snmp_session *sptr, const char *objname
,     char type, char *value);

static void 
APC_error(struct snmp_session *sptr, const char *fn, const char *msg)
{
    int snmperr = 0;
    int cliberr = 0;
    char *errstr;

    snmp_error(sptr, &cliberr, &snmperr, &errstr);
    LOG(PIL_CRIT
    , "%s: %s (cliberr: %i / snmperr: %i / error: %s)."
    , fn, msg, cliberr, snmperr, errstr);
    free(errstr);
}


/*
 *  creates a snmp session
 */
static struct snmp_session *
APC_open(char *hostname, int port, char *community)
{
    static struct snmp_session session;
    struct snmp_session *sptr;

    DEBUGCALL;

    /* create session */
    snmp_sess_init(&session);

    /* fill session */
    session.peername = hostname;
    session.version = SNMP_VERSION_1;
    session.remote_port = port;
    session.community = (u_char *)community;
    session.community_len = strlen(community);
    session.retries = 5;
    session.timeout = 1000000;

    /* open session */
    sptr = snmp_open(&session);

    if (sptr == NULL) {
      APC_error(&session, __FUNCTION__, "cannot open snmp session");
    }

    /* return pointer to opened session */
    return (sptr);
}

/*
 * parse config
 */

/*
 * read value of given oid and return it as string
 */
static void *
APC_read(struct snmp_session *sptr, const char *objname, int type)
{
    oid name[MAX_OID_LEN];
    size_t namelen = MAX_OID_LEN;
    struct variable_list *vars;
    struct snmp_pdu *pdu;
    struct snmp_pdu *resp;
    static char response_str[MAX_STRING];
    static int response_int;

    DEBUGCALL;

    /* convert objname into oid; return NULL if invalid */
    if (!read_objid(objname, name, &namelen)) {
        LOG(PIL_CRIT, "%s: cannot convert %s to oid.", __FUNCTION__, objname);
      return (NULL);
    }

    /* create pdu */
    if ((pdu = snmp_pdu_create(SNMP_MSG_GET)) != NULL) {

      /* get-request have no values */
      snmp_add_null_var(pdu, name, namelen);

      /* send pdu and get response; return NULL if error */
      if (snmp_synch_response(sptr, pdu, &resp) == SNMPERR_SUCCESS) {

          /* request succeed, got valid response ? */
          if (resp->errstat == SNMP_ERR_NOERROR) {

            /* go through the returned vars */
            for (vars = resp->variables; vars;
                 vars = vars->next_variable) {

                /* return response as string */
                if ((vars->type == type) && (type == ASN_OCTET_STR)) {
                  memset(response_str, 0, MAX_STRING);
                  strncpy(response_str, (char *)vars->val.string,
                        MIN(vars->val_len, MAX_STRING));
                  snmp_free_pdu(resp);
                  return ((void *) response_str);
                }
                /* return response as integer */
                if ((vars->type == type) && (type == ASN_INTEGER)) {
                  response_int = *vars->val.integer;
                  snmp_free_pdu(resp);
                  return ((void *) &response_int);
                }
            }
          }else{
            LOG(PIL_CRIT, "%s: error in response packet, reason %ld [%s]."
            ,   __FUNCTION__, resp->errstat, snmp_errstring(resp->errstat));
          }
      }else{
            APC_error(sptr, __FUNCTION__, "error sending/receiving pdu");
        }
      /* free repsonse pdu (necessary?) */
      snmp_free_pdu(resp);
    }else{
        APC_error(sptr, __FUNCTION__, "cannot create pdu");
    }
    /* error: return nothing */
    return (NULL);
}

/*
 * write value of given oid
 */
static int
APC_write(struct snmp_session *sptr, const char *objname, char type,
        char *value)
{
    oid name[MAX_OID_LEN];
    size_t namelen = MAX_OID_LEN;
    struct snmp_pdu *pdu;
    struct snmp_pdu *resp;

    DEBUGCALL;

    /* convert objname into oid; return FALSE if invalid */
    if (!read_objid(objname, name, &namelen)) {
        LOG(PIL_CRIT, "%s: cannot convert %s to oid.", __FUNCTION__, objname);
        return (FALSE);
    }

    /* create pdu */
    if ((pdu = snmp_pdu_create(SNMP_MSG_SET)) != NULL) {

      /* add to be written value to pdu */
      snmp_add_var(pdu, name, namelen, type, value);

      /* send pdu and get response; return NULL if error */
      if (snmp_synch_response(sptr, pdu, &resp) == STAT_SUCCESS) {

          /* go through the returned vars */
          if (resp->errstat == SNMP_ERR_NOERROR) {

            /* request successful done */
            snmp_free_pdu(resp);
            return (TRUE);

          }else{
            LOG(PIL_CRIT, "%s: error in response packet, reason %ld [%s]."
            ,   __FUNCTION__, resp->errstat, snmp_errstring(resp->errstat));
          }
      }else{
            APC_error(sptr, __FUNCTION__, "error sending/receiving pdu");
        }
      /* free pdu (again: necessary?) */
      snmp_free_pdu(resp);
    }else{
        APC_error(sptr, __FUNCTION__, "cannot create pdu");
    }
    /* error */
    return (FALSE);
}

/*
 * return the status for this device 
 */

static int
apcmastersnmp_status(StonithPlugin * s)
{
    struct pluginDevice *ad;
    char *ident;
    int i;

    DEBUGCALL;

    ERRIFNOTCONFIGED(s, S_OOPS);

    ad = (struct pluginDevice *) s;

    if ((ident = APC_read(ad->sptr, OID_IDENT, ASN_OCTET_STR)) == NULL) {
      LOG(PIL_CRIT, "%s: cannot read ident.", __FUNCTION__);
      return (S_ACCESS);
    }

    /* issue a warning if ident mismatches */
    for(i=DIMOF(APC_tested_ident) -1; i >=0 ; i--) {
      if (strcmp(ident, APC_tested_ident[i]) == 0) {
       break;
      }
    }

    if (i<0) {
      LOG(PIL_WARN
        ,   "%s: module not tested with this hardware '%s'."
        ,   __FUNCTION__, ident);
    }
    /* status ok */
    return (S_OK);
}

/*
 * return the list of hosts configured for this device 
 */

static char **
apcmastersnmp_hostlist(StonithPlugin * s)
{
    char **hl;
    struct pluginDevice *ad;
    int j, h, num_outlets;
    char *outlet_name;
    char objname[MAX_STRING];

    DEBUGCALL;

    ERRIFNOTCONFIGED(s, NULL);

    ad = (struct pluginDevice *) s;

    /* allocate memory for array of up to NUM_OUTLETS strings */
    if ((hl = (char **)MALLOC((ad->num_outlets+1) * sizeof(char *))) == NULL) {
      LOG(PIL_CRIT, "%s: out of memory.", __FUNCTION__);
      return (NULL);
    }
    /* clear hostlist array */
    memset(hl, 0, (ad->num_outlets + 1) * sizeof(char *));
    num_outlets = 0;

    /* read NUM_OUTLETS values and put them into hostlist array */
    for (j = 0; j < ad->num_outlets; ++j) {

      /* prepare objname */
      snprintf(objname, MAX_STRING, OID_OUTLET_NAMES, j + 1);

      /* read outlet name */
      if ((outlet_name = APC_read(ad->sptr, objname, ASN_OCTET_STR)) ==
          NULL) {
          LOG(PIL_CRIT, "%s: cannot read name for outlet %d."
            ,   __FUNCTION__, j+1);
          stonith_free_hostlist(hl);
          hl = NULL;
          return (hl);
      }

      /* Check whether the host is already listed */
      for (h = 0; h < num_outlets; ++h) {
            if (strcasecmp(hl[h],outlet_name) == 0)
                  break;
      }

      if (h >= num_outlets) {
            /* put outletname in hostlist */
            if (Debug) {
                  LOG(PIL_DEBUG, "%s: added %s to hostlist."
                ,   __FUNCTION__, outlet_name);
            }
            
            if ((hl[num_outlets] = STRDUP(outlet_name)) == NULL) {
                LOG(PIL_CRIT, "%s: out of memory.", __FUNCTION__);
                stonith_free_hostlist(hl);
                hl = NULL;
                return (hl);
            }
            g_strdown(hl[num_outlets]);
            num_outlets++;
      }
    }


    if (Debug) {
      LOG(PIL_DEBUG, "%s: %d unique hosts connected to %d outlets."
      ,   __FUNCTION__, num_outlets, j);
    }
    /* return list */
    return (hl);
}

/*
 * reset the host 
 */

static int
apcmastersnmp_reset_req(StonithPlugin * s, int request, const char *host)
{
    struct pluginDevice *ad;
    char objname[MAX_STRING];
    char value[MAX_STRING];
    char *outlet_name;
    int i, h, num_outlets, outlet, reboot_duration, *state, bad_outlets;
    int outlets[8]; /* Assume that one node is connected to a 
                   maximum of 8 outlets */
    
    DEBUGCALL;

    ERRIFNOTCONFIGED(s, S_OOPS);

    ad = (struct pluginDevice *) s;

    num_outlets = 0;
    reboot_duration = 0;
    bad_outlets = 0;

    /* read max. as->num_outlets values */
    for (outlet = 1; outlet <= ad->num_outlets; outlet++) {

      /* prepare objname */
      snprintf(objname, MAX_STRING, OID_OUTLET_NAMES, outlet);

      /* read outlet name */
      if ((outlet_name = APC_read(ad->sptr, objname, ASN_OCTET_STR))
      ==    NULL) {
          LOG(PIL_CRIT, "%s: cannot read name for outlet %d."
            ,   __FUNCTION__, outlet);
          return (S_ACCESS);
      }
      
      /* found one */
      if (strcasecmp(outlet_name, host) == 0) {
            if (Debug) {
                LOG(PIL_DEBUG, "%s: found %s at outlet %d."
                ,   __FUNCTION__, host, outlet);
            }
            /* Check that the outlet is not administratively down */
            
            /* prepare objname */
            snprintf(objname, MAX_STRING, OID_OUTLET_STATE, outlet);

            /* get outlet's state */
            if ((state = APC_read(ad->sptr, objname, ASN_INTEGER)) == NULL) {
                  LOG(PIL_CRIT
                  ,     "%s: cannot read state for outlet %d."
                  ,     __FUNCTION__, outlet);
                  return (S_ACCESS);
            }

            if (*state == OUTLET_OFF) {
                  if (Debug) {
                        LOG(PIL_DEBUG, "%s: outlet %d is off."
                        ,     __FUNCTION__, outlet);
                  }
                  continue;
            }
            
              /* prepare oid */
              snprintf(objname, MAX_STRING, OID_OUTLET_REBOOT_DURATION
            ,     outlet);

              /* read reboot duration of the port */
              if ((state = APC_read(ad->sptr, objname, ASN_INTEGER))
            ==    NULL) {
                  LOG(PIL_CRIT
                  ,     "%s: cannot read reboot duration for outlet %d."
                        ,     __FUNCTION__, outlet);
                  return (S_ACCESS);
              }
              if (num_outlets == 0) {
               /* save the inital value of the first port */
               reboot_duration = *state;
              } else if (reboot_duration != *state) {
              LOG(PIL_WARN, "%s: outlet %d has a different reboot duration!"
              , __FUNCTION__, outlet);
              if (reboot_duration < *state)
                        reboot_duration = *state;
              }
          
            /* Ok, add it to the list of outlets to control */
            outlets[num_outlets]=outlet;
            num_outlets++;
      }
    }
    if (Debug) {
          LOG(PIL_DEBUG, "%s: outlet: %i.", __FUNCTION__, outlet);
    }

    /* host not found in outlet names */
    if (num_outlets < 1) {
      LOG(PIL_CRIT, "%s: no active outlet for '%s'.", __FUNCTION__, host);
      return (S_BADHOST);
    }

    /* Turn them all off */

    for (outlet=outlets[0], i=0 ; i < num_outlets; i++, outlet = outlets[i]) {
          /* prepare objname */
          snprintf(objname, MAX_STRING, OID_OUTLET_COMMAND_PENDING, outlet);

          /* are there pending commands ? */
          if ((state = APC_read(ad->sptr, objname, ASN_INTEGER)) == NULL) {
            LOG(PIL_CRIT, "%s: cannot read pending commands for outlet %d." 
                , __FUNCTION__, outlet);
            return (S_ACCESS);
          }

          if (*state != OUTLET_NO_CMD_PEND) {
            LOG(PIL_CRIT, "%s: command pending.", __FUNCTION__);
            return (S_RESETFAIL);
          }
          
          /* prepare objnames */
          snprintf(objname, MAX_STRING, OID_OUTLET_STATE, outlet);
          snprintf(value, MAX_STRING, "%i", OUTLET_REBOOT);

          /* send reboot cmd */
          if (!APC_write(ad->sptr, objname, 'i', value)) {
            LOG(PIL_CRIT
            ,     "%s: cannot send reboot command for outlet %d."
            ,     __FUNCTION__, outlet);
            return (S_ACCESS);
          }
    }
  
    /* wait max. 2*reboot_duration for all outlets to go back on */
    for (i = 0; i < reboot_duration << 1; i++) {
          
          sleep(1);

          bad_outlets = 0;
          for (outlet=outlets[0], h=0 ; h < num_outlets; h++, 
                      outlet = outlets[h]) {

            /* prepare objname of the first outlet */
            snprintf(objname, MAX_STRING, OID_OUTLET_STATE, outlet);
            /* get outlet's state */
            
            if ((state = APC_read(ad->sptr, objname, ASN_INTEGER))
            == NULL)                {
                  LOG(PIL_CRIT
                  ,     "%s: cannot read state for outlet %d."
                  ,     __FUNCTION__, outlet);
                  return (S_ACCESS);
            }

            if (*state != OUTLET_ON)
                  bad_outlets++;
           }
           
           if (bad_outlets == 0)
            return (S_OK);
    }
    
    if (bad_outlets == num_outlets) {
          /* reset failed */
          LOG(PIL_CRIT, "%s: resetting host '%s' failed."
          , __FUNCTION__, host);
          return (S_RESETFAIL);
    } else {
          /* Not all outlets back on, but at least one; implies node was */
          /* rebooted correctly */
          LOG(PIL_WARN,"%s: Not all outlets came back online!"
          , __FUNCTION__);
          return (S_OK); 
    }
}

/*
 * Get the configuration parameter names.
 */

static const char **
apcmastersnmp_get_confignames(StonithPlugin * s)
{
      static const char * ret[] = {ST_IPADDR, ST_PORT, ST_COMMUNITY, NULL};
      return ret;
}

/*
 * Set the configuration parameters.
 */

static int
apcmastersnmp_set_config(StonithPlugin * s, StonithNVpair * list)
{
      struct pluginDevice* sd = (struct pluginDevice *)s;
      int   rc;
      int * i;
      StonithNamesToGet namestocopy [] =
      {     {ST_IPADDR, NULL}
      ,     {ST_PORT,   NULL}
      ,     {ST_COMMUNITY,    NULL}
      ,     {NULL,            NULL}
      };

      DEBUGCALL;
      ERRIFWRONGDEV(s,S_INVAL);
      if (sd->sp.isconfigured) {
            return S_OOPS;
      }

      if ((rc=OurImports->CopyAllValues(namestocopy, list)) != S_OK) {
            return rc;
      }
      sd->hostname = namestocopy[0].s_value;
      sd->port = atoi(namestocopy[1].s_value);
      PluginImports->mfree(namestocopy[1].s_value);
      sd->community = namestocopy[2].s_value;

        /* try to resolve the hostname/ip-address */
      if (gethostbyname(sd->hostname) != NULL) {
            /* init snmp library */
            init_snmp("apcmastersnmp");

            /* now try to get a snmp session */
            if ((sd->sptr = APC_open(sd->hostname, sd->port, sd->community)) != NULL) {

                  /* ok, get the number of outlets from the masterswitch */
                  if ((i = APC_read(sd->sptr, OID_NUM_OUTLETS, ASN_INTEGER))
                              == NULL) {
                        LOG(PIL_CRIT
                        , "%s: cannot read number of outlets."
                        ,       __FUNCTION__);
                        return (S_ACCESS);
                  }
                  /* store the number of outlets */
                  sd->num_outlets = *i;
                  if (Debug) {
                        LOG(PIL_DEBUG, "%s: number of outlets: %i."
                        ,       __FUNCTION__, sd->num_outlets );
                  }

                  /* Everything went well */
                  return (S_OK);
            }else{
                  LOG(PIL_CRIT, "%s: cannot create snmp session."
                  ,       __FUNCTION__);
            }
      }else{
            LOG(PIL_CRIT, "%s: cannot resolve hostname '%s', h_errno %d."
            ,       __FUNCTION__, sd->hostname, h_errno);
      }

      /* not a valid config */
      return (S_BADCONFIG);
}

/*
 * get info about the stonith device 
 */

static const char *
apcmastersnmp_getinfo(StonithPlugin * s, int reqtype)
{
    struct pluginDevice *ad;
    const char *ret = NULL;

    DEBUGCALL;

    ERRIFWRONGDEV(s, NULL);

    ad = (struct pluginDevice *) s;

    switch (reqtype) {
          case ST_DEVICEID:
            ret = ad->idinfo;
            break;

          case ST_DEVICENAME:
            ret = ad->hostname;
            break;

          case ST_DEVICEDESCR:
            ret = "APC MasterSwitch (via SNMP)\n"
                  "The APC MasterSwitch can accept multiple simultaneous SNMP clients";
            break;

          case ST_DEVICEURL:
            ret = "http://www.apc.com/";
            break;

          case ST_CONF_XML:         /* XML metadata */
            ret = apcmastersnmpXML;
            break;

      }
      return ret;
}


/*
 * APC StonithPlugin destructor... 
 */

static void
apcmastersnmp_destroy(StonithPlugin * s)
{
      struct pluginDevice *ad;

      DEBUGCALL;

      VOIDERRIFWRONGDEV(s);

      ad = (struct pluginDevice *) s;

      ad->pluginid = NOTpluginID;

      /* release snmp session */
      if (ad->sptr != NULL) {
            snmp_close(ad->sptr);
            ad->sptr = NULL;
      }

      /* reset defaults */
      if (ad->hostname != NULL) {
            PluginImports->mfree(ad->hostname);
            ad->hostname = NULL;
      }
      if (ad->community != NULL) {
            PluginImports->mfree(ad->community);
            ad->community = NULL;
      }
      ad->num_outlets = 0;

      PluginImports->mfree(ad);
}

/*
 * Create a new APC StonithPlugin device.  Too bad this function can't be
 * static 
 */

static StonithPlugin *
apcmastersnmp_new(const char *subplugin)
{
      struct pluginDevice *ad = MALLOCT(struct pluginDevice);

      DEBUGCALL;

      /* no memory for stonith-object */
      if (ad == NULL) {
            LOG(PIL_CRIT, "%s: out of memory.", __FUNCTION__);
            return (NULL);
      }

      /* clear stonith-object */
      memset(ad, 0, sizeof(*ad));

      /* set defaults */
      ad->pluginid = pluginid;
      ad->sptr = NULL;
      ad->hostname = NULL;
      ad->community = NULL;
      ad->idinfo = DEVICE;
      ad->sp.s_ops = &apcmastersnmpOps;

      /* return the object */
      return (&(ad->sp));
}

Generated by  Doxygen 1.6.0   Back to index