Blob Blame History Raw
From 994b4f5337f9bba1b2ca966d52d78983fd4e32f0 Mon Sep 17 00:00:00 2001
From: Samikshan Bairagya <samikshan@gmail.com>
Date: Fri, 23 Sep 2016 16:35:15 +0530
Subject: [PATCH 318/361] glusterd, cli: Get global options through volume get
 functionality

Currently it is not possible to retrieve values of global options
by using the 'gluster volume get' functionality if there are no
volumes present. In order to get the global options one has to use
'gluster volume get' with a specific volume name. This usage makes
the illusion as though the option is set only on one volume, which
is incorrect. When setting the global options, 'gluster volume set'
provides a way to set them using the volume name as 'all'.

Similarly, retrieving the global options should be made possible by
using the volume name 'all' with the 'gluster volume get'
functionality. This patch adds that functionality to 'volume get'

Usage:
	# gluster volume get all <OPTION/all>

mainline:
> BUG: 1378842
> Reviewed-on: http://review.gluster.org/15563
> Smoke: Gluster Build System <jenkins@build.gluster.org>
> NetBSD-regression: NetBSD Build System <jenkins@build.gluster.org>
> CentOS-regression: Gluster Build System <jenkins@build.gluster.org>
> Reviewed-by: Atin Mukherjee <amukherj@redhat.com>
(cherry picked from commit cef4fc694a6c5fd7e69f3780d43a590e67760af6)

BUG: 1433751
Change-Id: Ic2fdb9eda69d4806d432dae26d117d9660fe6d4e
Signed-off-by: Samikshan Bairagya <samikshan@gmail.com>
Reviewed-on: https://code.engineering.redhat.com/gerrit/101299
Tested-by: Milind Changire <mchangir@redhat.com>
Reviewed-by: Atin Mukherjee <amukherj@redhat.com>
---
 cli/src/cli-rpc-ops.c                        |   6 ++
 tests/bugs/cli/bug-1378842-volume-get-all.t  |  26 ++++++
 xlators/mgmt/glusterd/src/glusterd-handler.c |  39 +++++++++
 xlators/mgmt/glusterd/src/glusterd-op-sm.c   |  34 ++------
 xlators/mgmt/glusterd/src/glusterd-utils.c   | 120 +++++++++++++++++++++++++++
 xlators/mgmt/glusterd/src/glusterd-utils.h   |  36 ++++++++
 xlators/mgmt/glusterd/src/glusterd.h         |   1 +
 7 files changed, 233 insertions(+), 29 deletions(-)
 create mode 100644 tests/bugs/cli/bug-1378842-volume-get-all.t

diff --git a/cli/src/cli-rpc-ops.c b/cli/src/cli-rpc-ops.c
index 339d91b..cc395d7 100644
--- a/cli/src/cli-rpc-ops.c
+++ b/cli/src/cli-rpc-ops.c
@@ -11459,12 +11459,18 @@ gf_cli_get_vol_opt_cbk (struct rpc_req *req, struct iovec *iov, int count,
                 goto out;
         }
 
+        ret = dict_get_str (dict, "warning", &value);
+        if (!ret) {
+                cli_out ("%s", value);
+        }
+
         ret = dict_get_int32 (dict, "count", &count);
         if (ret) {
                 gf_log ("cli", GF_LOG_ERROR, "Failed to retrieve count "
                         "from the dictionary");
                 goto out;
         }
