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.
heartbeat/cim/cluster_provider.c

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);