diff options
author | Raghavendra G <rgowdapp@redhat.com> | 2013-11-14 17:05:26 +0530 |
---|---|---|
committer | Anand Avati <avati@redhat.com> | 2013-11-26 10:25:27 -0800 |
commit | 0d5cd92f51c02b8d664000b5a2d22a2ddbbc23b6 (patch) | |
tree | 3410752aa6e3389f33fcb43679318eb159ab2c94 /cli/src | |
parent | ab3ab1978a4768e9eed8e23b47e72b25046e607a (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/src')
-rw-r--r-- | cli/src/Makefile.am | 4 | ||||
-rw-r--r-- | cli/src/cli-cmd-parser.c | 129 | ||||
-rw-r--r-- | cli/src/cli-cmd-volume.c | 354 | ||||
-rw-r--r-- | cli/src/cli-cmd.c | 4 | ||||
-rw-r--r-- | cli/src/cli-cmd.h | 2 | ||||
-rw-r--r-- | cli/src/cli-quotad-client.c | 154 | ||||
-rw-r--r-- | cli/src/cli-quotad-client.h | 33 | ||||
-rw-r--r-- | cli/src/cli-rpc-ops.c | 509 | ||||
-rw-r--r-- | cli/src/cli.c | 48 | ||||
-rw-r--r-- | cli/src/cli.h | 9 |
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); |