+
         if (count <= 0) {
                 gf_log ("cli", GF_LOG_ERROR, "Value of count :%d is "
                         "invalid", count);
diff --git a/tests/bugs/cli/bug-1378842-volume-get-all.t b/tests/bugs/cli/bug-1378842-volume-get-all.t
new file mode 100644
index 0000000..c798ce5
--- /dev/null
+++ b/tests/bugs/cli/bug-1378842-volume-get-all.t
@@ -0,0 +1,26 @@
+#!/bin/bash
+
+. $(dirname $0)/../../include.rc
+. $(dirname $0)/../../volume.rc
+
+cleanup;
+TEST glusterd
+TEST pidof glusterd
+
+TEST $CLI volume set all server-quorum-ratio 80
+
+# Execute volume get without having an explicit option, this should fail
+TEST ! $CLI volume get all
+
+# Also volume get on an option not applicable for all volumes should fail
+TEST ! $CLI volume get all cluster.tier-mode
+
+# Execute volume get with an explicit global option
+TEST $CLI volume get all server-quorum-ratio
+EXPECT '80' volume_get_field all 'cluster.server-quorum-ratio'
+
+# Execute volume get with 'all'
+TEST $CLI volume get all all
+
+cleanup;
+
diff --git a/xlators/mgmt/glusterd/src/glusterd-handler.c b/xlators/mgmt/glusterd/src/glusterd-handler.c
index 664fe5b..dbe69d5 100644
--- a/xlators/mgmt/glusterd/src/glusterd-handler.c
+++ b/xlators/mgmt/glusterd/src/glusterd-handler.c
@@ -4626,6 +4626,19 @@ glusterd_handle_barrier (rpcsvc_request_t *req)
         return glusterd_big_locked_handler (req, __glusterd_handle_barrier);
 }
 
+static gf_boolean_t
+gd_is_global_option (char *opt_key)
+{
+        GF_VALIDATE_OR_GOTO (THIS->name, opt_key, out);
+
+        return (strcmp (opt_key, GLUSTERD_SHARED_STORAGE_KEY) == 0 ||
+                strcmp (opt_key, GLUSTERD_QUORUM_RATIO_KEY) == 0 ||
+                strcmp (opt_key, GLUSTERD_GLOBAL_OP_VERSION_KEY) == 0);
+
+out:
+        return _gf_false;
+}
+
 int32_t
 glusterd_get_volume_opts (rpcsvc_request_t *req, dict_t *dict)
 {
@@ -4638,6 +4651,7 @@ glusterd_get_volume_opts (rpcsvc_request_t *req, dict_t *dict)
         char                      *volname = NULL;
         char                      *value = NULL;
         char                      err_str[2048] = {0,};
+        char                      warn_str[2048] = {0,};
         char                      dict_key[50] = {0,};
         xlator_t                  *this = NULL;
         glusterd_conf_t           *priv = NULL;
@@ -4663,6 +4677,12 @@ glusterd_get_volume_opts (rpcsvc_request_t *req, dict_t *dict)
                 goto out;
         }
 
