summaryrefslogtreecommitdiffstats
path: root/cli
diff options
context:
space:
mode:
authorRaghavendra G <rgowdapp@redhat.com>2013-11-14 17:05:26 +0530
committerAnand Avati <avati@redhat.com>2013-11-26 10:25:27 -0800
commit0d5cd92f51c02b8d664000b5a2d22a2ddbbc23b6 (patch)
tree3410752aa6e3389f33fcb43679318eb159ab2c94 /cli
parentab3ab1978a4768e9eed8e23b47e72b25046e607a (diff)
cli/glusterd: Changes to quota command Quota feature
re-work. Following are the cli commands that are new/re-worked: ====================================================== volume quota <VOLNAME> {enable|disable|list [<path> ...]|remove <path>| default-soft-limit <percent>} | volume quota <VOLNAME> {limit-usage <path> <size> [<percent>]} | volume quota <VOLNAME> {alert-time|soft-timeout|hard-timeout} {<time>} volume status [all | <VOLNAME> [nfs|shd|<BRICK>|quotad]] [detail|clients|mem|inode|fd|callpool] volume statedump <VOLNAME> [nfs|quotad] [all|mem|iobuf|callpool|priv|fd|inode|history] glusterd changes: ================= * Quota limits are now set as extended attributes by glusterd from the aux mount created by the cli. * The gfids of the directories on which quota limits are set for a given volume are stored in /var/lib/glusterd/vols/<volname>/quota.conf file in binary format, and whose cksum and version is stored in /var/lib/glusterd/vols/<volname>/quota.cksum. Original-author: Krutika Dhananjay <kdhananj@redhat.com> Original-author: Krishnan Parthasarathi <kparthas@redhat.com> BUG: 969461 Change-Id: If32bba36c67f9c2a30417af9c6389045b2b7c13b Signed-off-by: Krutika Dhananjay <kdhananj@redhat.com> Signed-off-by: Raghavendra G <rgowdapp@redhat.com> Reviewed-on: http://review.gluster.org/6003 Tested-by: Gluster Build System <jenkins@build.gluster.com> Reviewed-by: Anand Avati <avati@redhat.com>
Diffstat (limited to 'cli')
-rw-r--r--cli/src/Makefile.am4
-rw-r--r--cli/src/cli-cmd-parser.c129
-rw-r--r--cli/src/cli-cmd-volume.c354
-rw-r--r--cli/src/cli-cmd.c4
-rw-r--r--cli/src/cli-cmd.h2
-rw-r--r--cli/src/cli-quotad-client.c154
-rw-r--r--cli/src/cli-quotad-client.h33
-rw-r--r--cli/src/cli-rpc-ops.c509
-rw-r--r--cli/src/cli.c48
-rw-r--r--cli/src/cli.h9
10 files changed, 1065 insertions, 181 deletions
diff --git a/cli/src/Makefile.am b/cli/src/Makefile.am
index d5189da5e8c..6370c2203bb 100644
--- a/cli/src/Makefile.am
+++ b/cli/src/Makefile.am
@@ -2,7 +2,7 @@ sbin_PROGRAMS = gluster
gluster_SOURCES = cli.c registry.c input.c cli-cmd.c cli-rl.c \
cli-cmd-volume.c cli-cmd-peer.c cli-rpc-ops.c cli-cmd-parser.c\
- cli-cmd-system.c cli-cmd-misc.c cli-xml-output.c
+ cli-cmd-system.c cli-cmd-misc.c cli-xml-output.c cli-quotad-client.c
gluster_LDADD = $(top_builddir)/libglusterfs/src/libglusterfs.la $(GF_LDADD)\
$(RLLIBS) $(top_builddir)/rpc/xdr/src/libgfxdr.la \
@@ -10,7 +10,7 @@ gluster_LDADD = $(top_builddir)/libglusterfs/src/libglusterfs.la $(GF_LDADD)\
$(GF_GLUSTERFS_LIBS) $(XML_LIBS)
gluster_LDFLAGS = $(GF_LDFLAGS)
-noinst_HEADERS = cli.h cli-mem-types.h cli-cmd.h
+noinst_HEADERS = cli.h cli-mem-types.h cli-cmd.h cli-quotad-client.h
AM_CPPFLAGS = $(GF_CPPFLAGS) \
-I$(top_srcdir)/libglusterfs/src -I$(top_srcdir)/rpc/rpc-lib/src\
diff --git a/cli/src/cli-cmd-parser.c b/cli/src/cli-cmd-parser.c
index cd0370acc78..dd7b11bccd4 100644
--- a/cli/src/cli-cmd-parser.c
+++ b/cli/src/cli-cmd-parser.c
@@ -485,8 +485,12 @@ cli_cmd_quota_parse (const char **words, int wordcount, dict_t **options)
uint64_t value = 0;
gf_quota_type type = GF_QUOTA_OPTION_TYPE_NONE;
char *opwords[] = { "enable", "disable", "limit-usage",
- "remove", "list", "version", NULL };
+ "remove", "list", "alert-time",
+ "soft-timeout", "hard-timeout",
+ "default-soft-limit", NULL};
char *w = NULL;
+ uint32_t time = 0;
+ double percent = 0;
GF_ASSERT (words);
GF_ASSERT (options);
@@ -558,7 +562,8 @@ cli_cmd_quota_parse (const char **words, int wordcount, dict_t **options)
}
if (strcmp (w, "limit-usage") == 0) {
- if (wordcount != 6) {
+
+ if (wordcount < 6 || wordcount > 7) {
ret = -1;
goto out;
}
@@ -567,8 +572,8 @@ cli_cmd_quota_parse (const char **words, int wordcount, dict_t **options)
if (words[4][0] != '/') {
cli_err ("Please enter absolute path");
-
- return -2;
+ ret = -1;
+ goto out;
}
ret = dict_set_str (dict, "path", (char *) words[4]);
if (ret)
@@ -576,20 +581,34 @@ cli_cmd_quota_parse (const char **words, int wordcount, dict_t **options)
if (!words[5]) {
cli_err ("Please enter the limit value to be set");
-
- return -2;
+ ret = -1;
+ goto out;
}
ret = gf_string2bytesize (words[5], &value);
if (ret != 0) {
cli_err ("Please enter a correct value");
- return -1;
+ goto out;
}
- ret = dict_set_str (dict, "limit", (char *) words[5]);
+ ret = dict_set_str (dict, "hard-limit", (char *) words[5]);
if (ret < 0)
goto out;
+ if (wordcount == 7) {
+
+ ret = gf_string2percent (words[6], &percent);
+ if (ret != 0) {
+ cli_err ("Please enter a correct value");
+ goto out;
+ }
+
+ ret = dict_set_str (dict, "soft-limit",
+ (char *) words[6]);
+ if (ret < 0)
+ goto out;
+ }
+
goto set_type;
}
if (strcmp (w, "remove") == 0) {
@@ -602,8 +621,8 @@ cli_cmd_quota_parse (const char **words, int wordcount, dict_t **options)
if (words[4][0] != '/') {
cli_err ("Please enter absolute path");
-
- return -2;
+ ret = -1;
+ goto out;
}
ret = dict_set_str (dict, "path", (char *) words[4]);
@@ -636,8 +655,75 @@ cli_cmd_quota_parse (const char **words, int wordcount, dict_t **options)
goto set_type;
}
- if (strcmp (w, "version") == 0) {
- type = GF_QUOTA_OPTION_TYPE_VERSION;
+
+ if (strcmp (w, "alert-time") == 0) {
+ if (wordcount != 5) {
+ ret = -1;
+ goto out;
+ }
+ type = GF_QUOTA_OPTION_TYPE_ALERT_TIME;
+
+ ret = gf_string2time (words[4], &time);
+ if (ret) {
+ cli_err ("Invalid argument %s. Please enter a valid "
+ "string", words[4]);
+ goto out;
+ }
+
+ ret = dict_set_str (dict, "value", (char *)words[4]);
+ if (ret < 0)
+ goto out;
+ goto set_type;
+ }
+ if (strcmp (w, "soft-timeout") == 0) {
+ if (wordcount != 5) {
+ ret = -1;
+ goto out;
+ }
+ type = GF_QUOTA_OPTION_TYPE_SOFT_TIMEOUT;
+
+ ret = gf_string2time (words[4], &time);
+ if (ret) {
+ cli_err ("Invalid argument %s. Please enter a valid "
+ "string", words[4]);
+ goto out;
+ }
+
+ ret = dict_set_str (dict, "value", (char *)words[4]);
+ if (ret < 0)
+ goto out;
+ goto set_type;
+ }
+ if (strcmp (w, "hard-timeout") == 0) {
+ if(wordcount != 5) {
+ ret = -1;
+ goto out;
+ }
+ type = GF_QUOTA_OPTION_TYPE_HARD_TIMEOUT;
+
+ ret = gf_string2time (words[4], &time);
+ if (ret) {
+ cli_err ("Invalid argument %s. Please enter a valid "
+ "string", words[4]);
+ goto out;
+ }
+
+ ret = dict_set_str (dict, "value", (char *)words[4]);
+ if (ret < 0)
+ goto out;
+ goto set_type;
+ }
+ if (strcmp (w, "default-soft-limit") == 0) {
+ if(wordcount != 5) {
+ ret = -1;
+ goto out;
+ }
+ type = GF_QUOTA_OPTION_TYPE_DEFAULT_SOFT_LIMIT;
+
+ ret = dict_set_str (dict, "value", (char *)words[4]);
+ if (ret < 0)
+ goto out;
+ goto set_type;
} else {
GF_ASSERT (!"opword mismatch");
}
@@ -2225,6 +2311,8 @@ cli_cmd_volume_status_parse (const char **words, int wordcount,
cmd |= GF_CLI_STATUS_NFS;
} else if (!strcmp (words[3], "shd")) {
cmd |= GF_CLI_STATUS_SHD;
+ } else if (!strcmp (words[3], "quotad")) {
+ cmd |= GF_CLI_STATUS_QUOTAD;
} else {
cmd = GF_CLI_STATUS_BRICK;
ret = dict_set_str (dict, "brick",
@@ -2280,6 +2368,17 @@ cli_cmd_volume_status_parse (const char **words, int wordcount,
goto out;
}
cmd |= GF_CLI_STATUS_SHD;
+ } else if (!strcmp (words[3], "quotad")) {
+ if (cmd == GF_CLI_STATUS_FD ||
+ cmd == GF_CLI_STATUS_CLIENTS ||
+ cmd == GF_CLI_STATUS_DETAIL ||
+ cmd == GF_CLI_STATUS_INODE) {
+ cli_err ("Detail/FD/Clients/Inode status not "
+ "available for Quota Daemon");
+ ret = -1;
+ goto out;
+ }
+ cmd |= GF_CLI_STATUS_QUOTAD;
} else {
if (cmd == GF_CLI_STATUS_TASKS) {
cli_err ("Tasks status not available for "
@@ -2317,7 +2416,7 @@ cli_cmd_validate_dumpoption (const char *arg, char **option)
{
char *opwords[] = {"all", "nfs", "mem", "iobuf", "callpool", "priv",
"fd", "inode", "history", "inodectx", "fdctx",
- NULL};
+ "quotad", NULL};
char *w = NULL;
w = str_getunamb (arg, opwords);
@@ -2349,6 +2448,10 @@ cli_cmd_volume_statedump_options_parse (const char **words, int wordcount,
strncat (option_str, option, strlen (option));
strncat (option_str, " ", 1);
}
+ if((strstr (option_str, "nfs")) && strstr (option_str, "quotad")) {
+ ret = -1;
+ goto out;
+ }
dict = dict_new ();
if (!dict)
diff --git a/cli/src/cli-cmd-volume.c b/cli/src/cli-cmd-volume.c
index 100be0b7337..9bc11d2dbb4 100644
--- a/cli/src/cli-cmd-volume.c
+++ b/cli/src/cli-cmd-volume.c
@@ -30,8 +30,10 @@
#include "run.h"
extern struct rpc_clnt *global_rpc;
+extern struct rpc_clnt *global_quotad_rpc;
extern rpc_clnt_prog_t *cli_rpc_prog;
+extern rpc_clnt_prog_t cli_quotad_clnt;
int
cli_cmd_volume_help_cbk (struct cli_state *state, struct cli_cmd_word *in_word,
@@ -1007,6 +1009,283 @@ out:
return ret;
}
+static int
+gf_cli_create_auxiliary_mount (char *volname)
+{
+ int ret = -1;
+ char mountdir[PATH_MAX] = {0,};
+ char pidfile_path[PATH_MAX] = {0,};
+ char logfile[PATH_MAX] = {0,};
+
+ GLUSTERFS_GET_AUX_MOUNT_PIDFILE (pidfile_path, volname);
+
+ if (gf_is_service_running (pidfile_path, NULL)) {
+ gf_log ("cli", GF_LOG_DEBUG, "Aux mount of volume %s is running"
+ " already", volname);
+ ret = 0;
+ goto out;
+ }
+
+ snprintf (mountdir, sizeof (mountdir)-1, "/tmp/%s", volname);
+ ret = mkdir (mountdir, 0777);
+ if (ret && errno != EEXIST) {
+ gf_log ("cli", GF_LOG_ERROR, "Failed to create auxiliary mount "
+ "directory %s. Reason : %s", mountdir,
+ strerror (errno));
+ goto out;
+ }
+
+ snprintf (logfile, PATH_MAX-1, "%s/quota-mount-%s.log",
+ DEFAULT_LOG_FILE_DIRECTORY, volname);
+
+ ret = runcmd (SBIN_DIR"/glusterfs",
+ "-s", "localhost",
+ "--volfile-id", volname,
+ "-l", logfile,
+ "-p", pidfile_path,
+ mountdir,
+ "--client-pid", "-42", NULL);
+
+ if (ret) {
+ gf_log ("cli", GF_LOG_WARNING, "failed to mount glusterfs "
+ "client. Please check the log file %s for more details",
+ logfile);
+ ret = -1;
+ goto out;
+ }
+
+ ret = 0;
+
+out:
+ return ret;
+}
+
+static int
+cli_stage_quota_op (char *volname, int op_code)
+{
+ int ret = -1;
+
+ switch (op_code) {
+ case GF_QUOTA_OPTION_TYPE_ENABLE:
+ case GF_QUOTA_OPTION_TYPE_LIMIT_USAGE:
+ case GF_QUOTA_OPTION_TYPE_REMOVE:
+ case GF_QUOTA_OPTION_TYPE_LIST:
+ ret = gf_cli_create_auxiliary_mount (volname);
+ if (ret)
+ goto out;
+ ret = 0;
+ break;
+
+ default:
+ ret = 0;
+ break;
+ }
+
+out:
+ return ret;
+}
+
+static void
+print_quota_list_header (void)
+{
+ //Header
+ cli_out (" Path Hard-limit "
+ "Soft-limit Used Available");
+ cli_out ("-----------------------------------------------------"
+ "---------------------------");
+}
+
+int
+cli_get_soft_limit (dict_t *options, const char **words, dict_t *xdata)
+{
+ call_frame_t *frame = NULL;
+ cli_local_t *local = NULL;
+ rpc_clnt_procedure_t *proc = NULL;
+ char *default_sl = NULL;
+ char *default_sl_dup = NULL;
+ int ret = -1;
+
+ frame = create_frame (THIS, THIS->ctx->pool);
+ if (!frame) {
+ ret = -1;
+ goto out;
+ }
+
+ //We need a ref on @options to prevent CLI_STACK_DESTROY
+ //from destroying it prematurely.
+ dict_ref (options);
+ CLI_LOCAL_INIT (local, words, frame, options);
+ proc = &cli_rpc_prog->proctable[GLUSTER_CLI_QUOTA];
+ ret = proc->fn (frame, THIS, options);
+
+ ret = dict_get_str (options, "default-soft-limit", &default_sl);
+ if (ret) {
+ gf_log ("cli", GF_LOG_ERROR, "Failed to get default soft limit");
+ goto out;
+ }
+
+ default_sl_dup = gf_strdup (default_sl);
+ if (!default_sl_dup) {
+ ret = -1;
+ goto out;
+ }
+
+ ret = dict_set_dynstr (xdata, "default-soft-limit", default_sl_dup);
+ if (ret) {
+ gf_log ("cli", GF_LOG_ERROR, "Failed to set default soft limit");
+ GF_FREE (default_sl_dup);
+ goto out;
+ }
+
+out:
+ CLI_STACK_DESTROY (frame);
+ return ret;
+}
+
+#define QUOTA_CONF_HEADER \
+ "GlusterFS Quota conf | version: v%d.%d\n"
+int
+cli_cmd_quota_conf_skip_header (int fd)
+{
+ char buf[PATH_MAX] = {0,};
+
+ snprintf (buf, sizeof(buf)-1, QUOTA_CONF_HEADER, 1, 1);
+ return gf_skip_header_section (fd, strlen (buf));
+}
+
+int
+cli_cmd_quota_handle_list_all (const char **words, dict_t *options)
+{
+ int all_failed = 1;
+ int count = 0;
+ int ret = -1;
+ rpc_clnt_procedure_t *proc = NULL;
+ cli_local_t *local = NULL;
+ call_frame_t *frame = NULL;
+ dict_t *xdata = NULL;
+ char *gfid_str = NULL;
+ char *volname = NULL;
+ char *volname_dup = NULL;
+ unsigned char buf[16] = {0};
+ int fd = -1;
+ char quota_conf_file[PATH_MAX] = {0};
+
+ xdata = dict_new ();
+ if (!xdata) {
+ ret = -1;
+ goto out;
+ }
+
+ ret = dict_get_str (options, "volname", &volname);
+ if (ret) {
+ gf_log ("cli", GF_LOG_ERROR, "Failed to get volume name");
+ goto out;
+ }
+
+ ret = cli_get_soft_limit (options, words, xdata);
+ if (ret) {
+ gf_log ("cli", GF_LOG_ERROR, "Failed to fetch default "
+ "soft-limit");
+ goto out;
+ }
+
+ frame = create_frame (THIS, THIS->ctx->pool);
+ if (!frame) {
+ ret = -1;
+ goto out;
+ }
+
+ volname_dup = gf_strdup (volname);
+ if (!volname_dup) {
+ ret = -1;
+ goto out;
+ }
+
+ ret = dict_set_dynstr (xdata, "volume-uuid", volname_dup);
+ if (ret) {
+ gf_log ("cli", GF_LOG_ERROR, "Failed to set volume-uuid");
+ GF_FREE (volname_dup);
+ goto out;
+ }
+
+ //TODO: fix hardcoding; Need to perform an RPC call to glusterd
+ //to fetch working directory
+ sprintf (quota_conf_file, "/var/lib/glusterd/vols/%s/quota.conf",
+ volname);
+ fd = open (quota_conf_file, O_RDONLY);
+ if (fd == -1) {
+ //This may because no limits were yet set on the volume
+ gf_log ("cli", GF_LOG_TRACE, "Unable to open "
+ "quota.conf");
+ ret = 0;
+ goto out;
+ }
+
+ ret = cli_cmd_quota_conf_skip_header (fd);
+ if (ret) {
+ goto out;
+ }
+ CLI_LOCAL_INIT (local, words, frame, xdata);
+ proc = &cli_quotad_clnt.proctable[GF_AGGREGATOR_GETLIMIT];
+
+ print_quota_list_header ();
+ gfid_str = GF_CALLOC (1, gf_common_mt_char, 64);
+ if (!gfid_str) {
+ ret = -1;
+ goto out;
+ }
+ for (count = 0;; count++) {
+ ret = read (fd, (void*) buf, 16);
+ if (ret <= 0) {
+ //Finished reading all entries in the conf file
+ break;
+ }
+ if (ret < 16) {
+ //This should never happen. We must have a multiple of
+ //entry_sz bytes in our configuration file.
+ gf_log (THIS->name, GF_LOG_CRITICAL, "Quota "
+ "configuration store may be corrupt.");
+ goto out;
+ }
+ uuid_utoa_r (buf, gfid_str);
+ ret = dict_set_str (xdata, "gfid", gfid_str);
+ if (ret) {
+ gf_log ("cli", GF_LOG_ERROR, "Failed to set gfid");
+ goto out;
+ }
+
+ ret = proc->fn (frame, THIS, xdata);
+ if (ret) {
+ gf_log ("cli", GF_LOG_ERROR, "Failed to get quota "
+ "limits for %s", uuid_utoa ((unsigned char*)buf));
+ }
+
+ dict_del (xdata, "gfid");
+ all_failed = all_failed && ret;
+ }
+
+ if (count > 0) {
+ ret = all_failed? 0: -1;
+ } else {
+ ret = 0;
+ }
+out:
+ if (count == 0) {
+ cli_out ("quota: No quota configured on volume %s", volname);
+ }
+ if (fd != -1) {
+ close (fd);
+ }
+
+ GF_FREE (gfid_str);
+ if (ret) {
+ gf_log ("cli", GF_LOG_ERROR, "Couldn't fetch quota limits "
+ "for even one of the directories configured");
+ }
+ CLI_STACK_DESTROY (frame);
+ return ret;
+}
+
int
cli_cmd_quota_cbk (struct cli_state *state, struct cli_cmd_word *word,
const char **words, int wordcount)
@@ -1020,47 +1299,78 @@ cli_cmd_quota_cbk (struct cli_state *state, struct cli_cmd_word *word,
dict_t *options = NULL;
gf_answer_t answer = GF_ANSWER_NO;
cli_local_t *local = NULL;
+ int sent = 0;
+ char *volname = NULL;
const char *question = "Disabling quota will delete all the quota "
"configuration. Do you want to continue?";
- proc = &cli_rpc_prog->proctable[GLUSTER_CLI_QUOTA];
- if (proc == NULL) {
- ret = -1;
+ //parse **words into options dictionary
+ ret = cli_cmd_quota_parse (words, wordcount, &options);
+ if (ret < 0) {
+ cli_usage_out (word->pattern);
+ parse_err = 1;
goto out;
}
- frame = create_frame (THIS, THIS->ctx->pool);
- if (!frame) {
- ret = -1;
+ ret = dict_get_int32 (options, "type", &type);
+ if (ret) {
+ gf_log ("cli", GF_LOG_ERROR, "Failed to get opcode");
goto out;
}
- ret = cli_cmd_quota_parse (words, wordcount, &options);
-
- if (ret < 0) {
- cli_usage_out (word->pattern);
- parse_err = 1;
- goto out;
- } else if (dict_get_int32 (options, "type", &type) == 0 &&
- type == GF_QUOTA_OPTION_TYPE_DISABLE) {
+ //handle quota-disable and quota-list-all different from others
+ switch (type) {
+ case GF_QUOTA_OPTION_TYPE_DISABLE:
answer = cli_cmd_get_confirmation (state, question);
if (answer == GF_ANSWER_NO)
goto out;
+ break;
+ case GF_QUOTA_OPTION_TYPE_LIST:
+ if (wordcount != 4)
+ break;
+ ret = cli_cmd_quota_handle_list_all (words, options);
+ goto out;
+ default:
+ break;
+ }
+
+ ret = dict_get_str (options, "volname", &volname);
+ if (ret) {
+ gf_log ("cli", GF_LOG_ERROR, "Failed to get volume name");
+ goto out;
+ }
+
+ //create auxillary mount need for quota commands that operate on path
+ ret = cli_stage_quota_op (volname, type);
+ if (ret)
+ goto out;
+
+ frame = create_frame (THIS, THIS->ctx->pool);
+ if (!frame) {
+ ret = -1;
+ goto out;
}
CLI_LOCAL_INIT (local, words, frame, options);
+ proc = &cli_rpc_prog->proctable[GLUSTER_CLI_QUOTA];
+ if (proc == NULL) {
+ ret = -1;
+ goto out;
+ }
if (proc->fn)
ret = proc->fn (frame, THIS, options);
out:
- if (ret && parse_err == 0)
- cli_out ("Quota command failed");
+ if (ret) {
+ cli_cmd_sent_status_get (&sent);
+ if (sent == 0 && parse_err == 0)
+ cli_out ("Quota command failed. Please check the cli "
+ "logs for more details");
+ }
CLI_STACK_DESTROY (frame);
-
return ret;
-
}
int
@@ -1906,7 +2216,9 @@ struct cli_cmd volume_cmds[] = {
cli_cmd_volume_profile_cbk,
"volume profile operations"},
- { "volume quota <VOLNAME> <enable|disable|limit-usage|list|remove> [path] [value]",
+ { "volume quota <VOLNAME> {enable|disable|list [<path> ...]|remove <path>| default-soft-limit <percent>} |\n"
+ "volume quota <VOLNAME> {limit-usage <path> <size> [<percent>]} |\n"
+ "volume quota <VOLNAME> {alert-time|soft-timeout|hard-timeout} {<time>}",
cli_cmd_quota_cbk,
"quota translator specific operations"},
@@ -1915,7 +2227,7 @@ struct cli_cmd volume_cmds[] = {
cli_cmd_volume_top_cbk,
"volume top operations"},
- { "volume status [all | <VOLNAME> [nfs|shd|<BRICK>]]"
+ { "volume status [all | <VOLNAME> [nfs|shd|<BRICK>|quotad]]"
" [detail|clients|mem|inode|fd|callpool|tasks]",
cli_cmd_volume_status_cbk,
"display status of all or specified volume(s)/brick"},
@@ -1924,7 +2236,7 @@ struct cli_cmd volume_cmds[] = {
cli_cmd_volume_heal_cbk,
"self-heal commands on volume specified by <VOLNAME>"},
- {"volume statedump <VOLNAME> [nfs] [all|mem|iobuf|callpool|priv|fd|"
+ {"volume statedump <VOLNAME> [nfs|quotad] [all|mem|iobuf|callpool|priv|fd|"
"inode|history]...",
cli_cmd_volume_statedump_cbk,
"perform statedump on bricks"},
diff --git a/cli/src/cli-cmd.c b/cli/src/cli-cmd.c
index 1045f34f0f5..63b939282fa 100644
--- a/cli/src/cli-cmd.c
+++ b/cli/src/cli-cmd.c
@@ -352,7 +352,7 @@ cli_cmd_broadcast_connected ()
}
int
-cli_cmd_submit (void *req, call_frame_t *frame,
+cli_cmd_submit (struct rpc_clnt* rpc, void *req, call_frame_t *frame,
rpc_clnt_prog_t *prog,
int procnum, struct iobref *iobref,
xlator_t *this, fop_cbk_fn_t cbkfn, xdrproc_t xdrproc)
@@ -368,7 +368,7 @@ cli_cmd_submit (void *req, call_frame_t *frame,
cli_cmd_lock ();
cmd_sent = 0;
- ret = cli_submit_request (req, frame, prog,
+ ret = cli_submit_request (rpc, req, frame, prog,
procnum, NULL, this, cbkfn, xdrproc);
if (!ret) {
diff --git a/cli/src/cli-cmd.h b/cli/src/cli-cmd.h
index 06a1ed32aac..52396bbf755 100644
--- a/cli/src/cli-cmd.h
+++ b/cli/src/cli-cmd.h
@@ -110,7 +110,7 @@ int cli_cmd_lock ();
int cli_cmd_unlock ();
int
-cli_cmd_submit (void *req, call_frame_t *frame,
+cli_cmd_submit (struct rpc_clnt *rpc, void *req, call_frame_t *frame,
rpc_clnt_prog_t *prog,
int procnum, struct iobref *iobref,
xlator_t *this, fop_cbk_fn_t cbkfn, xdrproc_t xdrproc);
diff --git a/cli/src/cli-quotad-client.c b/cli/src/cli-quotad-client.c
new file mode 100644
index 00000000000..f0efc8640bd
--- /dev/null
+++ b/cli/src/cli-quotad-client.c
@@ -0,0 +1,154 @@
+/*
+ Copyright (c) 2010-2013 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.
+*/
+#ifndef _CONFIG_H
+#define _CONFIG_H
+#include "config.h"
+#endif
+
+
+#include "cli-quotad-client.h"
+
+extern struct rpc_clnt global_quotad_rpc;
+extern struct rpc_clnt_program cli_quotad_clnt;
+
+int
+cli_quotad_submit_request (void *req, call_frame_t *frame,
+ rpc_clnt_prog_t *prog,
+ int procnum, struct iobref *iobref,
+ xlator_t *this, fop_cbk_fn_t cbkfn,
+ xdrproc_t xdrproc)
+{
+ int ret = -1;
+ int count = 0;
+ struct iovec iov = {0, };
+ struct iobuf *iobuf = NULL;
+ char new_iobref = 0;
+ ssize_t xdr_size = 0;
+
+ GF_ASSERT (this);
+
+ if (req) {
+ xdr_size = xdr_sizeof (xdrproc, req);
+ iobuf = iobuf_get2 (this->ctx->iobuf_pool, xdr_size);
+ if (!iobuf) {
+ goto out;
+ };
+
+ if (!iobref) {
+ iobref = iobref_new ();
+ if (!iobref) {
+ goto out;
+ }
+
+ new_iobref = 1;
+ }
+
+ iobref_add (iobref, iobuf);
+
+ iov.iov_base = iobuf->ptr;
+ iov.iov_len = iobuf_size (iobuf);
+
+ /* Create the xdr payload */
+ ret = xdr_serialize_generic (iov, req, xdrproc);
+ if (ret == -1) {
+ goto out;
+ }
+ iov.iov_len = ret;
+ count = 1;
+ }
+
+ /* Send the msg */
+ ret = rpc_clnt_submit (&global_quotad_rpc, prog, procnum, cbkfn,
+ &iov, count,
+ NULL, 0, iobref, frame, NULL, 0, NULL, 0, NULL);
+ ret = 0;
+
+out:
+ if (new_iobref)
+ iobref_unref (iobref);
+ if (iobuf)
+ iobuf_unref (iobuf);
+
+ return ret;
+}
+
+int
+cli_quotad_notify (struct rpc_clnt *rpc, void *mydata,
+ rpc_clnt_event_t event, void *data)
+{
+ xlator_t *this = NULL;
+ int ret = 0;
+
+ this = mydata;
+
+ switch (event) {
+ case RPC_CLNT_CONNECT:
+ {
+ gf_log (this->name, GF_LOG_TRACE, "got RPC_CLNT_CONNECT");
+ break;
+ }
+
+ case RPC_CLNT_DISCONNECT:
+ {
+ gf_log (this->name, GF_LOG_TRACE, "got RPC_CLNT_DISCONNECT");
+ break;
+ }
+
+ default:
+ gf_log (this->name, GF_LOG_TRACE,
+ "got some other RPC event %d", event);
+ ret = 0;
+ break;
+ }
+
+ return ret;
+}
+
+struct rpc_clnt *
+cli_quotad_clnt_init (xlator_t *this, dict_t *options)
+{
+ struct rpc_clnt *rpc = NULL;
+ int ret = -1;
+
+
+ ret = dict_set_str (options, "transport.address-family", "unix");
+ if (ret)
+ goto out;
+
+ ret = dict_set_str (options, "transport-type", "socket");
+ if (ret)
+ goto out;
+
+ ret = dict_set_str (options, "transport.socket.connect-path",
+ "/tmp/quotad.socket");
+ if (ret)
+ goto out;
+
+ rpc = rpc_clnt_new (options, this->ctx, this->name, 16);
+ if (!rpc)
+ goto out;
+
+ ret = rpc_clnt_register_notify (rpc, cli_quotad_notify, this);
+ if (ret) {
+ gf_log ("cli", GF_LOG_ERROR, "failed to register notify");
+ goto out;
+ }
+
+ rpc_clnt_start (rpc);
+out:
+ if (ret) {
+ if (rpc)
+ rpc_clnt_unref (rpc);
+ rpc = NULL;
+ }
+
+ return rpc;
+}
+
diff --git a/cli/src/cli-quotad-client.h b/cli/src/cli-quotad-client.h
new file mode 100644
index 00000000000..aa0b42af38d
--- /dev/null
+++ b/cli/src/cli-quotad-client.h
@@ -0,0 +1,33 @@
+/*
+ Copyright (c) 2010-2013 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 "cli.h"
+#include "compat-errno.h"
+#include "compat.h"
+#include "cli-cmd.h"
+#include "cli1-xdr.h"
+#include "xdr-generic.h"
+#include "protocol-common.h"
+#include "cli-mem-types.h"
+
+
+int
+cli_quotad_submit_request (void *req, call_frame_t *frame,
+ rpc_clnt_prog_t *prog,
+ int procnum, struct iobref *iobref,
+ xlator_t *this, fop_cbk_fn_t cbkfn,
+ xdrproc_t xdrproc);
+
+struct rpc_clnt *
+cli_quotad_clnt_init (xlator_t *this, dict_t *options);
+
+int
+cli_quotad_notify (struct rpc_clnt *rpc, void *mydata,
+ rpc_clnt_event_t event, void *data);
+
diff --git a/cli/src/cli-rpc-ops.c b/cli/src/cli-rpc-ops.c
index 208f7a281f0..07c081affcc 100644
--- a/cli/src/cli-rpc-ops.c
+++ b/cli/src/cli-rpc-ops.c
@@ -37,9 +37,13 @@
#include "syscall.h"
#include "glusterfs3.h"
#include "portmap-xdr.h"
+#include "byte-order.h"
+#include "cli-quotad-client.h"
#include "run.h"
+extern struct rpc_clnt *global_quotad_rpc;
+extern rpc_clnt_prog_t cli_quotad_clnt;
extern rpc_clnt_prog_t *cli_rpc_prog;
extern int cli_op_ret;
extern int connected;
@@ -2281,137 +2285,346 @@ out:
return ret;
}
-int32_t
-gf_cli_print_limit_list (char *volname, char *limit_list,
- char *op_errstr)
+static int
+print_quota_list_output (char *mountdir, char *default_sl, char *path)
{
- int64_t size = 0;
- int64_t limit_value = 0;
- int32_t i, j;
- int32_t len = 0, ret = -1;
- char *size_str = NULL;
- char path [PATH_MAX] = {0, };
- char ret_str [1024] = {0, };
- char value [1024] = {0, };
- char mountdir [] = "/tmp/mntXXXXXX";
- char abspath [PATH_MAX] = {0, };
- char *colon_ptr = NULL;
- runner_t runner = {0,};
+ uint64_t used_space = 0;
+ uint64_t avail = 0;
+ char *used_str = NULL;
+ char *avail_str = NULL;
+ int ret = -1;
+ char *sl_final = NULL;
+ char percent_str[20] = {0,};
+ char *hl_str = NULL;
+
+ struct quota_limit {
+ int64_t hl;
+ int64_t sl;
+ } __attribute__ ((__packed__)) existing_limits;
+
+ ret = sys_lgetxattr (mountdir, "trusted.glusterfs.quota.limit-set",
+ (void *)&existing_limits,
+ sizeof (existing_limits));
+ if (ret < 0) {
+ gf_log ("cli", GF_LOG_ERROR, "Failed to get the xattr "
+ "trusted.glusterfs.quota.limit-set on %s. Reason : %s",
+ mountdir, strerror (errno));
+ goto out;
+ }
- GF_VALIDATE_OR_GOTO ("cli", volname, out);
- GF_VALIDATE_OR_GOTO ("cli", limit_list, out);
+ existing_limits.hl = ntoh64 (existing_limits.hl);
+ existing_limits.sl = ntoh64 (existing_limits.sl);
- if (!connected)
+ hl_str = gf_uint64_2human_readable (existing_limits.hl);
+
+ if (existing_limits.sl < 0) {
+ sl_final = default_sl;
+ } else {
+ snprintf (percent_str, sizeof (percent_str), "%"PRIu64"%%",
+ existing_limits.sl);
+ sl_final = percent_str;
+ }
+
+ ret = sys_lgetxattr (mountdir, "trusted.glusterfs.quota.size",
+ &used_space, sizeof (used_space));
+
+ if (ret < 0) {
+ cli_out ("%-40s %7s %9s %11s %7s", path, hl_str, sl_final,
+ "N/A", "N/A");
+ } else {
+ used_space = ntoh64 (used_space);
+
+ used_str = gf_uint64_2human_readable (used_space);
+
+ if (existing_limits.hl > used_space)
+ avail = existing_limits.hl - used_space;
+ else
+ avail = 0;
+
+ avail_str = gf_uint64_2human_readable (avail);
+ if (used_str == NULL)
+ cli_out ("%-40s %7s %9s %11"PRIu64
+ "%9"PRIu64, path, hl_str,
+ sl_final, used_space, avail);
+ else
+ cli_out ("%-40s %7s %9s %11s %7s", path, hl_str,
+ sl_final, used_str, avail_str);
+ }
+
+out:
+ GF_FREE (used_str);
+ GF_FREE (avail_str);
+ GF_FREE (hl_str);
+ return ret;
+}
+
+int
+gf_cli_print_limit_list_from_dict (char *volname, dict_t *dict,
+ char *default_sl, int count, char *op_errstr)
+{
+ int ret = -1;
+ int i = 0;
+ char key[1024] = {0,};
+ char mountdir[PATH_MAX] = {0,};
+ char *path = NULL;
+
+ if (!dict|| count <= 0)
goto out;
- len = strlen (limit_list);
- if (len == 0) {
- cli_err ("%s", op_errstr?op_errstr:"quota limit not set ");
+ /*To-Do:
+ * Proper error reporting to handle the case where none of the given
+ * path arguments are present or have their limits set.
+ */
+
+ cli_out (" Path Hard-limit "
+ "Soft-limit Used Available");
+ cli_out ("-----------------------------------------------------"
+ "---------------------------");
+
+ while (count--) {
+ snprintf (key, sizeof (key), "path%d", i++);
+
+ ret = dict_get_str (dict, key, &path);
+ if (ret < 0) {
+ gf_log ("cli", GF_LOG_DEBUG, "Path not present in limit"
+ " list");
+ continue;
+ }
+
+ ret = gf_canonicalize_path (path);
+ if (ret)
+ goto out;
+ snprintf (mountdir, sizeof (mountdir), "/tmp/%s%s", volname,
+ path);
+
+ ret = print_quota_list_output (mountdir, default_sl, path);
+
+ }
+out:
+ return ret;
+}
+
+int
+print_quota_list_from_quotad (call_frame_t *frame, dict_t *rsp_dict)
+{
+ int64_t used_space = 0;
+ int64_t avail = 0;
+ int64_t *limit = NULL;
+ char *used_str = NULL;
+ char *avail_str = NULL;
+ char percent_str[20]= {0};
+ char *hl_str = NULL;
+ char *sl_final = NULL;
+ char *path = NULL;
+ char *default_sl = NULL;
+ int ret = -1;
+ cli_local_t *local = NULL;
+ dict_t *gd_rsp_dict = NULL;
+
+ local = frame->local;
+ gd_rsp_dict = local->dict;
+
+ struct quota_limit {
+ int64_t hl;
+ int64_t sl;
+ } __attribute__ ((__packed__)) *existing_limits = NULL;
+
+ ret = dict_get_str (rsp_dict, GET_ANCESTRY_PATH_KEY, &path);
+ if (ret) {
+ gf_log ("cli", GF_LOG_WARNING, "path key is not present "
+ "in dict");
goto out;
}
- if (mkdtemp (mountdir) == NULL) {
- gf_log ("cli", GF_LOG_WARNING, "failed to create a temporary "
- "mount directory");
- ret = -1;
+ ret = dict_get_bin (rsp_dict, QUOTA_LIMIT_KEY, (void**)&limit);
+ if (ret) {
+ gf_log ("cli", GF_LOG_WARNING,
+ "limit key not present in dict");
goto out;
}
- /* Mount a temporary client to fetch the disk usage
- * of the directory on which the limit is set.
- */
- ret = runcmd (SBIN_DIR"/glusterfs", "-s",
- "localhost", "--volfile-id", volname, "-l",
- DEFAULT_LOG_FILE_DIRECTORY"/quota-list.log",
- mountdir, NULL);
+ ret = dict_get_str (gd_rsp_dict, "default-soft-limit", &default_sl);
if (ret) {
- gf_log ("cli", GF_LOG_WARNING, "failed to mount glusterfs client");
- ret = -1;
- goto rm_dir;
+ gf_log (frame->this->name, GF_LOG_ERROR, "failed to "
+ "get default soft limit");
+ goto out;
}
+ existing_limits = (struct quota_limit *)limit;
+ existing_limits->hl = ntoh64 (existing_limits->hl);
+ existing_limits->sl = ntoh64 (existing_limits->sl);
- len = strlen (limit_list);
- if (len == 0) {
- cli_err ("quota limit not set ");
- goto unmount;
+ hl_str = gf_uint64_2human_readable (existing_limits->hl);
+
+ if (existing_limits->sl < 0) {
+ sl_final = default_sl;
+ } else {
+ snprintf (percent_str, sizeof (percent_str), "%"PRIu64"%%",
+ existing_limits->sl);
+ sl_final = percent_str;
}
- i = 0;
+ ret = dict_get_bin (rsp_dict, QUOTA_SIZE_KEY, (void**)&limit);
+ if (ret < 0) {
+ gf_log ("cli", GF_LOG_WARNING,
+ "size key not present in dict");
+ cli_out ("%-40s %7s %9s %11s %7s", path, hl_str, sl_final,
+ "N/A", "N/A");
+ } else {
+ used_space = *limit;
+ used_space = ntoh64 (used_space);
+ used_str = gf_uint64_2human_readable (used_space);
- cli_out ("\tpath\t\t limit_set\t size");
- cli_out ("-----------------------------------------------------------"
- "-----------------------");
- while (i < len) {
- j = 0;
+ if (existing_limits->hl > used_space)
+ avail = existing_limits->hl - used_space;
+ else
+ avail = 0;
- while (limit_list [i] != ',' && limit_list [i] != '\0') {
- path [j++] = limit_list[i++];
- }
- path [j] = '\0';
- //here path[] contains both path and limit value
+ avail_str = gf_uint64_2human_readable (avail);
+ if (used_str == NULL)
+ cli_out ("%-40s %7s %9s %11"PRIu64
+ "%9"PRIu64, path, hl_str,
+ sl_final, used_space, avail);
+ else
+ cli_out ("%-40s %7s %9s %11s %7s", path, hl_str,
+ sl_final, used_str, avail_str);
+ }
+
+ ret = 0;
+out:
+ GF_FREE (used_str);
+ GF_FREE (avail_str);
+ GF_FREE (hl_str);
+ return ret;
+}
+
+int
+cli_quotad_getlimit_cbk (struct rpc_req *req, struct iovec *iov,
+ int count, void *myframe)
+{
+ //TODO: we need to gather the path, hard-limit, soft-limit and used space
+ gf_cli_rsp rsp = {0,};
+ int ret = -1;
+ dict_t *dict = NULL;
+ call_frame_t *frame = NULL;
- colon_ptr = strrchr (path, ':');
- *colon_ptr = '\0';
- strcpy (value, ++colon_ptr);
+ if (-1 == req->rpc_status) {
+ goto out;
+ }
- snprintf (abspath, sizeof (abspath), "%s/%s", mountdir, path);
+ frame = myframe;
+
+ ret = xdr_to_generic (*iov, &rsp, (xdrproc_t)xdr_gf_cli_rsp);
+ if (ret < 0) {
+ gf_log (frame->this->name, GF_LOG_ERROR,
+ "Failed to decode xdr response");
+ goto out;
+ }
+
+ if (rsp.op_ret && strcmp (rsp.op_errstr, "") == 0) {
+ cli_err ("quota command : failed");
+ goto out;
+
+ } else if (strcmp (rsp.op_errstr, ""))
+ cli_err ("quota command failed : %s", rsp.op_errstr);
+
+ if (rsp.dict.dict_len) {
+ /* Unserialize the dictionary */
+ dict = dict_new ();
- ret = sys_lgetxattr (abspath, "trusted.limit.list", (void *) ret_str, 4096);
+ ret = dict_unserialize (rsp.dict.dict_val,
+ rsp.dict.dict_len,
+ &dict);
if (ret < 0) {
- cli_out ("%-20s %10s", path, value);
- } else {
- sscanf (ret_str, "%"PRId64",%"PRId64, &size,
- &limit_value);
- size_str = gf_uint64_2human_readable ((uint64_t) size);
- if (size_str == NULL) {
- cli_out ("%-20s %10s %20"PRId64, path,
- value, size);
- } else {
- cli_out ("%-20s %10s %20s", path,
- value, size_str);
- GF_FREE (size_str);
- }
+ gf_log ("cli", GF_LOG_ERROR,
+ "failed to "
+ "unserialize req-buffer to dictionary");
+ goto out;
}
- i++;
+ print_quota_list_from_quotad (frame, dict);
}
-unmount:
+out:
+ cli_cmd_broadcast_response (ret);
+ if (dict)
+ dict_unref (dict);
- runinit (&runner);
- runner_add_args (&runner, "umount",
-#if GF_LINUX_HOST_OS
- "-l",
-#endif
- mountdir, NULL);
- ret = runner_run_reuse (&runner);
- if (ret)
- runner_log (&runner, "cli", GF_LOG_WARNING, "error executing");
- runner_end (&runner);
+ free (rsp.dict.dict_val);
+ return ret;
+}
+
+int
+cli_quotad_getlimit (call_frame_t *frame, xlator_t *this, void *data)
+{
+ gf_cli_req req = {{0,}};
+ int ret = 0;
+ dict_t *dict = NULL;
+
+ if (!frame || !this || !data) {
+ ret = -1;
+ goto out;
+ }
+
+ dict = data;
+ ret = dict_allocate_and_serialize (dict, &req.dict.dict_val,
+ &req.dict.dict_len);
+ if (ret < 0) {
+ gf_log (this->name, GF_LOG_ERROR,
+ "failed to serialize the data");
+
+ goto out;
+ }
+
+ ret = cli_cmd_submit (global_quotad_rpc, &req, frame, &cli_quotad_clnt,
+ GF_AGGREGATOR_GETLIMIT, NULL,
+ this, cli_quotad_getlimit_cbk,
+ (xdrproc_t) xdr_gf_cli_req);
-rm_dir:
- rmdir (mountdir);
out:
+ gf_log ("cli", GF_LOG_DEBUG, "Returning %d", ret);
return ret;
+
+
+}
+
+void
+gf_cli_quota_list (char *volname, dict_t *dict, int count, char *op_errstr,
+ char *default_sl)
+{
+ GF_VALIDATE_OR_GOTO ("cli", volname, out);
+
+ if (!connected)
+ goto out;
+
+ if (count > 0)
+ gf_cli_print_limit_list_from_dict (volname, dict, default_sl,
+ count, op_errstr);
+out:
+ return;
}
int
gf_cli_quota_cbk (struct rpc_req *req, struct iovec *iov,
int count, void *myframe)
{
- gf_cli_rsp rsp = {0,};
- int ret = -1;
- dict_t *dict = NULL;
- char *volname = NULL;
- char *limit_list = NULL;
- int32_t type = 0;
- char msg[1024] = {0,};
- call_frame_t *frame = NULL;
-
+ gf_cli_rsp rsp = {0,};
+ int ret = -1;
+ dict_t *dict = NULL;
+ char *volname = NULL;
+ int32_t type = 0;
+ call_frame_t *frame = NULL;
+ char *default_sl = NULL;
+ char *limit_list = NULL;
+ cli_local_t *local = NULL;
+ dict_t *aggr = NULL;
+ char *default_sl_dup = NULL;
+ int32_t entry_count = 0;
if (-1 == req->rpc_status) {
goto out;
}
frame = myframe;
+ local = frame->local;
+ aggr = local->dict;
ret = xdr_to_generic (*iov, &rsp, (xdrproc_t)xdr_gf_cli_rsp);
if (ret < 0) {
@@ -2420,15 +2633,14 @@ gf_cli_quota_cbk (struct rpc_req *req, struct iovec *iov,
goto out;
}
- if (rsp.op_ret &&
- strcmp (rsp.op_errstr, "") == 0) {
- snprintf (msg, sizeof (msg), "command unsuccessful %s",
- rsp.op_errstr);
+ if (rsp.op_ret && strcmp (rsp.op_errstr, "") == 0) {
+ cli_err ("quota command : failed");
if (global_state->mode & GLUSTER_MODE_XML)
goto xml_output;
goto out;
- }
+ } else if (strcmp (rsp.op_errstr, ""))
+ cli_err ("quota command failed : %s", rsp.op_errstr);
if (rsp.dict.dict_len) {
/* Unserialize the dictionary */
@@ -2438,28 +2650,51 @@ gf_cli_quota_cbk (struct rpc_req *req, struct iovec *iov,
rsp.dict.dict_len,
&dict);
if (ret < 0) {
- gf_log ("glusterd", GF_LOG_ERROR,
+ gf_log ("cli", GF_LOG_ERROR,
"failed to "
"unserialize req-buffer to dictionary");
goto out;
}
}
+ gf_log ("cli", GF_LOG_DEBUG, "Received resp to quota command");
+
ret = dict_get_str (dict, "volname", &volname);
if (ret)
- gf_log (frame->this->name, GF_LOG_TRACE,
+ gf_log (frame->this->name, GF_LOG_ERROR,
"failed to get volname");
- ret = dict_get_str (dict, "limit_list", &limit_list);
+ ret = dict_get_str (dict, "default-soft-limit", &default_sl);
if (ret)
- gf_log (frame->this->name, GF_LOG_TRACE,
- "failed to get limit_list");
+ gf_log (frame->this->name, GF_LOG_TRACE, "failed to get "
+ "default soft limit");
+
+ // default-soft-limit is part of rsp_dict only iff we sent
+ // GLUSTER_CLI_QUOTA with type being GF_QUOTA_OPTION_TYPE_LIST
+ if (default_sl) {
+ default_sl_dup = gf_strdup (default_sl);
+ if (!default_sl_dup) {
+ ret = -1;
+ goto out;
+ }
+ ret = dict_set_dynstr (aggr, "default-soft-limit",
+ default_sl_dup);
+ if (ret) {
+ gf_log (frame->this->name, GF_LOG_TRACE,
+ "failed to set default soft limit");
+ GF_FREE (default_sl_dup);
+ }
+ }
ret = dict_get_int32 (dict, "type", &type);
if (ret)
gf_log (frame->this->name, GF_LOG_TRACE,
"failed to get type");
+ ret = dict_get_int32 (dict, "count", &entry_count);
+ if (ret)
+ gf_log (frame->this->name, GF_LOG_TRACE, "failed to get count");
+
if (type == GF_QUOTA_OPTION_TYPE_LIST) {
if (global_state->mode & GLUSTER_MODE_XML) {
ret = cli_xml_output_vol_quota_limit_list
@@ -2469,31 +2704,15 @@ gf_cli_quota_cbk (struct rpc_req *req, struct iovec *iov,
gf_log ("cli", GF_LOG_ERROR,
"Error outputting to xml");
goto out;
-
}
- if (limit_list) {
- gf_cli_print_limit_list (volname,
- limit_list,
- rsp.op_errstr);
- } else {
- gf_log ("cli", GF_LOG_INFO, "Received resp to quota "
- "command ");
- if (rsp.op_errstr)
- snprintf (msg, sizeof (msg), "%s",
- rsp.op_errstr);
- }
- } else {
- gf_log ("cli", GF_LOG_INFO, "Received resp to quota command ");
- if (rsp.op_errstr)
- snprintf (msg, sizeof (msg), "%s", rsp.op_errstr);
- else
- snprintf (msg, sizeof (msg), "successful");
+ gf_cli_quota_list (volname, dict, entry_count, rsp.op_errstr,
+ default_sl);
}
xml_output:
if (global_state->mode & GLUSTER_MODE_XML) {
- ret = cli_xml_output_str ("volQuota", msg, rsp.op_ret,
+ ret = cli_xml_output_str ("volQuota", NULL, rsp.op_ret,
rsp.op_errno, rsp.op_errstr);
if (ret)
gf_log ("cli", GF_LOG_ERROR,
@@ -2501,12 +2720,8 @@ xml_output:
goto out;
}
- if (strlen (msg) > 0) {
- if (rsp.op_ret)
- cli_err ("%s", msg);
- else
- cli_out ("%s", msg);
- }
+ if (!rsp.op_ret && type != GF_QUOTA_OPTION_TYPE_LIST)
+ cli_out ("volume quota : success");
ret = rsp.op_ret;
out:
@@ -2700,7 +2915,7 @@ gf_cli_list_friends (call_frame_t *frame, xlator_t *this,
flags = (long)data;
req.flags = flags;
frame->local = (void*)flags;
- ret = cli_cmd_submit (&req, frame, cli_rpc_prog,
+ ret = cli_cmd_submit (NULL, &req, frame, cli_rpc_prog,
GLUSTER_CLI_LIST_FRIENDS, NULL,
this, gf_cli_list_friends_cbk,
(xdrproc_t) xdr_gf1_cli_peer_list_req);
@@ -2814,7 +3029,7 @@ gf_cli_get_volume (call_frame_t *frame, xlator_t *this,
ret = dict_allocate_and_serialize (dict, &req.dict.dict_val,
&req.dict.dict_len);
- ret = cli_cmd_submit (&req, frame, cli_rpc_prog,
+ ret = cli_cmd_submit (NULL, &req, frame, cli_rpc_prog,
GLUSTER_CLI_GET_VOLUME, NULL,
this, gf_cli_get_volume_cbk,
(xdrproc_t) xdr_gf_cli_req);
@@ -3033,7 +3248,7 @@ gf_cli_rename_volume (call_frame_t *frame, xlator_t *this,
}
- ret = cli_cmd_submit (&req, frame, cli_rpc_prog,
+ ret = cli_cmd_submit (NULL, &req, frame, cli_rpc_prog,
GLUSTER_CLI_RENAME_VOLUME, NULL,
this, gf_cli_rename_volume_cbk,
(xdrproc_t) xdr_gf_cli_req);
@@ -3385,7 +3600,7 @@ gf_cli_getspec (call_frame_t *frame, xlator_t *this,
goto out;
}
- ret = cli_cmd_submit (&req, frame, &cli_handshake_prog,
+ ret = cli_cmd_submit (NULL, &req, frame, &cli_handshake_prog,
GF_HNDSK_GETSPEC, NULL,
this, gf_cli_getspec_cbk,
(xdrproc_t) xdr_gf_getspec_req);
@@ -3442,7 +3657,7 @@ gf_cli_pmap_b2p (call_frame_t *frame, xlator_t *this, void *data)
if (ret)
goto out;
- ret = cli_cmd_submit (&req, frame, &cli_pmap_prog,
+ ret = cli_cmd_submit (NULL, &req, frame, &cli_pmap_prog,
GF_PMAP_PORTBYBRICK, NULL,
this, gf_cli_pmap_b2p_cbk,
(xdrproc_t) xdr_pmap_port_by_brick_req);
@@ -3557,7 +3772,7 @@ gf_cli_fsm_log (call_frame_t *frame, xlator_t *this, void *data)
if (!frame || !this || !data)
goto out;
req.name = data;
- ret = cli_cmd_submit (&req, frame, cli_rpc_prog,
+ ret = cli_cmd_submit (NULL, &req, frame, cli_rpc_prog,
GLUSTER_CLI_FSM_LOG, NULL,
this, gf_cli_fsm_log_cbk,
(xdrproc_t) xdr_gf1_cli_fsm_log_req);
@@ -5125,7 +5340,7 @@ gf_cli_getwd (call_frame_t *frame, xlator_t *this, void *data)
if (!frame || !this)
goto out;
- ret = cli_cmd_submit (&req, frame, cli_rpc_prog,
+ ret = cli_cmd_submit (NULL, &req, frame, cli_rpc_prog,
GLUSTER_CLI_GETWD, NULL,
this, gf_cli_getwd_cbk,
(xdrproc_t) xdr_gf1_cli_getwd_req);
@@ -6329,7 +6544,8 @@ gf_cli_status_cbk (struct rpc_req *req, struct iovec *iov,
goto out;
}
- if ((cmd & GF_CLI_STATUS_NFS) || (cmd & GF_CLI_STATUS_SHD))
+ if ((cmd & GF_CLI_STATUS_NFS) || (cmd & GF_CLI_STATUS_SHD) ||
+ (cmd & GF_CLI_STATUS_QUOTAD))
notbrick = _gf_true;
if (global_state->mode & GLUSTER_MODE_XML) {
@@ -6444,7 +6660,8 @@ gf_cli_status_cbk (struct rpc_req *req, struct iovec *iov,
*/
memset (status.brick, 0, PATH_MAX + 255);
if (!strcmp (hostname, "NFS Server") ||
- !strcmp (hostname, "Self-heal Daemon"))
+ !strcmp (hostname, "Self-heal Daemon") ||
+ !strcmp (hostname, "Quota Daemon"))
snprintf (status.brick, PATH_MAX + 255, "%s on %s",
hostname, path);
else
@@ -6694,7 +6911,7 @@ gf_cli_mount (call_frame_t *frame, xlator_t *this, void *data)
goto out;
}
- ret = cli_cmd_submit (&req, frame, cli_rpc_prog,
+ ret = cli_cmd_submit (NULL, &req, frame, cli_rpc_prog,
GLUSTER_CLI_MOUNT, NULL,
this, gf_cli_mount_cbk,
(xdrproc_t)xdr_gf1_cli_mount_req);
@@ -6757,7 +6974,7 @@ gf_cli_umount (call_frame_t *frame, xlator_t *this, void *data)
goto out;
}
- ret = cli_cmd_submit (&req, frame, cli_rpc_prog,
+ ret = cli_cmd_submit (NULL, &req, frame, cli_rpc_prog,
GLUSTER_CLI_UMOUNT, NULL,
this, gf_cli_umount_cbk,
(xdrproc_t)xdr_gf1_cli_umount_req);
@@ -7326,7 +7543,7 @@ gf_cli_list_volume (call_frame_t *frame, xlator_t *this, void *data)
if (!frame || !this)
goto out;
- ret = cli_cmd_submit (&req, frame, cli_rpc_prog,
+ ret = cli_cmd_submit (NULL, &req, frame, cli_rpc_prog,
GLUSTER_CLI_LIST_VOLUME, NULL,
this, gf_cli_list_volume_cbk,
(xdrproc_t)xdr_gf_cli_req);
@@ -7499,7 +7716,7 @@ cli_to_glusterd (gf_cli_req *req, call_frame_t *frame,
goto out;
}
- ret = cli_cmd_submit (req, frame, prog, procnum, iobref, this,
+ ret = cli_cmd_submit (NULL, req, frame, prog, procnum, iobref, this,
cbkfn, (xdrproc_t) xdrproc);
out:
@@ -7556,3 +7773,17 @@ struct rpc_clnt_program cli_prog = {
.numproc = GLUSTER_CLI_MAXVALUE,
.proctable = gluster_cli_actors,
};
+
+struct rpc_clnt_procedure cli_quotad_procs[GF_AGGREGATOR_MAXVALUE] = {
+ [GF_AGGREGATOR_NULL] = {"NULL", NULL},
+ [GF_AGGREGATOR_LOOKUP] = {"LOOKUP", NULL},
+ [GF_AGGREGATOR_GETLIMIT] = {"GETLIMIT", cli_quotad_getlimit},
+};
+
+struct rpc_clnt_program cli_quotad_clnt = {
+ .progname = "CLI Quotad client",
+ .prognum = GLUSTER_AGGREGATOR_PROGRAM,
+ .progver = GLUSTER_AGGREGATOR_VERSION,
+ .numproc = GF_AGGREGATOR_MAXVALUE,
+ .proctable = cli_quotad_procs,
+};
diff --git a/cli/src/cli.c b/cli/src/cli.c
index 91b315ff169..67f1ad25793 100644
--- a/cli/src/cli.c
+++ b/cli/src/cli.c
@@ -45,6 +45,7 @@
#endif
#include "cli.h"
+#include "cli-quotad-client.h"
#include "cli-cmd.h"
#include "cli-mem-types.h"
@@ -82,6 +83,7 @@ const char *argp_program_bug_address = "<" PACKAGE_BUGREPORT ">";
+struct rpc_clnt *global_quotad_rpc;
struct rpc_clnt *global_rpc;
rpc_clnt_prog_t *cli_rpc_prog;
@@ -184,7 +186,7 @@ logging_init (glusterfs_ctx_t *ctx, struct cli_state *state)
}
int
-cli_submit_request (void *req, call_frame_t *frame,
+cli_submit_request (struct rpc_clnt *rpc, void *req, call_frame_t *frame,
rpc_clnt_prog_t *prog,
int procnum, struct iobref *iobref,
xlator_t *this, fop_cbk_fn_t cbkfn, xdrproc_t xdrproc)
@@ -229,8 +231,10 @@ cli_submit_request (void *req, call_frame_t *frame,
count = 1;
}
+ if (!rpc)
+ rpc = global_rpc;
/* Send the msg */
- ret = rpc_clnt_submit (global_rpc, prog, procnum, cbkfn,
+ ret = rpc_clnt_submit (rpc, prog, procnum, cbkfn,
&iov, count,
NULL, 0, iobref, frame, NULL, 0, NULL, 0, NULL);
ret = 0;
@@ -491,6 +495,42 @@ _cli_out (const char *fmt, ...)
}
struct rpc_clnt *
+cli_quotad_clnt_rpc_init (void)
+{
+ struct rpc_clnt *rpc = NULL;
+ dict_t *rpc_opts = NULL;
+ int ret = -1;
+
+ rpc_opts = dict_new ();
+ if (!rpc_opts) {
+ ret = -1;
+ goto out;
+ }
+
+ ret = dict_set_str (rpc_opts, "transport.address-family", "unix");
+ if (ret)
+ goto out;
+
+ ret = dict_set_str (rpc_opts, "transport-type", "socket");
+ if (ret)
+ goto out;
+
+ ret = dict_set_str (rpc_opts, "transport.socket.connect-path",
+ "/tmp/quotad.socket");
+ if (ret)
+ goto out;
+
+ rpc = cli_quotad_clnt_init (THIS, rpc_opts);
+ if (!rpc)
+ goto out;
+
+ global_quotad_rpc = rpc;
+out:
+ dict_unref (rpc_opts);
+ return rpc;
+}
+
+struct rpc_clnt *
cli_rpc_init (struct cli_state *state)
{
struct rpc_clnt *rpc = NULL;
@@ -634,6 +674,10 @@ main (int argc, char *argv[])
if (!global_rpc)
goto out;
+ global_quotad_rpc = cli_quotad_clnt_rpc_init ();
+ if (!global_quotad_rpc)
+ goto out;
+
ret = cli_cmds_register (&state);
if (ret)
goto out;
diff --git a/cli/src/cli.h b/cli/src/cli.h
index bc71ee2b4f0..b71140a810b 100644
--- a/cli/src/cli.h
+++ b/cli/src/cli.h
@@ -45,6 +45,13 @@ enum argp_option_keys {
#define GLUSTER_MODE_SCRIPT (1 << 0)
#define GLUSTER_MODE_ERR_FATAL (1 << 1)
#define GLUSTER_MODE_XML (1 << 2)
+
+
+#define GLUSTERFS_GET_AUX_MOUNT_PIDFILE(pidfile,volname) { \
+ snprintf (pidfile, PATH_MAX-1, \
+ DEFAULT_VAR_RUN_DIRECTORY"/%s.pid", volname); \
+ }
+
struct cli_state;
struct cli_cmd_word;
struct cli_cmd_tree;
@@ -212,7 +219,7 @@ int _cli_err (const char *fmt, ...);
} while (0)
int
-cli_submit_request (void *req, call_frame_t *frame,
+cli_submit_request (struct rpc_clnt *rpc, void *req, call_frame_t *frame,
rpc_clnt_prog_t *prog,
int procnum, struct iobref *iobref,
xlator_t *this, fop_cbk_fn_t cbkfn, xdrproc_t xdrproc);