mirror of https://github.com/sipwise/heartbeat.git
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
513 lines
15 KiB
513 lines
15 KiB
/*
|
|
* cluster_provider.c: HA_Cluster provider
|
|
*
|
|
* Author: Jia Ming Pan <jmltc@cn.ibm.com>
|
|
* Copyright (c) 2005 International Business Machines
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program 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 General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
|
*
|
|
*/
|
|
|
|
#include <lha_internal.h>
|
|
#include <unistd.h>
|
|
#include <stdlib.h>
|
|
#include <stdio.h>
|
|
#include <string.h>
|
|
#include <sys/stat.h>
|
|
#include <sys/types.h>
|
|
#include <cmpidt.h>
|
|
#include <cmpift.h>
|
|
#include <cmpimacs.h>
|
|
#include <hb_api.h>
|
|
#include <clplumbing/cl_malloc.h>
|
|
#include "cmpi_utils.h"
|
|
#include "cluster_info.h"
|
|
#include "utils.h"
|
|
|
|
static const char * PROVIDER_ID = "cim-hb";
|
|
static CMPIBroker * Broker = NULL;
|
|
static char ClassName [] = "HA_Cluster";
|
|
static char InstName [] = "LinuxHACluster";
|
|
static char Caption [] = "LinuxHA Cluster";
|
|
|
|
/* auth map */
|
|
uint32_t auth_valuemap [] = {0, 1, 2};
|
|
const char * auth_values [] = {"sha1", "md5", "crc"};
|
|
static uint32_t last_requested_state = 5; /* Not Changed */
|
|
|
|
static CMPIInstance * make_cluster_instance(CMPIObjectPath * op,
|
|
CMPIStatus * rc);
|
|
|
|
static int cluster_get_inst(CMPIContext * ctx, CMPIResult * rslt,
|
|
CMPIObjectPath * cop, CMPIStatus * rc);
|
|
|
|
static int cluster_enum_insts(CMPIContext * ctx, CMPIResult * rslt,
|
|
CMPIObjectPath * cop, char ** properties,
|
|
int enum_inst, CMPIStatus * rc);
|
|
|
|
static int auth_value2map(const char * method);
|
|
static const char * auth_map2value(uint32_t map);
|
|
|
|
static void config_set_instance(CMPIInstance * ci, CMPIStatus * rc);
|
|
static void auth_set_instance(CMPIInstance * ci, CMPIStatus * rc);
|
|
static void crm_set_instance(CMPIInstance * ci, CMPIStatus * rc);
|
|
|
|
/* set instance */
|
|
|
|
static int cluster_update_inst(CMPIContext* ctx, CMPIResult* rslt,
|
|
CMPIObjectPath*, CMPIInstance*, CMPIStatus*);
|
|
static int request_state_change(int state);
|
|
static int cleanup_cluster(void);
|
|
|
|
DeclareInstanceFunctions(Cluster);
|
|
|
|
static int
|
|
auth_value2map(const char * method)
|
|
{
|
|
int i;
|
|
for (i = 0; i < sizeof(auth_valuemap)/sizeof(uint32_t); i++) {
|
|
if ( strcmp(auth_values[i], method) == 0) {
|
|
return auth_valuemap[i];
|
|
}
|
|
}
|
|
return -1;
|
|
}
|
|
|
|
static const char *
|
|
auth_map2value(uint32_t map)
|
|
{
|
|
int i;
|
|
for (i = 0; i < sizeof(auth_valuemap)/sizeof(uint32_t); i++) {
|
|
if ( map == auth_valuemap[i] ) {
|
|
return auth_values[i];
|
|
}
|
|
}
|
|
return NULL;
|
|
}
|
|
|
|
static void
|
|
config_set_instance(CMPIInstance * ci, CMPIStatus * rc)
|
|
{
|
|
struct ha_msg * info;
|
|
|
|
DEBUG_ENTER();
|
|
/* get cluster config values */
|
|
info = cim_get_hacf_config ();
|
|
if ( info == NULL ) {
|
|
cl_log(LOG_ERR, "%s:can not get cluster.", __FUNCTION__);
|
|
return;
|
|
}
|
|
cmpi_msg2inst(Broker, ci, HA_CLUSTER, info, rc);
|
|
DEBUG_LEAVE();
|
|
ha_msg_del(info);
|
|
}
|
|
|
|
static void
|
|
auth_set_instance(CMPIInstance * ci, CMPIStatus * rc)
|
|
{
|
|
int num;
|
|
char* method;
|
|
char* key;
|
|
struct ha_msg *msg;
|
|
|
|
DEBUG_ENTER();
|
|
if ( (msg = cim_get_authkeys()) == NULL ){
|
|
cl_log(LOG_WARNING, "Can not get auth message");
|
|
return;
|
|
}
|
|
|
|
method = cim_strdup(cl_get_string(msg, "authmethod"));
|
|
key = cim_strdup(cl_get_string(msg, "authkey"));
|
|
|
|
num = auth_value2map(method);
|
|
CMSetProperty(ci, "AuthMethod", &num, CMPI_uint32);
|
|
CMSetProperty(ci, "AuthKey", key, CMPI_chars);
|
|
|
|
DEBUG_LEAVE();
|
|
ha_msg_del(msg);
|
|
}
|
|
|
|
static void
|
|
crm_set_instance(CMPIInstance * ci, CMPIStatus * rc)
|
|
{
|
|
char * it, * sc, * se;
|
|
char * nq, * rs, * hq;
|
|
struct ha_msg *msg;
|
|
|
|
if (( msg = cim_query_dispatch(GET_CRM_CONFIG, NULL, NULL)) == NULL ){
|
|
return;
|
|
}
|
|
|
|
it = cim_strdup(cl_get_string(msg, "transition_idle_timeout"));
|
|
sc = cim_strdup(cl_get_string(msg, "symmetric_cluster"));
|
|
se = cim_strdup(cl_get_string(msg, "stonith_enabled"));
|
|
nq = cim_strdup(cl_get_string(msg, "no_quorum_policy"));
|
|
rs = cim_strdup(cl_get_string(msg, "default_resource_stickiness"));
|
|
hq = cim_strdup(cl_get_string(msg, "have_quorum"));
|
|
|
|
if (it && sc && se && nq && rs && hq) {
|
|
CMSetProperty(ci, "TransitionIdleTimeout", it, CMPI_chars);
|
|
CMSetProperty(ci, "SymmetricCluster", sc, CMPI_chars);
|
|
CMSetProperty(ci, "StonithEnabled", se, CMPI_chars);
|
|
CMSetProperty(ci, "NoQuorumPolicy", nq, CMPI_chars);
|
|
CMSetProperty(ci, "DefaultResourceStickiness", rs, CMPI_chars);
|
|
CMSetProperty(ci, "HaveQuorum", hq, CMPI_chars);
|
|
}
|
|
|
|
ha_msg_del(msg);
|
|
}
|
|
|
|
/* always only one cluster instance */
|
|
static CMPIInstance *
|
|
make_cluster_instance(CMPIObjectPath * op, CMPIStatus * rc)
|
|
{
|
|
CMPIInstance *ci = NULL;
|
|
uint32_t state = 0;
|
|
struct ha_msg *msg;
|
|
|
|
DEBUG_ENTER();
|
|
ci = CMNewInstance(Broker, op, rc);
|
|
if ( CMIsNullObject(ci) ) {
|
|
cl_log(LOG_ERR, "%s: couldn't create instance", __FUNCTION__);
|
|
CMSetStatusWithChars(Broker, rc,
|
|
CMPI_RC_ERR_FAILED, "Could not create instance.");
|
|
return NULL;
|
|
}
|
|
|
|
CMSetProperty(ci, "CreationClassName", ClassName, CMPI_chars);
|
|
CMSetProperty(ci, "Name", InstName, CMPI_chars);
|
|
CMSetProperty(ci, "Caption", Caption, CMPI_chars);
|
|
|
|
/* set config properties */
|
|
config_set_instance(ci, rc);
|
|
|
|
/* set auth properties */
|
|
auth_set_instance(ci, rc);
|
|
|
|
state = 3; /* Disabled */
|
|
if( cim_get_hb_status() == HB_RUNNING) {
|
|
state = 2; /* Enabled */
|
|
/* set crm properties */
|
|
crm_set_instance(ci, rc);
|
|
}
|
|
|
|
CMSetProperty(ci, "EnabledState", &state, CMPI_uint32);
|
|
CMSetProperty(ci, "RequestedState", &last_requested_state, CMPI_uint32);
|
|
|
|
if ( (msg = cim_get_software_identity() )){
|
|
char * hv;
|
|
hv = cim_strdup(cl_get_string(msg, "hbversion"));
|
|
if (hv) {
|
|
CMSetProperty(ci, "HBVersion", hv, CMPI_chars);
|
|
}
|
|
cim_free(hv);
|
|
}
|
|
DEBUG_LEAVE();
|
|
return ci;
|
|
}
|
|
|
|
/* get a cluster instance */
|
|
static int
|
|
cluster_get_inst(CMPIContext * ctx, CMPIResult * rslt,
|
|
CMPIObjectPath * cop, CMPIStatus * rc)
|
|
{
|
|
CMPIObjectPath * op = NULL;
|
|
CMPIString * cmpi_namespace = NULL;
|
|
char * namespace = NULL;
|
|
CMPIInstance * ci = NULL;
|
|
int ret = 0;
|
|
|
|
cmpi_namespace = CMGetNameSpace(cop, rc);
|
|
namespace = CMGetCharPtr(cmpi_namespace);
|
|
|
|
op = CMNewObjectPath(Broker, namespace, ClassName, rc);
|
|
if ( CMIsNullObject(op) ){
|
|
ret = HA_FAIL;
|
|
CMSetStatusWithChars(Broker, rc,
|
|
CMPI_RC_ERR_FAILED, "Create object path failed");
|
|
goto out;
|
|
}
|
|
/* make a cluster instance */
|
|
ci = make_cluster_instance(op, rc);
|
|
if ( CMIsNullObject(ci) ) {
|
|
ret = HA_FAIL;
|
|
goto out;
|
|
}
|
|
|
|
/* return the instance */
|
|
CMReturnInstance(rslt, ci);
|
|
CMReturnDone(rslt);
|
|
ret = HA_OK;
|
|
out:
|
|
return ret;
|
|
}
|
|
|
|
/* enumerate cluster instances or instance names */
|
|
static int
|
|
cluster_enum_insts(CMPIContext * ctx, CMPIResult * rslt, CMPIObjectPath * cop,
|
|
char ** properties, int enum_inst, CMPIStatus * rc)
|
|
{
|
|
CMPIInstance * ci = NULL;
|
|
CMPIObjectPath * op = NULL;
|
|
CMPIString * cmpi_namespace = NULL;
|
|
char * namespace = NULL;
|
|
int ret = 0;
|
|
|
|
cmpi_namespace = CMGetNameSpace(cop, rc);
|
|
namespace = CMGetCharPtr(cmpi_namespace);
|
|
|
|
op = CMNewObjectPath(Broker, namespace, ClassName, rc);
|
|
if ( CMIsNullObject(op) ){
|
|
CMSetStatusWithChars(Broker, rc,
|
|
CMPI_RC_ERR_FAILED, "Create object path failed");
|
|
ret = HA_FAIL;
|
|
goto out;
|
|
}
|
|
|
|
if ( ! enum_inst ) {
|
|
/* enumerate instance names */
|
|
CMAddKey(op, "CreationClassName", ClassName, CMPI_chars);
|
|
CMAddKey(op, "Name", InstName, CMPI_chars);
|
|
CMReturnObjectPath(rslt, op);
|
|
|
|
} else {
|
|
/* enumerate instances */
|
|
ci = make_cluster_instance(op, rc);
|
|
if ( CMIsNullObject(ci) ) {
|
|
ret = HA_FAIL;
|
|
goto out;
|
|
}
|
|
CMReturnInstance(rslt, ci);
|
|
}
|
|
|
|
CMReturnDone(rslt);
|
|
ret = HA_OK;
|
|
out:
|
|
return ret;
|
|
}
|
|
|
|
/* update cluster instance, this will result in modification to the
|
|
ha.cf and authkeys */
|
|
static int
|
|
cluster_update_inst(CMPIContext * ctx, CMPIResult * rslt,
|
|
CMPIObjectPath * op, CMPIInstance * inst,
|
|
CMPIStatus * rc)
|
|
{
|
|
int ret, authnum;
|
|
const char *authkey, *authmethod;
|
|
struct ha_msg *cfginfo, *authinfo;
|
|
|
|
/* ha.cf */
|
|
if((cfginfo = cim_get_hacf_config()) == NULL ) {
|
|
/* ha.cf not exist yet */
|
|
if ((cfginfo = ha_msg_new(16)) == NULL ) {
|
|
return HA_FAIL;
|
|
}
|
|
}
|
|
|
|
ret = cmpi_inst2msg(inst, HA_CLUSTER, cfginfo, rc);
|
|
|
|
/* update the ha.cf file */
|
|
ret = cim_update_hacf(cfginfo);
|
|
ha_msg_del(cfginfo);
|
|
|
|
/* authkeys */
|
|
if ( (authinfo = cim_get_authkeys()) == NULL ) {
|
|
if ((authinfo = ha_msg_new(2)) == NULL ) {
|
|
return HA_FAIL;
|
|
}
|
|
}
|
|
|
|
authnum = CMGetProperty(inst, "AuthMethod", rc).value.uint32;
|
|
if ( rc->rc == CMPI_RC_OK ) {
|
|
authmethod = auth_map2value(authnum);
|
|
cl_msg_modstring(authinfo, "authmethod", authmethod);
|
|
}
|
|
authkey = CMGetPropertyString(inst, "AuthKey", rc);
|
|
if ( authkey ) {
|
|
cl_msg_modstring(authinfo, "authkey", authkey);
|
|
}
|
|
|
|
/* update the authkeys file */
|
|
ret = cim_update_authkeys(authinfo);
|
|
ha_msg_del(authinfo);
|
|
return HA_OK;
|
|
}
|
|
|
|
/* clean up */
|
|
static int
|
|
cleanup_cluster ()
|
|
{
|
|
cl_log(LOG_INFO, "%s: clean up", __FUNCTION__);
|
|
return HA_OK;
|
|
}
|
|
|
|
|
|
/* use
|
|
2: Enabled, 3: Disabled, 10: Reboot
|
|
for hb start hb stop hb restart
|
|
*/
|
|
static int
|
|
request_state_change(int state)
|
|
{
|
|
int action [] = {0, 0, START_HB, STOP_HB, 0, /* 4 */
|
|
0, 0, 0, 0, 0, /* 9 */
|
|
0, RESTART_HB};
|
|
|
|
last_requested_state = state;
|
|
cim_change_hb_state(action[state]);
|
|
|
|
return HA_OK;
|
|
}
|
|
|
|
/**********************************************
|
|
* Instance Provider Interface
|
|
**********************************************/
|
|
|
|
static CMPIStatus
|
|
ClusterCleanup(CMPIInstanceMI * mi, CMPIContext * ctx)
|
|
{
|
|
cleanup_cluster();
|
|
CMReturn(CMPI_RC_OK);
|
|
}
|
|
|
|
static CMPIStatus
|
|
ClusterEnumInstanceNames(CMPIInstanceMI * mi, CMPIContext * ctx,
|
|
CMPIResult * rslt, CMPIObjectPath *ref)
|
|
{
|
|
CMPIStatus rc = {CMPI_RC_OK, NULL};
|
|
PROVIDER_INIT_LOGGER();
|
|
/* enumerate instance names */
|
|
cluster_enum_insts(ctx, rslt, ref, NULL, FALSE, &rc);
|
|
return rc;
|
|
}
|
|
|
|
static CMPIStatus
|
|
ClusterEnumInstances(CMPIInstanceMI * mi, CMPIContext * ctx, CMPIResult * rslt,
|
|
CMPIObjectPath* ref, char ** properties)
|
|
{
|
|
CMPIStatus rc = {CMPI_RC_OK, NULL};
|
|
PROVIDER_INIT_LOGGER();
|
|
cluster_enum_insts(ctx, rslt, ref, NULL, TRUE, &rc);
|
|
return rc;
|
|
}
|
|
|
|
static CMPIStatus
|
|
ClusterGetInstance(CMPIInstanceMI * mi, CMPIContext * ctx, CMPIResult * rslt,
|
|
CMPIObjectPath * cop, char ** properties)
|
|
{
|
|
CMPIStatus rc = {CMPI_RC_OK, NULL};
|
|
PROVIDER_INIT_LOGGER();
|
|
cluster_get_inst(ctx, rslt, cop, &rc);
|
|
return rc;
|
|
}
|
|
|
|
static CMPIStatus
|
|
ClusterCreateInstance(CMPIInstanceMI * mi, CMPIContext * ctx, CMPIResult * rslt,
|
|
CMPIObjectPath * cop, CMPIInstance * ci)
|
|
{
|
|
CMPIStatus rc = {CMPI_RC_OK, NULL};
|
|
|
|
PROVIDER_INIT_LOGGER();
|
|
if ( cim_get_hacf_config() ) {
|
|
cl_log(LOG_WARNING, "Only one instance is allowed.");
|
|
CMSetStatusWithChars(Broker, &rc,
|
|
CMPI_RC_ERR_FAILED, "Only one instance is allowed.");
|
|
} else {
|
|
cluster_update_inst(ctx, rslt, cop, ci, &rc);
|
|
CMReturn(CMPI_RC_OK);
|
|
}
|
|
return rc;
|
|
}
|
|
|
|
|
|
static CMPIStatus
|
|
ClusterSetInstance(CMPIInstanceMI * mi, CMPIContext * ctx, CMPIResult * rslt,
|
|
CMPIObjectPath * op, CMPIInstance * inst, char ** properties)
|
|
{
|
|
CMPIStatus rc = {CMPI_RC_OK, NULL};
|
|
/* initialize logger */
|
|
PROVIDER_INIT_LOGGER();
|
|
/* set instance */
|
|
cluster_update_inst(ctx, rslt, op, inst, &rc);
|
|
CMReturn(CMPI_RC_OK);
|
|
}
|
|
|
|
static CMPIStatus
|
|
ClusterDeleteInstance(CMPIInstanceMI * mi, CMPIContext * ctx,
|
|
CMPIResult * rslt, CMPIObjectPath * cop)
|
|
{
|
|
CMPIStatus rc = {CMPI_RC_OK, NULL};
|
|
CMSetStatusWithChars(Broker, &rc,
|
|
CMPI_RC_ERR_NOT_SUPPORTED, "CIM_ERR_NOT_SUPPORTED");
|
|
return rc;
|
|
}
|
|
|
|
static CMPIStatus
|
|
ClusterExecQuery(CMPIInstanceMI * mi, CMPIContext * ctx, CMPIResult * rslt,
|
|
CMPIObjectPath * ref, char * lang, char * query)
|
|
{
|
|
CMPIStatus rc = {CMPI_RC_OK, NULL};
|
|
CMSetStatusWithChars(Broker, &rc,
|
|
CMPI_RC_ERR_NOT_SUPPORTED, "CIM_ERR_NOT_SUPPORTED");
|
|
return rc;
|
|
}
|
|
|
|
|
|
/**************************************************
|
|
* Method Provider Interface
|
|
*************************************************/
|
|
static CMPIStatus
|
|
ClusterInvokeMethod(CMPIMethodMI * mi, CMPIContext * ctx, CMPIResult * rslt,
|
|
CMPIObjectPath * ref, const char * method_name,
|
|
CMPIArgs * in, CMPIArgs * out)
|
|
{
|
|
CMPIString * class_name = NULL;
|
|
CMPIStatus rc = {CMPI_RC_OK, NULL};
|
|
int ret;
|
|
|
|
class_name = CMGetClassName(ref, &rc);
|
|
|
|
if(strcasecmp(CMGetCharPtr(class_name), ClassName) == 0 &&
|
|
strcasecmp("RequestStateChange", method_name) == 0 ){
|
|
int state;
|
|
/* we ignore the TimeoutPeriod parameter */
|
|
state = CMGetArg(in, "RequestedState", &rc).value.uint32;
|
|
ret = request_state_change(state);
|
|
|
|
CMAddArg(out, "Job", NULL, CMPI_ref);
|
|
}
|
|
|
|
CMReturnData(rslt, &ret, CMPI_uint32);
|
|
CMReturnDone(rslt);
|
|
|
|
CMReturn(CMPI_RC_OK);
|
|
}
|
|
|
|
|
|
static CMPIStatus
|
|
ClusterMethodCleanup(CMPIMethodMI * mi, CMPIContext * ctx)
|
|
{
|
|
CMReturn(CMPI_RC_OK);
|
|
}
|
|
|
|
|
|
|
|
/*****************************************************
|
|
* install interface
|
|
****************************************************/
|
|
DeclareInstanceMI(Cluster, HA_ClusterProvider, Broker);
|
|
DeclareMethodMI(Cluster, HA_ClusterProvider, Broker);
|