+        if (strcasecmp (volname, "all") == 0) {
+                ret = glusterd_get_global_options_for_all_vols (dict,
+                                                                &rsp.op_errstr);
+                goto out;
+        }
+
         ret = dict_get_str (dict, "key", &key);
         if (ret) {
                 snprintf (err_str, sizeof (err_str), "Failed to get key "
@@ -4728,6 +4748,25 @@ glusterd_get_volume_opts (rpcsvc_request_t *req, dict_t *dict)
                                 orig_key = key;
                                 key = key_fixed;
                         }
+                        if (gd_is_global_option (key)) {
+                                snprintf (warn_str, sizeof (warn_str),
+                                          "Warning: Support to get "
+                                          "global option value using "
+                                          "`volume get <volname>` will be "
+                                          "deprecated from next release. "
+                                          "Consider using `volume get all` "
+                                          "instead for global options");
+
+                                ret = dict_set_str (dict, "warning", warn_str);
+                                if (ret) {
+                                        gf_msg (this->name, GF_LOG_ERROR,
+                                                0, GD_MSG_DICT_SET_FAILED,
+                                                "Failed to set warning "
+                                                "message in dictionary");
+                                        goto out;
+                                }
+                        }
+
                         if (strcmp (key, "cluster.op-version") == 0) {
                                 sprintf (dict_key, "key%d", count);
                                 ret = dict_set_str(dict, dict_key, key);
diff --git a/xlators/mgmt/glusterd/src/glusterd-op-sm.c b/xlators/mgmt/glusterd/src/glusterd-op-sm.c
index 9ebdb9e..7cc864d 100644
--- a/xlators/mgmt/glusterd/src/glusterd-op-sm.c
+++ b/xlators/mgmt/glusterd/src/glusterd-op-sm.c
@@ -63,38 +63,13 @@ glusterd_set_shared_storage (dict_t *dict, char *key, char *value,
  * all volumes, we can just add more entries to this *
  * table                                             *
  */
-glusterd_all_vol_opts   valid_all_vol_opts[] = {
+glusterd_all_vol_opts valid_all_vol_opts[] = {
         { GLUSTERD_QUORUM_RATIO_KEY },
         { GLUSTERD_SHARED_STORAGE_KEY },
+        { GLUSTERD_GLOBAL_OP_VERSION_KEY },
         { NULL },
 };
 
-#define ALL_VOLUME_OPTION_CHECK(volname, key, ret, op_errstr, label)           \
-        do {                                                                   \
-                gf_boolean_t    _all   = !strcmp ("all", volname);             \
-                gf_boolean_t    _ratio = _gf_false;                            \
-                int32_t         i      = 0;                                    \
-                                                                               \
-                for (i = 0; valid_all_vol_opts[i].option; i++) {               \
-                        if (!strcmp (key, valid_all_vol_opts[i].option)) {     \
-                                _ratio = _gf_true;                             \
-                                break;                                         \
-                        }                                                      \
-                }                                                              \
-                                                                               \
-                if (_all && !_ratio) {                                         \
-                        ret = -1;                                              \
-                        *op_errstr = gf_strdup ("Not a valid option for all "  \
-                                                "volumes");                    \
-                        goto label;                                            \
-                } else if (!_all && _ratio) {                                  \
-                        ret = -1;                                              \
-                        *op_errstr = gf_strdup ("Not a valid option for "      \
-                                                "single volume");              \
-                        goto label;                                            \
-                }                                                              \
-         } while (0)
-
 static struct cds_list_head gd_op_sm_queue;
 synclock_t gd_op_sm_lock;
 glusterd_op_info_t    opinfo = {{0},};
@@ -1203,7 +1178,8 @@ glusterd_op_stage_set_volume (dict_t *dict, char **op_errstr)
                         goto cont;
                 }
 
-                ALL_VOLUME_OPTION_CHECK (volname, key, ret, op_errstr, out);
+                ALL_VOLUME_OPTION_CHECK (volname, _gf_false, key, ret,
+                                         op_errstr, out);
                 ret = glusterd_validate_quorum_options (this, key, value,
                                                         op_errstr);
                 if (ret)
@@ -1563,7 +1539,7 @@ glusterd_op_stage_reset_volume (dict_t *dict, char **op_errstr)
                                 ret = -1;
                                 goto out;
                         }
-                        ALL_VOLUME_OPTION_CHECK (volname, key, ret,
+                        ALL_VOLUME_OPTION_CHECK (volname, _gf_false, key, ret,
                                                  op_errstr, out);
                 }
         }
diff --git a/xlators/mgmt/glusterd/src/glusterd-utils.c b/xlators/mgmt/glusterd/src/glusterd-utils.c
index 91cc12e..1f71d41 100644
--- a/xlators/mgmt/glusterd/src/glusterd-utils.c
+++ b/xlators/mgmt/glusterd/src/glusterd-utils.c
@@ -93,6 +93,7 @@
 #define NLMV1_VERSION       1
 
 extern struct volopt_map_entry glusterd_volopt_map[];
+extern glusterd_all_vol_opts valid_all_vol_opts[];
 
 static glusterd_lock_t lock;
 
@@ -10997,6 +10998,125 @@ out:
 }
 
 int
