/*
Copyright (c) 2015 Red Hat, Inc. <http://www.redhat.com>
This file is part of GlusterFS.
This file is licensed to you under your choice of the GNU Lesser
General Public License, version 3 or any later version (LGPLv3 or
later), or the GNU General Public License, version 2 (GPLv2), in all
cases as published by the Free Software Foundation.
*/
#include <glusterfs/common-utils.h>
#include "glusterd.h"
#include "glusterd-op-sm.h"
#include "glusterd-store.h"
#include "glusterd-utils.h"
#include "glusterd-nfs-svc.h"
#include "glusterd-volgen.h"
#include "glusterd-messages.h"
#include <glusterfs/syscall.h>
#include <ctype.h>
int
start_ganesha(char **op_errstr);
typedef struct service_command {
char *binary;
char *service;
int (*action)(struct service_command *, char *);
} service_command;
/* parsing_ganesha_ha_conf will allocate the returned string
* to be freed (GF_FREE) by the caller
* return NULL if error or not found */
static char *
parsing_ganesha_ha_conf(const char *key)
{
#define MAX_LINE 1024
char scratch[MAX_LINE * 2] = {
0,
};
char *value = NULL, *pointer = NULL, *end_pointer = NULL;
FILE *fp;
fp = fopen(GANESHA_HA_CONF, "r");
if (fp == NULL) {
gf_msg(THIS->name, GF_LOG_ERROR, errno, GD_MSG_FILE_OP_FAILED,
"couldn't open the file %s", GANESHA_HA_CONF);
goto end_ret;
}
while ((pointer = fgets(scratch, MAX_LINE, fp)) != NULL) {
/* Read config file until we get matching "^[[:space:]]*key" */
if (*pointer == '#') {
continue;
}
while (isblank(*pointer)) {
pointer++;
}
if (strncmp(pointer, key, strlen(key))) {
continue;
}
pointer += strlen(key);
/* key found : if we fail to parse, we'll return an error
* rather than trying next one
* - supposition : conf file is bash compatible : no space
* around the '=' */
if (*pointer != '=') {
gf_msg(THIS->name, GF_LOG_ERROR, errno,
GD_MSG_GET_CONFIG_INFO_FAILED, "Parsing %s failed at key %s",
GANESHA_HA_CONF, key);
goto end_close;
}
pointer++; /* jump the '=' */
if (*pointer == '"' || *pointer == '\'') {
/* dont get the quote */
pointer++;
}
end_pointer = pointer;
/* stop at the next closing quote or blank/newline */
do {
end_pointer++;
} while (!(*end_pointer == '\'' || *end_pointer == '"' ||
isspace(*end_pointer) || *end_pointer == '\0'));
*end_pointer = '\0';
/* got it. copy it and return */
value = gf_strdup(pointer);
break;
}
end_close:
fclose(fp);
end_ret:
return value;
}
static int
sc_systemctl_action(struct service_command *sc, char *command)
{
runner_t runner = {
0,
};
runinit(&runner);
runner_add_args(&runner, sc->binary, command, sc->service, NULL);
return runner_run(&runner);
}
static int
sc_service_action(struct service_command *sc, char *command)
{
runner_t runner = {
0,
};
runinit(&runner);
runner_add_args(&runner, sc->binary, sc->service, command, NULL);
return runner_run(&runner);
}
static int
manage_service(char *action)
{
int i = 0;
int ret = 0;
struct service_command sc_list[] = {{.binary = "/bin/systemctl",
.service = "nfs-ganesha",
.action = sc_systemctl_action},
{.binary = "/sbin/invoke-rc.d",
.service = "nfs-ganesha",
.action = sc_service_action},
{.binary = "/sbin/service",
.service = "nfs-ganesha",
.action = sc_service_action},
{.binary = NULL}};
while (sc_list[i].binary != NULL) {
ret = sys_access(sc_list[i].binary, X_OK);
if (ret == 0) {
gf_msg_debug(THIS->name, 0, "%s found.", sc_list[i].binary);
return sc_list[i].action(&sc_list[i], action);
}
i++;
}
gf_msg(THIS->name, GF_LOG_ERROR, 0, GD_MSG_UNRECOGNIZED_SVC_MNGR,
"Could not %s NFS-Ganesha.Service manager for distro"
" not recognized.",
action);
return ret;
}
/*
* Check if the cluster is a ganesha cluster or not *
*/
gf_boolean_t
glusterd_is_ganesha_cluster()
{
int ret = -1;
glusterd_conf_t *priv = NULL;
xlator_t *this = NULL;
gf_boolean_t ret_bool = _gf_false;
this = THIS;
GF_VALIDATE_OR_GOTO("ganesha", this, out);
priv = this->private;
GF_VALIDATE_OR_GOTO(this->name, priv, out);
ret = dict_get_str_boolean(priv->opts, GLUSTERD_STORE_KEY_GANESHA_GLOBAL,
_gf_false);
if (ret == _gf_true) {
ret_bool = _gf_true;
gf_msg_debug(this->name, 0, "nfs-ganesha is enabled for the cluster");
} else
gf_msg_debug(this->name, 0, "nfs-ganesha is disabled for the cluster");
out:
return ret_bool;
}
/* Check if ganesha.enable is set to 'on', that checks if
* a particular volume is exported via NFS-Ganesha */
gf_boolean_t
glusterd_check_ganesha_export(glusterd_volinfo_t *volinfo)
{
char *value = NULL;
gf_boolean_t is_exported = _gf_false;
int ret = 0;
ret = glusterd_volinfo_get(volinfo, "ganesha.enable", &value);
if ((ret == 0) && value) {
if (strcmp(value, "on") == 0) {
gf_msg_debug(THIS->name, 0,
"ganesha.enable set"
" to %s",
value);
is_exported = _gf_true;
}
}
return is_exported;
}
/* *
* The below function is called as part of commit phase for volume set option
* "ganesha.enable". If the value is "on", it creates export configuration file
* and then export the volume via dbus command. Incase of "off", the volume
* will be already unexported during stage phase, so it will remove the conf
* file from shared storage
*/
int
glusterd_check_ganesha_cmd(char *key, char *value, char **errstr, dict_t *dict)
{
int ret = 0;
char *volname = NULL;
GF_ASSERT(key);
GF_ASSERT(value);
GF_ASSERT(dict);
if ((strcmp(key, "ganesha.enable") == 0)) {
if ((strcmp(value, "on")) && (strcmp(value, "off"))) {
gf_asprintf(errstr,
"Invalid value"
" for volume set command. Use on/off only.");
ret = -1;
goto out;
}
if (strcmp(value, "on") == 0) {
ret = glusterd_handle_ganesha_op(dict, errstr, key, value);
} else if (is_origin_glusterd(dict)) {
ret = dict_get_str(dict, "volname", &volname);
if (ret) {
gf_msg("glusterd-ganesha", GF_LOG_ERROR, errno,
GD_MSG_DICT_GET_FAILED, "Unable to get volume name");
goto out;
}
ret = manage_export_config(volname, "off", errstr);
}
}
out:
if (ret) {
gf_msg("glusterd-ganesha", GF_LOG_ERROR, 0,
GD_MSG_NFS_GNS_OP_HANDLE_FAIL,
"Handling NFS-Ganesha"
" op failed.");
}
return ret;
}
int
glusterd_op_stage_set_ganesha(dict_t *dict, char **op_errstr)
{
int ret = -1;
char *value = NULL;
char *str = NULL;
glusterd_conf_t *priv = NULL;
xlator_t *this = NULL;
GF_ASSERT(dict);
this = THIS;
GF_ASSERT(this);
priv = this->private;
GF_ASSERT(priv);
ret = dict_get_str(dict, "value", &value);
if (value == NULL) {
gf_msg(this->name, GF_LOG_ERROR, errno, GD_MSG_DICT_GET_FAILED,
"value not present.");
goto out;
}
/* This dict_get will fail if the user had never set the key before */
/*Ignoring the ret value and proceeding */
ret = dict_get_str(priv->opts, GLUSTERD_STORE_KEY_GANESHA_GLOBAL, &str);
if (str ? strcmp(value, str) == 0 : strcmp(value, "disable") == 0) {
gf_asprintf(op_errstr, "nfs-ganesha is already %sd.", value);
ret = -1;
goto out;
}
if (strcmp(value, "enable") == 0) {
ret = start_ganesha(op_errstr);
if (ret) {
gf_msg(THIS->name, GF_LOG_ERROR, 0, GD_MSG_NFS_GNS_START_FAIL,
"Could not start NFS-Ganesha");
}
} else {
ret = stop_ganesha(op_errstr);
if (ret)
gf_msg_debug(THIS->name, 0,
"Could not stop "
"NFS-Ganesha.");
}
out:
if (ret) {
if (!(*op_errstr)) {
*op_errstr = gf_strdup("Error, Validation Failed");
gf_msg_debug(this->name, 0, "Error, Cannot Validate option :%s",
GLUSTERD_STORE_KEY_GANESHA_GLOBAL);
} else {
gf_msg_debug(this->name, 0, "Error, Cannot Validate option");
}
}
return ret;
}
int
glusterd_op_set_ganesha(dict_t *dict, char **errstr)
{
int ret = 0;
xlator_t *this = NULL;
glusterd_conf_t *priv = NULL;
char *key = NULL;
char *value = NULL;
char *next_version = NULL;
this = THIS;
GF_ASSERT(this);
GF_ASSERT(dict);
priv = this->private;
GF_ASSERT(priv);
ret = dict_get_str(dict, "key", &key);
if (ret) {
gf_msg(this->name, GF_LOG_ERROR, errno, GD_MSG_DICT_GET_FAILED,
"Couldn't get key in global option set");
goto out;
}
ret = dict_get_str(dict, "value", &value);
if (ret) {
gf_msg(this->name, GF_LOG_ERROR, errno, GD_MSG_DICT_GET_FAILED,
"Couldn't get value in global option set");
goto out;
}
ret = glusterd_handle_ganesha_op(dict, errstr, key, value);
if (ret) {
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_NFS_GNS_SETUP_FAIL,
"Initial NFS-Ganesha set up failed");
ret = -1;
goto out;
}
ret = dict_set_dynstr_with_alloc(priv->opts,
GLUSTERD_STORE_KEY_GANESHA_GLOBAL, value);
if (ret) {
gf_msg(this->name, GF_LOG_WARNING, errno, GD_MSG_DICT_SET_FAILED,
"Failed to set"
" nfs-ganesha in dict.");
goto out;
}
ret = glusterd_get_next_global_opt_version_str(priv->opts, &next_version);
if (ret) {
gf_msg_debug(THIS->name, 0,
"Could not fetch "
" global op version");
goto out;
}
ret = dict_set_str(priv->opts, GLUSTERD_GLOBAL_OPT_VERSION, next_version);
if (ret)
goto out;
ret = glusterd_store_options(this, priv->opts);
if (ret) {
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_STORE_FAIL,
"Failed to store options");
goto out;
}
out:
gf_msg_debug(this->name, 0, "returning %d", ret);
return ret;
}
/* Following function parse GANESHA_HA_CONF
* The sample file looks like below,
* HA_NAME="ganesha-ha-360"
* HA_VOL_NAME="ha-state"
* HA_CLUSTER_NODES="server1,server2"
* VIP_rhs_1="10.x.x.x"
* VIP_rhs_2="10.x.x.x." */
/* Check if the localhost is listed as one of nfs-ganesha nodes */
gf_boolean_t
check_host_list(void)
{
glusterd_conf_t *priv = NULL;
char *hostname, *hostlist;
gf_boolean_t ret = _gf_false;
xlator_t *this = NULL;
this = THIS;
priv = THIS->private;
GF_ASSERT(priv);
hostlist = parsing_ganesha_ha_conf("HA_CLUSTER_NODES");
if (hostlist == NULL) {
gf_msg(this->name, GF_LOG_INFO, errno, GD_MSG_GET_CONFIG_INFO_FAILED,
"couldn't get HA_CLUSTER_NODES from file %s", GANESHA_HA_CONF);
return _gf_false;
}
/* Hostlist is a comma separated list now */
hostname = strtok(hostlist, ",");
while (hostname != NULL) {
ret = gf_is_local_addr(hostname);
if (ret) {
gf_msg(this->name, GF_LOG_INFO, 0, GD_MSG_NFS_GNS_HOST_FOUND,
"ganesha host found "
"Hostname is %s",
hostname);
break;
}
hostname = strtok(NULL, ",");
}
GF_FREE(hostlist);
return ret;
}
int
manage_export_config(char *volname, char *value, char **op_errstr)
{
runner_t runner = {
0,
};
int ret = -1;
GF_ASSERT(volname);
runinit(&runner);
runner_add_args(&runner, GANESHA_PREFIX "/create-export-ganesha.sh",
CONFDIR, value, volname, NULL);
ret = runner_run(&runner);
if (ret && op_errstr)
gf_asprintf(op_errstr,
"Failed to create"
" NFS-Ganesha export config file.");
return ret;
}
/* Exports and unexports a particular volume via NFS-Ganesha */
int
ganesha_manage_export(dict_t *dict, char *value,
gf_boolean_t update_cache_invalidation, char **op_errstr)
{
runner_t runner = {
0,
};
int ret = -1;
glusterd_volinfo_t *volinfo = NULL;
dict_t *vol_opts = NULL;
char *volname = NULL;
xlator_t *this = NULL;
glusterd_conf_t *priv = NULL;
gf_boolean_t option = _gf_false;
runinit(&runner);
this = THIS;
GF_ASSERT(this);
priv = this->private;
GF_ASSERT(value);
GF_ASSERT(dict);
GF_ASSERT(priv);
ret = dict_get_str(dict, "volname", &volname);
if (ret) {
gf_msg(this->name, GF_LOG_ERROR, errno, GD_MSG_DICT_GET_FAILED,
"Unable to get volume name");
goto out;
}
ret = gf_string2boolean(value, &option);
if (ret == -1) {
gf_msg(this->name, GF_LOG_ERROR, EINVAL, GD_MSG_INVALID_ENTRY,
"invalid value.");
goto out;
}
ret = glusterd_volinfo_find(volname, &volinfo);
if (ret) {
gf_msg(this->name, GF_LOG_ERROR, EINVAL, GD_MSG_VOL_NOT_FOUND,
FMTSTR_CHECK_VOL_EXISTS, volname);
goto out;
}
ret = glusterd_check_ganesha_export(volinfo);
if (ret && option) {
gf_asprintf(op_errstr,
"ganesha.enable "
"is already 'on'.");
ret = -1;
goto out;
} else if (!option && !ret) {
gf_asprintf(op_errstr,
"ganesha.enable "
"is already 'off'.");
ret = -1;
goto out;
}
/* Check if global option is enabled, proceed only then */
ret = dict_get_str_boolean(priv->opts, GLUSTERD_STORE_KEY_GANESHA_GLOBAL,
_gf_false);
if (ret == -1) {
gf_msg_debug(this->name, 0,
"Failed to get "
"global option dict.");
gf_asprintf(op_errstr,
"The option "
"nfs-ganesha should be "
"enabled before setting ganesha.enable.");
goto out;
}
if (!ret) {
gf_asprintf(op_errstr,
"The option "
"nfs-ganesha should be "
"enabled before setting ganesha.enable.");
ret = -1;
goto out;
}
/* *
* Create the export file from the node where ganesha.enable "on"
* is executed
* */
if (option && is_origin_glusterd(dict)) {
ret = manage_export_config(volname, "on", op_errstr);
if (ret) {
gf_msg(this->name, GF_LOG_ERROR, 0, GD_MSG_EXPORT_FILE_CREATE_FAIL,
"Failed to create"
"export file for NFS-Ganesha\n");
goto out;
}
}
if (check_host_list()) {
/* Check whether ganesha is running on this node */
if (manage_service("status")) {
gf_msg(this->name, GF_LOG_WARNING, 0, GD_MSG_GANESHA_NOT_RUNNING,
"Export failed, NFS-Ganesha is not running");
} else {
runner_add_args(&runner, GANESHA_PREFIX "/dbus-send.sh", CONFDIR,
value, volname, NULL);
ret = runner_run(&runner);
if (ret) {
gf_asprintf(op_errstr,
"Dynamic export"
" addition/deletion failed."
" Please see log file for details");
goto out;
}
}
}
if (update_cache_invalidation) {
vol_opts = volinfo->dict;
ret = dict_set_dynstr_with_alloc(vol_opts,
"features.cache-invalidation", value);
if (ret)
gf_asprintf(op_errstr,
"Cache-invalidation could not"
" be set to %s.",
value);
ret = glusterd_store_volinfo(volinfo,
GLUSTERD_VOLINFO_VER_AC_INCREMENT);
if (ret)
gf_asprintf(op_errstr, "failed to store volinfo for %s",
volinfo->volname);
}
out:
return ret;
}
int
tear_down_cluster(gf_boolean_t run_teardown)
{
int ret = 0;
runner_t runner = {
0,
};
struct stat st = {
0,
};
DIR *dir = NULL;
struct dirent *entry = NULL;
struct dirent scratch[2] = {
{
0,
},
};
char path[PATH_MAX] = {
0,
};
if (run_teardown) {
runinit(&runner);
runner_add_args(&runner, GANESHA_PREFIX "/ganesha-ha.sh", "teardown",
CONFDIR, NULL);
ret = runner_run(&runner);
/* *
* Remove all the entries in CONFDIR expect ganesha.conf and
* ganesha-ha.conf
*/
dir = sys_opendir(CONFDIR);
if (!dir) {
gf_msg_debug(THIS->name, 0,
"Failed to open directory %s. "
"Reason : %s",
CONFDIR, strerror(errno));
ret = 0;
goto out;
}
GF_SKIP_IRRELEVANT_ENTRIES(entry, dir, scratch);
while (entry) {
snprintf(path, PATH_MAX, "%s/%s", CONFDIR, entry->d_name);
ret = sys_lstat(path, &st);
if (ret == -1) {
gf_msg_debug(THIS->name, 0,
"Failed to stat entry %s :"
" %s",
path, strerror(errno));
goto out;
}
if (strcmp(entry->d_name, "ganesha.conf") == 0 ||
strcmp(entry->d_name, "ganesha-ha.conf") == 0)
gf_msg_debug(THIS->name, 0,
" %s is not required"
" to remove",
path);
else if (S_ISDIR(st.st_mode))
ret = recursive_rmdir(path);
else
ret = sys_unlink(path);
if (ret) {
gf_msg_debug(THIS->name, 0,
" Failed to remove %s. "
"Reason : %s",
path, strerror(errno));
}
gf_msg_debug(THIS->name, 0, "%s %s",
ret ? "Failed to remove" : "Removed", entry->d_name);
GF_SKIP_IRRELEVANT_ENTRIES(entry, dir, scratch);
}
ret = sys_closedir(dir);
if (ret) {
gf_msg_debug(THIS->name, 0,
"Failed to close dir %s. Reason :"
" %s",
CONFDIR, strerror(errno));
}
}
out:
return ret;
}
int
setup_cluster(gf_boolean_t run_setup)
{
int ret = 0;
runner_t runner = {
0,
};
if (run_setup) {
runinit(&runner);
runner_add_args(&runner, GANESHA_PREFIX "/ganesha-ha.sh", "setup",
CONFDIR, NULL);
ret = runner_run(&runner);
}
return ret;
}
static int
teardown(gf_boolean_t run_teardown, char **op_errstr)
{
runner_t runner = {
0,
};
int ret = 1;
glusterd_volinfo_t *volinfo = NULL;
glusterd_conf_t *priv = NULL;
dict_t *vol_opts = NULL;
priv = THIS->private;
ret = tear_down_cluster(run_teardown);
if (ret == -1) {
gf_asprintf(op_errstr,
"Cleanup of NFS-Ganesha"
" HA config failed.");
goto out;
}
runinit(&runner);
runner_add_args(&runner, GANESHA_PREFIX "/ganesha-ha.sh", "cleanup",
CONFDIR, NULL);
ret = runner_run(&runner);
if (ret)
gf_msg_debug(THIS->name, 0,
"Could not clean up"
" NFS-Ganesha related config");
cds_list_for_each_entry(volinfo, &priv->volumes, vol_list)
{
vol_opts = volinfo->dict;
/* All the volumes exported via NFS-Ganesha will be
unexported, hence setting the appropriate keys */
ret = dict_set_str(vol_opts, "features.cache-invalidation", "off");
if (ret)
gf_msg(THIS->name, GF_LOG_WARNING, errno, GD_MSG_DICT_SET_FAILED,
"Could not set features.cache-invalidation "
"to off for %s",
volinfo->volname);
ret = dict_set_str(vol_opts, "ganesha.enable", "off");
if (ret)
gf_msg(THIS->name, GF_LOG_WARNING, errno, GD_MSG_DICT_SET_FAILED,
"Could not set ganesha.enable to off for %s",
volinfo->volname);
ret = glusterd_store_volinfo(volinfo,
GLUSTERD_VOLINFO_VER_AC_INCREMENT);
if (ret)
gf_msg(THIS->name, GF_LOG_WARNING, 0, GD_MSG_VOLINFO_SET_FAIL,
"failed to store volinfo for %s", volinfo->volname);
}
out:
return ret;
}
int
stop_ganesha(char **op_errstr)
{
int ret = 0;
runner_t runner = {
0,
};
if (check_host_list()) {
runinit(&runner);
runner_add_args(&runner, GANESHA_PREFIX "/ganesha-ha.sh",
"--setup-ganesha-conf-files", CONFDIR, "no", NULL);
ret = runner_run(&runner);
if (ret) {
gf_asprintf(op_errstr,
"removal of symlink ganesha.conf "
"in /etc/ganesha failed");
}
ret = manage_service("stop");
if (ret)
gf_asprintf(op_errstr,
"NFS-Ganesha service could not"
"be stopped.");
}
return ret;
}
int
start_ganesha(char **op_errstr)
{
int ret = -1;
dict_t *vol_opts = NULL;
glusterd_volinfo_t *volinfo = NULL;
glusterd_conf_t *priv = NULL;
runner_t runner = {
0,
};
priv = THIS->private;
GF_ASSERT(priv);
cds_list_for_each_entry(volinfo, &priv->volumes, vol_list)
{
vol_opts = volinfo->dict;
/* Gluster-nfs has to be disabled across the trusted pool */
/* before attempting to start nfs-ganesha */
ret = dict_set_str(vol_opts, NFS_DISABLE_MAP_KEY, "on");
if (ret)
goto out;
ret = glusterd_store_volinfo(volinfo,
GLUSTERD_VOLINFO_VER_AC_INCREMENT);
if (ret) {
*op_errstr = gf_strdup(
"Failed to store the "
"Volume information");
goto out;
}
}
/* If the nfs svc is not initialized it means that the service is not
* running, hence we can skip the process of stopping gluster-nfs
* service
*/
if (priv->nfs_svc.inited) {
ret = priv->nfs_svc.stop(&(priv->nfs_svc), SIGKILL);
if (ret) {
ret = -1;
gf_asprintf(op_errstr,
"Gluster-NFS service could"
"not be stopped, exiting.");
goto out;
}
}
if (check_host_list()) {
runinit(&runner);
runner_add_args(&runner, GANESHA_PREFIX "/ganesha-ha.sh",
"--setup-ganesha-conf-files", CONFDIR, "yes", NULL);
ret = runner_run(&runner);
if (ret) {
gf_asprintf(op_errstr,
"creation of symlink ganesha.conf "
"in /etc/ganesha failed");
goto out;
}
ret = manage_service("start");
if (ret)
gf_asprintf(op_errstr,
"NFS-Ganesha failed to start."
"Please see log file for details");
}
out:
return ret;
}
static int
pre_setup(gf_boolean_t run_setup, char **op_errstr)
{
int ret = 0;
if (run_setup) {
if (!check_host_list()) {
gf_asprintf(op_errstr,
"Running nfs-ganesha setup command "
"from node which is not part of ganesha cluster");
return -1;
}
}
ret = setup_cluster(run_setup);
if (ret == -1)
gf_asprintf(op_errstr,
"Failed to set up HA "
"config for NFS-Ganesha. "
"Please check the log file for details");
return ret;
}
int
glusterd_handle_ganesha_op(dict_t *dict, char **op_errstr, char *key,
char *value)
{
int32_t ret = -1;
gf_boolean_t option = _gf_false;
GF_ASSERT(dict);
GF_ASSERT(op_errstr);
GF_ASSERT(key);
GF_ASSERT(value);
if (strcmp(key, "ganesha.enable") == 0) {
ret = ganesha_manage_export(dict, value, _gf_true, op_errstr);
if (ret < 0)
goto out;
}
/* It is possible that the key might not be set */
ret = gf_string2boolean(value, &option);
if (ret == -1) {
gf_asprintf(op_errstr, "Invalid value in key-value pair.");
goto out;
}
if (strcmp(key, GLUSTERD_STORE_KEY_GANESHA_GLOBAL) == 0) {
/* *
* The set up/teardown of pcs cluster should be performed only
* once. This will done on the node in which the cli command
* 'gluster nfs-ganesha <enable/disable>' got executed. So that
* node should part of ganesha HA cluster
*/
if (option) {
ret = pre_setup(is_origin_glusterd(dict), op_errstr);
if (ret < 0)
goto out;
} else {
ret = teardown(is_origin_glusterd(dict), op_errstr);
if (ret < 0)
goto out;
}
}
out:
return ret;
}