diff options
Diffstat (limited to 'xlators/mgmt/glusterd/src/glusterd-ganesha.c')
-rw-r--r-- | xlators/mgmt/glusterd/src/glusterd-ganesha.c | 907 |
1 files changed, 907 insertions, 0 deletions
diff --git a/xlators/mgmt/glusterd/src/glusterd-ganesha.c b/xlators/mgmt/glusterd/src/glusterd-ganesha.c new file mode 100644 index 00000000000..0a16925c19b --- /dev/null +++ b/xlators/mgmt/glusterd/src/glusterd-ganesha.c @@ -0,0 +1,907 @@ +/* + 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; +} |