+glusterd_get_global_options_for_all_vols (dict_t *ctx, char **op_errstr)
+{
+        int                     ret = -1;
+        int                     count = 0;
+        gf_boolean_t            all_opts = _gf_false;
+        gf_boolean_t            key_found = _gf_false;
+        glusterd_conf_t         *priv = NULL;
+        xlator_t                *this = NULL;
+        char                    *key = NULL;
+        char                    *key_fixed = NULL;
+        char                    dict_key[50] = {0,};
+        char                    *def_val = NULL;
+        char                    err_str[PATH_MAX] = {0,};
+        char                    *allvolopt = NULL;
+        int32_t                 i = 0;
+        gf_boolean_t            exists = _gf_false;
+
+        this = THIS;
+        GF_VALIDATE_OR_GOTO (THIS->name, this, out);
+
+        priv = this->private;
+        GF_VALIDATE_OR_GOTO (this->name, priv, out);
+
+        GF_VALIDATE_OR_GOTO (this->name, ctx, out);
+
+        ret = dict_get_str (ctx, "key", &key);
+        if (ret) {
+                gf_msg (this->name, GF_LOG_ERROR, 0,
+                        GD_MSG_DICT_GET_FAILED,
+                        "Failed to get option key from dictionary");
+                goto out;
+        }
+
+        if (strcasecmp (key, "all") == 0)
+                all_opts = _gf_true;
+        else {
+                exists = glusterd_check_option_exists (key, &key_fixed);
+                if (!exists) {
+                        snprintf (err_str, sizeof (err_str), "Option "
+                                  "with name: %s does not exist", key);
+                        gf_msg (this->name, GF_LOG_ERROR, EINVAL,
+                                GD_MSG_UNKNOWN_KEY, "%s", err_str);
+                        if (key_fixed)
+                                snprintf (err_str, sizeof (err_str),
+                                          "Did you mean %s?", key_fixed);
+                        ret = -1;
+                        goto out;
+                }
+                if (key_fixed)
+                        key = key_fixed;
+        }
+
+        ALL_VOLUME_OPTION_CHECK ("all", _gf_true, key, ret, op_errstr, out);
+
+        for (i = 0; valid_all_vol_opts[i].option; i++) {
+                allvolopt = gf_strdup (valid_all_vol_opts[i].option);
+
+                if (!all_opts && strcmp (key, allvolopt) != 0)
+                        continue;
+
+                ret = dict_get_str (priv->opts, allvolopt, &def_val);
+
+                /* If global option isn't set explicitly */
+                if (!def_val) {
+                        if (!strcmp (allvolopt, GLUSTERD_GLOBAL_OP_VERSION_KEY))
+                                gf_asprintf (&def_val, "%d", priv->op_version);
+                        else if (!strcmp (allvolopt, GLUSTERD_QUORUM_RATIO_KEY))
+                                gf_asprintf (&def_val, "%d", 0);
+                        else if (!strcmp (allvolopt, GLUSTERD_SHARED_STORAGE_KEY))
+                                gf_asprintf (&def_val, "%s", "disable");
+                }
+
+                count++;
+                sprintf (dict_key, "key%d", count);
+                ret = dict_set_str (ctx, dict_key, allvolopt);
+                if (ret) {
+                        gf_msg (this->name, GF_LOG_ERROR, 0,
+                                GD_MSG_DICT_SET_FAILED,
+                                "Failed to set %s in dictionary", allvolopt);
+                        goto out;
+                }
+
+                sprintf (dict_key, "value%d", count);
+                ret = dict_set_dynstr_with_alloc (ctx, dict_key, def_val);
+                if (ret) {
+                        gf_msg (this->name, GF_LOG_ERROR, 0,
+                                GD_MSG_DICT_SET_FAILED,
+                                "Failed to set %s for key %s in dictionary",
+                                def_val, allvolopt);
+                        goto out;
+                }
+
+                def_val = NULL;
+                allvolopt = NULL;
+
+                if (!all_opts)
+                        break;
+        }
+
+        ret = dict_set_int32 (ctx, "count", count);
+        if (ret) {
+                gf_msg (this->name, GF_LOG_ERROR, 0, GD_MSG_DICT_SET_FAILED,
+                        "Failed to set count in dictionary");
+        }
+
+out:
+        if (ret && !all_opts && !key_found) {
+                if (err_str == NULL)
+                        snprintf (err_str, sizeof (err_str),
+                                  "option %s does not exist", key);
+                if (*op_errstr == NULL)
+                        *op_errstr = gf_strdup (err_str);
+        }
+        gf_msg_debug (THIS->name, 0, "Returning %d", ret);
+
+        return ret;
+}
+
+int
 glusterd_get_default_val_for_volopt (dict_t *ctx, gf_boolean_t all_opts,
                                      char *input_key, char *orig_key,
                                      glusterd_volinfo_t *volinfo,
diff --git a/xlators/mgmt/glusterd/src/glusterd-utils.h b/xlators/mgmt/glusterd/src/glusterd-utils.h
index b1493df..bbf4ef2 100644
--- a/xlators/mgmt/glusterd/src/glusterd-utils.h
+++ b/xlators/mgmt/glusterd/src/glusterd-utils.h
@@ -32,6 +32,39 @@
                  volinfo->volname, brickid);\
 } while (0)
 
+#define ALL_VOLUME_OPTION_CHECK(volname, get_opt, key, ret, op_errstr, label)  \
+        do {                                                                   \
+                gf_boolean_t    _all   = !strcmp ("all", volname);             \
+                gf_boolean_t    _is_valid_opt = _gf_false;                     \
+                int32_t         i      = 0;                                    \
+                                                                               \
+                if (strcmp (key, "all") == 0 && !get_opt) {                    \
+                        ret = -1;                                              \
+                        *op_errstr = gf_strdup ("Not a valid option to set");  \
+                }                                                              \
+                                                                               \
+                for (i = 0; valid_all_vol_opts[i].option; i++) {               \
+                        if (!strcmp (key, "all") ||                            \
+                            !strcmp (key, valid_all_vol_opts[i].option)) {     \
+                                _is_valid_opt = _gf_true;                      \
+                                break;                                         \
+                        }                                                      \
+                }                                                              \
+                                                                               \
+                if (_all && !_is_valid_opt) {                                  \
+                        ret = -1;                                              \
+                        *op_errstr = gf_strdup ("Not a valid option for all "  \
+                                                "volumes");                    \
+                        goto label;                                            \
+                } else if (!_all && _is_valid_opt) {                           \
+                        ret = -1;                                              \
+                        *op_errstr = gf_strdup ("Not a valid option for "      \
+                                                "single volume");              \
+                        goto label;                                            \
+                }                                                              \
+         } while (0)                                                           \
+
+
 struct glusterd_lock_ {
         uuid_t  owner;
         time_t  timestamp;
@@ -628,6 +661,9 @@ int
 glusterd_get_volopt_content (dict_t *dict, gf_boolean_t xml_out);
 
 int
+glusterd_get_global_options_for_all_vols (dict_t *dict, char **op_errstr);
+
+int
 glusterd_get_default_val_for_volopt (dict_t *dict, gf_boolean_t all_opts,
                                      char *key, char *orig_key,
                                      glusterd_volinfo_t  *volinfo,
diff --git a/xlators/mgmt/glusterd/src/glusterd.h b/xlators/mgmt/glusterd/src/glusterd.h
index ab7c03e..08a88ed 100644
--- a/xlators/mgmt/glusterd/src/glusterd.h
+++ b/xlators/mgmt/glusterd/src/glusterd.h
@@ -43,6 +43,7 @@
 #define GLUSTERD_QUORUM_TYPE_KEY        "cluster.server-quorum-type"
 #define GLUSTERD_QUORUM_RATIO_KEY       "cluster.server-quorum-ratio"
 #define GLUSTERD_GLOBAL_OPT_VERSION     "global-option-version"
+#define GLUSTERD_GLOBAL_OP_VERSION_KEY  "cluster.op-version"
 #define GLUSTERD_COMMON_PEM_PUB_FILE    "/geo-replication/common_secret.pem.pub"
 #define GEO_CONF_MAX_OPT_VALS           6
 #define GLUSTERD_CREATE_HOOK_SCRIPT     "/hooks/1/gsync-create/post/" \
-- 
1.8.3.1