From 5757ed2727990fd2c3aaff420003638f1eec6b92 Mon Sep 17 00:00:00 2001 From: Avra Sengupta Date: Wed, 10 Jul 2013 17:32:41 +0530 Subject: glusterd/cli changes for distributed geo-rep Commands: gluster system:: execute gsec_create gluster volume geo-rep create [push-pem] [force] gluster volume geo-rep start [force] gluster volume geo-rep stop [force] gluster volume geo-rep delete gluster volume geo-rep config gluster volume geo-rep status The geo-replication is distributed. The session will be created, and gsyncd will be spawned on all relevant nodes, instead of only one node. geo-rep: Collecting status detail related data Added persistent store for saving information about TotalFilesSynced, TotalSyncTime, TotalBytesSynced Changes in the status information in socket: Existing(Ex): FilesSynced=2;BytesSynced=2507;Uptime=00:26:01; New(Ex): FilesSynced=2;BytesSynced=2507;Uptime=00:26:01;SyncTime=0.69978; TotalSyncTime=2.890044;TotalFilesSynced=6;TotalBytesSynced=143640; Persistent details stored in /var/lib/glusterd/geo-replication/${mastervol}/${eSlave}-detail.status Change-Id: I1db7fc13ffca2e415c05200b0109b1254067f111 BUG: 847839 Original Author: Avra Sengupta Original Author: Venky Shankar Original Author: Aravinda VK Original Author: Amar Tumballi Original Author: Csaba Henk Signed-off-by: Avra Sengupta Reviewed-on: http://review.gluster.org/5132 Reviewed-by: Vijay Bellur Tested-by: Vijay Bellur --- cli/src/cli-cmd-parser.c | 256 ++++++++++++++------- cli/src/cli-cmd-system.c | 147 ++++++++++++ cli/src/cli-cmd-volume.c | 3 +- cli/src/cli-rpc-ops.c | 586 ++++++++++++++++++++++++++++++++++++++++++++--- 4 files changed, 866 insertions(+), 126 deletions(-) (limited to 'cli') diff --git a/cli/src/cli-cmd-parser.c b/cli/src/cli-cmd-parser.c index 484c4a34..c3f2cca9 100644 --- a/cli/src/cli-cmd-parser.c +++ b/cli/src/cli-cmd-parser.c @@ -1595,22 +1595,161 @@ gsyncd_glob_check (const char *w) return !!strpbrk (w, "*?["); } +static int +config_parse (const char **words, int wordcount, dict_t *dict, + unsigned cmdi, unsigned glob) +{ + int32_t ret = -1; + int32_t i = -1; + char *append_str = NULL; + size_t append_len = 0; + char *subop = NULL; + + switch ((wordcount - 1) - cmdi) { + case 0: + subop = gf_strdup ("get-all"); + break; + case 1: + if (words[cmdi + 1][0] == '!') { + (words[cmdi + 1])++; + if (gf_asprintf (&subop, "del%s", + glob ? "-glob" : "") == -1) + subop = NULL; + } else + subop = gf_strdup ("get"); + + ret = dict_set_str (dict, "op_name", ((char *)words[cmdi + 1])); + if (ret < 0) + goto out; + break; + default: + if (gf_asprintf (&subop, "set%s", glob ? "-glob" : "") == -1) + subop = NULL; + + ret = dict_set_str (dict, "op_name", ((char *)words[cmdi + 1])); + if (ret < 0) + goto out; + + /* join the varargs by spaces to get the op_value */ + + for (i = cmdi + 2; i < wordcount; i++) + append_len += (strlen (words[i]) + 1); + /* trailing strcat will add two bytes, make space for that */ + append_len++; + + append_str = GF_CALLOC (1, append_len, cli_mt_append_str); + if (!append_str) { + ret = -1; + goto out; + } + + for (i = cmdi + 2; i < wordcount; i++) { + strcat (append_str, words[i]); + strcat (append_str, " "); + } + append_str[append_len - 2] = '\0'; + /* "checkpoint now" is special: we resolve that "now" */ + if (strcmp (words[cmdi + 1], "checkpoint") == 0 && + strcmp (append_str, "now") == 0) { + struct timeval tv = {0,}; + + ret = gettimeofday (&tv, NULL); + if (ret == -1) + goto out; /* FIXME: free append_str? */ + + GF_FREE (append_str); + append_str = GF_CALLOC (1, 300, cli_mt_append_str); + if (!append_str) { + ret = -1; + goto out; + } + strcpy (append_str, "as of "); + gf_time_fmt (append_str + strlen ("as of "), + 300 - strlen ("as of "), + tv.tv_sec, gf_timefmt_FT); + } + + ret = dict_set_dynstr (dict, "op_value", append_str); + } + + ret = -1; + if (subop) { + ret = dict_set_dynstr (dict, "subop", subop); + if (!ret) + subop = NULL; + } + +out: + if (ret && append_str) + GF_FREE (append_str); + + GF_FREE (subop); + + gf_log ("cli", GF_LOG_DEBUG, "Returning %d", ret); + return ret; +} + +static int32_t +force_push_pem_parse (const char **words, int wordcount, + dict_t *dict, unsigned *cmdi) +{ + int32_t ret = 0; + + if (!strcmp ((char *)words[wordcount-1], "force")) { + if ((strcmp ((char *)words[wordcount-2], "start")) && + (strcmp ((char *)words[wordcount-2], "stop")) && + (strcmp ((char *)words[wordcount-2], "create")) && + (strcmp ((char *)words[wordcount-2], "push-pem"))) { + ret = -1; + goto out; + } + ret = dict_set_uint32 (dict, "force", + _gf_true); + if (ret) + goto out; + (*cmdi)++; + + if (!strcmp ((char *)words[wordcount-2], "push-pem")) { + if (strcmp ((char *)words[wordcount-3], "create")) { + ret = -1; + goto out; + } + ret = dict_set_int32 (dict, "push_pem", 1); + if (ret) + goto out; + (*cmdi)++; + } + } else if (!strcmp ((char *)words[wordcount-1], "push-pem")) { + if (strcmp ((char *)words[wordcount-2], "create")) { + ret = -1; + goto out; + } + ret = dict_set_int32 (dict, "push_pem", 1); + if (ret) + goto out; + (*cmdi)++; + } + +out: + gf_log ("cli", GF_LOG_DEBUG, "Returning %d", ret); + return ret; +} + + int32_t cli_cmd_gsync_set_parse (const char **words, int wordcount, dict_t **options) { int32_t ret = -1; dict_t *dict = NULL; gf1_cli_gsync_set type = GF_GSYNC_OPTION_TYPE_NONE; - char *append_str = NULL; - size_t append_len = 0; - char *subop = NULL; int i = 0; unsigned masteri = 0; unsigned slavei = 0; unsigned glob = 0; unsigned cmdi = 0; - char *opwords[] = { "status", "start", "stop", "config", - "log-rotate", NULL }; + char *opwords[] = { "create", "status", "start", "stop", + "config", "force", "delete", + "push-pem", NULL }; char *w = NULL; GF_ASSERT (words); @@ -1622,10 +1761,11 @@ cli_cmd_gsync_set_parse (const char **words, int wordcount, dict_t **options) /* new syntax: * + * volume geo-replication $m $s create [push-pem] [force] * volume geo-replication [$m [$s]] status * volume geo-replication [$m] $s config [[!]$opt [$val]] - * volume geo-replication $m $s start|stop - * volume geo-replication $m [$s] log-rotate + * volume geo-replication $m $s start|stop [force] + * volume geo-replication $m $s delete */ if (wordcount < 3) @@ -1682,7 +1822,12 @@ cli_cmd_gsync_set_parse (const char **words, int wordcount, dict_t **options) if (!w) goto out; - if (strcmp (w, "status") == 0) { + if (strcmp (w, "create") == 0) { + type = GF_GSYNC_OPTION_TYPE_CREATE; + + if (!masteri || !slavei) + goto out; + } else if (strcmp (w, "status") == 0) { type = GF_GSYNC_OPTION_TYPE_STATUS; if (slavei && !masteri) @@ -1702,14 +1847,18 @@ cli_cmd_gsync_set_parse (const char **words, int wordcount, dict_t **options) if (!masteri || !slavei) goto out; - } else if (strcmp(w, "log-rotate") == 0) { - type = GF_GSYNC_OPTION_TYPE_ROTATE; + } else if (strcmp (w, "delete") == 0) { + type = GF_GSYNC_OPTION_TYPE_DELETE; - if (slavei && !masteri) + if (!masteri || !slavei) goto out; } else GF_ASSERT (!"opword mismatch"); + ret = force_push_pem_parse (words, wordcount, dict, &cmdi); + if (ret) + goto out; + if (type != GF_GSYNC_OPTION_TYPE_CONFIG && (cmdi < wordcount - 1 || glob)) goto out; @@ -1718,97 +1867,26 @@ cli_cmd_gsync_set_parse (const char **words, int wordcount, dict_t **options) ret = 0; - if (masteri) + if (masteri) { ret = dict_set_str (dict, "master", (char *)words[masteri]); + if (!ret) + ret = dict_set_str (dict, "volname", + (char *)words[masteri]); + } if (!ret && slavei) ret = dict_set_str (dict, "slave", (char *)words[slavei]); if (!ret) ret = dict_set_int32 (dict, "type", type); - if (!ret && type == GF_GSYNC_OPTION_TYPE_CONFIG) { - switch ((wordcount - 1) - cmdi) { - case 0: - subop = gf_strdup ("get-all"); - break; - case 1: - if (words[cmdi + 1][0] == '!') { - (words[cmdi + 1])++; - if (gf_asprintf (&subop, "del%s", glob ? "-glob" : "") == -1) - subop = NULL; - } else - subop = gf_strdup ("get"); - - ret = dict_set_str (dict, "op_name", ((char *)words[cmdi + 1])); - if (ret < 0) - goto out; - break; - default: - if (gf_asprintf (&subop, "set%s", glob ? "-glob" : "") == -1) - subop = NULL; - - ret = dict_set_str (dict, "op_name", ((char *)words[cmdi + 1])); - if (ret < 0) - goto out; - - /* join the varargs by spaces to get the op_value */ - - for (i = cmdi + 2; i < wordcount; i++) - append_len += (strlen (words[i]) + 1); - /* trailing strcat will add two bytes, make space for that */ - append_len++; - - append_str = GF_CALLOC (1, append_len, cli_mt_append_str); - if (!append_str) { - ret = -1; - goto out; - } - - for (i = cmdi + 2; i < wordcount; i++) { - strcat (append_str, words[i]); - strcat (append_str, " "); - } - append_str[append_len - 2] = '\0'; - - /* "checkpoint now" is special: we resolve that "now" */ - if (strcmp (words[cmdi + 1], "checkpoint") == 0 && - strcmp (append_str, "now") == 0) { - struct timeval tv = {0,}; - - ret = gettimeofday (&tv, NULL); - if (ret == -1) - goto out; /* FIXME: free append_str? */ - - GF_FREE (append_str); - append_str = GF_CALLOC (1, 300, cli_mt_append_str); - if (!append_str) { - ret = -1; - goto out; - } - strcpy (append_str, "as of "); - gf_time_fmt (append_str + strlen ("as of "), - 300 - strlen ("as of "), - tv.tv_sec, gf_timefmt_FT); - } - - ret = dict_set_dynstr (dict, "op_value", append_str); - } - - ret = -1; - if (subop) { - ret = dict_set_dynstr (dict, "subop", subop); - if (!ret) - subop = NULL; - } - } + if (!ret && type == GF_GSYNC_OPTION_TYPE_CONFIG) + ret = config_parse (words, wordcount, dict, cmdi, glob); out: if (ret) { if (dict) dict_destroy (dict); - GF_FREE (append_str); } else *options = dict; - GF_FREE (subop); return ret; } diff --git a/cli/src/cli-cmd-system.c b/cli/src/cli-cmd-system.c index f73758ae..8cfa5e70 100644 --- a/cli/src/cli-cmd-system.c +++ b/cli/src/cli-cmd-system.c @@ -31,6 +31,12 @@ extern rpc_clnt_prog_t *cli_rpc_prog; int cli_cmd_system_help_cbk (struct cli_state *state, struct cli_cmd_word *in_word, const char **words, int wordcount); +int cli_cmd_copy_file_cbk (struct cli_state *state, struct cli_cmd_word *word, + const char **words, int wordcount); + +int cli_cmd_sys_exec_cbk (struct cli_state *state, struct cli_cmd_word *word, + const char **words, int wordcount); + int cli_cmd_getspec_cbk (struct cli_state *state, struct cli_cmd_word *word, const char **words, int wordcount) @@ -423,9 +429,150 @@ struct cli_cmd cli_system_cmds[] = { cli_cmd_system_help_cbk, "display help for system commands"}, + { "system:: copy file []", + cli_cmd_copy_file_cbk, + "Copy file from current node's $working_dir to " + "$working_dir of all cluster nodes"}, + + { "system:: execute ", + cli_cmd_sys_exec_cbk, + "Execute the command on all the nodes " + "in the cluster and display their output."}, + { NULL, NULL, NULL } }; +int +cli_cmd_sys_exec_cbk (struct cli_state *state, struct cli_cmd_word *word, + const char **words, int wordcount) +{ + char cmd_arg_name[PATH_MAX] = ""; + char *command = NULL; + char *saveptr = NULL; + char *tmp = NULL; + int ret = -1; + int i = -1; + int cmd_args_count = 0; + int in_cmd_args_count = 0; + rpc_clnt_procedure_t *proc = NULL; + call_frame_t *frame = NULL; + dict_t *dict = NULL; + cli_local_t *local = NULL; + + if (wordcount < 3) { + cli_usage_out (word->pattern); + goto out; + } + + dict = dict_new (); + if (!dict) + goto out; + + command = strtok_r ((char *)words[2], " ", &saveptr); + do { + tmp = strtok_r (NULL, " ", &saveptr); + if (tmp) { + in_cmd_args_count++; + memset (cmd_arg_name, '\0', sizeof(cmd_arg_name)); + snprintf (cmd_arg_name, sizeof(cmd_arg_name), + "cmd_arg_%d", in_cmd_args_count); + ret = dict_set_str (dict, cmd_arg_name, tmp); + if (ret) { + gf_log ("", GF_LOG_ERROR, "Unable to set " + "%s in dict", cmd_arg_name); + goto out; + } + } + } while (tmp); + + cmd_args_count = wordcount - 3; + + ret = dict_set_str (dict, "command", command); + if (ret) { + gf_log ("", GF_LOG_ERROR, "Unable to set command in dict"); + goto out; + } + + for (i=1; i <= cmd_args_count; i++) { + in_cmd_args_count++; + memset (cmd_arg_name, '\0', sizeof(cmd_arg_name)); + snprintf (cmd_arg_name, sizeof(cmd_arg_name), + "cmd_arg_%d", in_cmd_args_count); + ret = dict_set_str (dict, cmd_arg_name, + (char *)words[2+i]); + if (ret) { + gf_log ("", GF_LOG_ERROR, "Unable to set %s in dict", + cmd_arg_name); + goto out; + } + } + + ret = dict_set_int32 (dict, "cmd_args_count", in_cmd_args_count); + if (ret) { + gf_log ("", GF_LOG_ERROR, + "Unable to set cmd_args_count in dict"); + goto out; + } + + ret = dict_set_str (dict, "volname", "N/A"); + if (ret) { + gf_log ("", GF_LOG_ERROR, "Unable to set volname in dict"); + goto out; + } + + proc = &cli_rpc_prog->proctable[GLUSTER_CLI_SYS_EXEC]; + if (proc && proc->fn) { + frame = create_frame (THIS, THIS->ctx->pool); + if (!frame) + goto out; + CLI_LOCAL_INIT (local, words, frame, dict); + ret = proc->fn (frame, THIS, (void*)dict); + } +out: + return ret; +} + +int +cli_cmd_copy_file_cbk (struct cli_state *state, struct cli_cmd_word *word, + const char **words, int wordcount) +{ + int ret = -1; + rpc_clnt_procedure_t *proc = NULL; + call_frame_t *frame = NULL; + char *filename = ""; + dict_t *dict = NULL; + cli_local_t *local = NULL; + + if (wordcount != 4) { + cli_usage_out (word->pattern); + goto out; + } + + dict = dict_new (); + if (!dict) + goto out; + + filename = (char*)words[3]; + ret = dict_set_str (dict, "source", filename); + if (ret) + gf_log ("", GF_LOG_ERROR, "Unable to set filename in dict"); + + ret = dict_set_str (dict, "volname", "N/A"); + if (ret) + gf_log ("", GF_LOG_ERROR, "Unable to set volname in dict"); + + proc = &cli_rpc_prog->proctable[GLUSTER_CLI_COPY_FILE]; + if (proc && proc->fn) { + frame = create_frame (THIS, THIS->ctx->pool); + if (!frame) + goto out; + CLI_LOCAL_INIT (local, words, frame, dict); + ret = proc->fn (frame, THIS, (void*)dict); + } +out: + return ret; +} + int cli_cmd_system_help_cbk (struct cli_state *state, struct cli_cmd_word *in_word, const char **words, int wordcount) diff --git a/cli/src/cli-cmd-volume.c b/cli/src/cli-cmd-volume.c index aa1c7755..97a47c2c 100644 --- a/cli/src/cli-cmd-volume.c +++ b/cli/src/cli-cmd-volume.c @@ -1887,7 +1887,8 @@ struct cli_cmd volume_cmds[] = { "reset all the reconfigured options"}, #if (SYNCDAEMON_COMPILE) - {"volume "GEOREP" [] [] {start|stop|config|status|log-rotate} [options...]", + {"volume "GEOREP" [] [] {create [push-pem] [force]" + "|start [force]|stop [force]|config|status|delete} [options...]", cli_cmd_volume_gsync_set_cbk, "Geo-sync operations", cli_cmd_check_gsync_exists_cbk}, diff --git a/cli/src/cli-rpc-ops.c b/cli/src/cli-rpc-ops.c index 28b92ee2..0bab5d42 100644 --- a/cli/src/cli-rpc-ops.c +++ b/cli/src/cli-rpc-ops.c @@ -13,10 +13,6 @@ #include "config.h" #endif -#ifndef GSYNC_CONF -#define GSYNC_CONF GEOREP"/gsyncd.conf" -#endif - /* Widths of various columns in top read/write-perf output * Total width of top read/write-perf should be 80 chars * including one space between column @@ -3745,6 +3741,54 @@ out: return ret; } +static int +gf_cli_get_slave_volname (char *slave, char **slave_vol) +{ + char *tmp = NULL; + char *buf = NULL; + char *save_ptr = NULL; + char *slave_buf = NULL; + int32_t ret = -1; + + GF_ASSERT (slave); + + slave_buf = gf_strdup(slave); + if (!slave_buf) { + gf_log ("", GF_LOG_ERROR, + "Failed to gf_strdup"); + ret = -1; + goto out; + } + + tmp = strtok_r (slave_buf, ":", &save_ptr); + while (tmp) { + buf = tmp; + tmp = strtok_r (NULL, ":", &save_ptr); + } + + if (buf) { + *slave_vol = gf_strdup (buf); + if (!*slave_vol) { + gf_log ("", GF_LOG_ERROR, + "Failed to gf_strdup"); + ret = -1; + goto out; + } + gf_log ("", GF_LOG_DEBUG, "Slave Vol : %s", *slave_vol); + ret = 0; + } else { + gf_log ("", GF_LOG_ERROR, "Invalid slave name"); + goto out; + } + +out: + if (slave_buf) + GF_FREE(slave_buf); + + gf_log ("", GF_LOG_DEBUG, "Returning %d", ret); + return ret; +} + int gf_cli_gsync_config_command (dict_t *dict) { @@ -3752,8 +3796,11 @@ gf_cli_gsync_config_command (dict_t *dict) char *subop = NULL; char *gwd = NULL; char *slave = NULL; + char *slave_vol = NULL; char *master = NULL; char *op_name = NULL; + int ret = -1; + char conf_path[PATH_MAX] = ""; if (dict_get_str (dict, "subop", &subop) != 0) return -1; @@ -3772,9 +3819,21 @@ gf_cli_gsync_config_command (dict_t *dict) if (dict_get_str (dict, "op_name", &op_name) != 0) op_name = NULL; + ret = gf_cli_get_slave_volname (slave, &slave_vol); + if (ret) { + gf_log ("", GF_LOG_ERROR, + "Unable to fetch slave volume name."); + return -1; + } + + ret = snprintf (conf_path, sizeof(conf_path) - 1, + "%s/"GEOREP"/%s-%s/gsyncd.conf", + gwd, master, slave_vol); + conf_path[ret] = '\0'; + runinit (&runner); runner_add_args (&runner, GSYNCD_PREFIX"/gsyncd", "-c", NULL); - runner_argprintf (&runner, "%s/"GSYNC_CONF, gwd); + runner_argprintf (&runner, "%s", conf_path); if (master) runner_argprintf (&runner, ":%s", master); runner_add_arg (&runner, slave); @@ -3785,68 +3844,450 @@ gf_cli_gsync_config_command (dict_t *dict) return runner_run (&runner); } -int -gf_cli_gsync_out_status (dict_t *dict) +static int +gf_cli_fetch_gsyncd_health_uptime (char *status, char **health, char **uptime) { - int gsync_count = 0; - int i = 0; - int ret = 0; - char mst[PATH_MAX] = {0, }; - char slv[PATH_MAX] = {0, }; - char sts[PATH_MAX] = {0, }; - char nds[PATH_MAX] = {0, }; - char hyphens[100] = {0, }; - char *mst_val = NULL; - char *slv_val = NULL; - char *sts_val = NULL; - char *nds_val = NULL; - - cli_out ("%-20s %-20s %-50s %-10s", "NODE", "MASTER", "SLAVE", "STATUS"); - - for (i=0; i spacing [0]) + spacing[0] = strlen (dict_values[j]); + j++; - ret = dict_get_str (dict, mst, &mst_val); + ret = dict_get_str (dict, mst, &dict_values[j]); if (ret) goto out; + if (strlen (dict_values[j]) > spacing [1]) + spacing[1] = strlen (dict_values[j]); + j++; - ret = dict_get_str (dict, slv, &slv_val); + ret = dict_get_str (dict, slv, &dict_values[j]); if (ret) goto out; + if (strlen (dict_values[j]) > spacing [2]) + spacing[2] = strlen (dict_values[j]); + j++; ret = dict_get_str (dict, sts, &sts_val); if (ret) goto out; - cli_out ("%-20s %-20s %-50s %-10s", nds_val, mst_val, - slv_val, sts_val); + /* Fetching health and uptime from sts_val */ + ret = gf_cli_fetch_gsyncd_health_uptime (sts_val, + &dict_values[j], + &dict_values[j+1]); + if (ret) + goto out; + + if (strlen (dict_values[j]) > spacing [3]) + spacing[3] = strlen (dict_values[j]); + j++; + if (strlen (dict_values[j]) > spacing [4]) + spacing[4] = strlen (dict_values[j]); + j++; } - out: + /* calculating spacing for hyphens */ + for (i = 0; i < 5; i++) { + spacing[i] += 3; /* Adding extra space to + distinguish between fields */ + total_spacing += spacing[i]; + } + total_spacing += 4; /* For the spacing between the fields */ + + /* char pointers for each field */ + output_values = GF_CALLOC (5, sizeof (char *), gf_common_mt_char); + if (!output_values) + ret = -1; + for (i = 0; i < 5; i++) { + output_values[i] = GF_CALLOC (spacing[i] + 1, sizeof (char), + gf_common_mt_char); + if (!output_values[i]) + ret = -1; + } + + hyphens = GF_CALLOC (total_spacing + 1, sizeof (char), + gf_common_mt_char); + if (!hyphens) + ret = -1; + + if (ret) { + gf_log ("cli", GF_LOG_ERROR, "Out Of Memory"); + ret = -1; + goto out; + } + + /* setting the title "NODE", "MASTER", etc. from title_values[] + and printing the same */ + for (j = 0; j < 5; j++) { + memset (output_values[j], ' ', spacing[j]); + memcpy (output_values[j], title_values[j], + strlen(title_values[j])); + output_values[j][spacing[j]] = '\0'; + } + cli_out ("%s %s %s %s %s", output_values[0], output_values[1], + output_values[2], output_values[3], output_values[4]); + + /* setting and printing the hyphens */ + memset (hyphens, '-', total_spacing); + hyphens[total_spacing] = '\0'; + cli_out ("%s", hyphens); + + for (i = 1, dict_val_count = 0; i <= gsync_count; i++) { + /* Setting the field values for each row */ + for (j = 0; j < 5; j++) { + memset (output_values[j], ' ', spacing[j]); + memcpy (output_values[j], dict_values[dict_val_count], + strlen(dict_values[dict_val_count])); + output_values[j][spacing[j]] = '\0'; + dict_val_count++; + } + cli_out ("%s %s %s %s %s", output_values[0], output_values[1], + output_values[2], output_values[3], output_values[4]); + } +out: + if (output_values) { + for (i = 0; i < 5; i++) { + if (output_values[i]) + GF_FREE (output_values[i]); + } + GF_FREE (output_values); + } + + if (dict_values) + GF_FREE (dict_values); + + if (hyphens) + GF_FREE (hyphens); + return ret; +} + +static int32_t +write_contents_to_common_pem_file (dict_t *dict, int output_count) +{ + char *workdir = NULL; + char common_pem_file[PATH_MAX] = ""; + char *output = NULL; + char output_name[PATH_MAX] = ""; + int bytes_writen = 0; + int fd = -1; + int ret = -1; + int i = -1; + + ret = dict_get_str (dict, "glusterd_workdir", &workdir); + if (ret || !workdir) { + gf_log ("", GF_LOG_ERROR, "Unable to fetch workdir"); + ret = -1; + goto out; + } + + snprintf (common_pem_file, sizeof(common_pem_file), + "%s/geo-replication/common_secret.pem.pub", + workdir); + + unlink (common_pem_file); + + fd = open (common_pem_file, O_WRONLY | O_CREAT, 0600); + if (fd == -1) { + gf_log ("", GF_LOG_ERROR, "Failed to open %s" + " Error : %s", common_pem_file, + strerror (errno)); + ret = -1; + goto out; + } + + for (i = 1; i <= output_count; i++) { + memset (output_name, '\0', sizeof (output_name)); + snprintf (output_name, sizeof (output_name), + "output_%d", i); + ret = dict_get_str (dict, output_name, &output); + if (ret) { + gf_log ("", GF_LOG_ERROR, "Failed to get %s.", + output_name); + cli_out ("Unable to fetch output."); + } + if (output) { + bytes_writen = write (fd, output, strlen(output)); + if (bytes_writen != strlen(output)) { + gf_log ("", GF_LOG_ERROR, "Failed to write " + "to %s", common_pem_file); + ret = -1; + goto out; + } + /* Adding the new line character */ + bytes_writen = write (fd, "\n", strlen("\n")); + if (bytes_writen != strlen("\n")) { + gf_log ("", GF_LOG_ERROR, + "Failed to add new line char"); + ret = -1; + goto out; + } + output = NULL; + } + } + cli_out ("Common secret pub file present at %s", common_pem_file); + ret = 0; +out: + if (fd) + close (fd); + + gf_log ("", GF_LOG_DEBUG, "Returning %d", ret); + return ret; +} + +int +gf_cli_sys_exec_cbk (struct rpc_req *req, struct iovec *iov, + int count, void *myframe) +{ + int ret = -1; + int output_count = -1; + int i = -1; + char *output = NULL; + char *command = NULL; + char output_name[PATH_MAX] = ""; + gf_cli_rsp rsp = {0, }; + dict_t *dict = NULL; + call_frame_t *frame = NULL; + + if (req->rpc_status == -1) { + ret = -1; + goto out; + } + + 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; + } + + dict = dict_new (); + + if (!dict) { + ret = -1; + goto out; + } + + ret = dict_unserialize (rsp.dict.dict_val, rsp.dict.dict_len, &dict); + + if (ret) + goto out; + + if (rsp.op_ret) { + cli_err ("%s", rsp.op_errstr ? rsp.op_errstr : + "Command failed."); + ret = rsp.op_ret; + goto out; + } + + ret = dict_get_int32 (dict, "output_count", &output_count); + if (ret) { + cli_out ("Command executed successfully."); + ret = 0; + goto out; + } + + ret = dict_get_str (dict, "command", &command); + if (ret) { + gf_log ("", GF_LOG_ERROR, + "Unable to get command from dict"); + goto out; + } + + if (!strcmp (command, "gsec_create")) { + ret = write_contents_to_common_pem_file (dict, output_count); + if (!ret) + goto out; + } + + for (i = 1; i <= output_count; i++) { + memset (output_name, '\0', sizeof (output_name)); + snprintf (output_name, sizeof (output_name), + "output_%d", i); + ret = dict_get_str (dict, output_name, &output); + if (ret) { + gf_log ("", GF_LOG_ERROR, "Failed to get %s.", + output_name); + cli_out ("Unable to fetch output."); + } + if (output) { + cli_out ("%s", output); + output = NULL; + } + } + + ret = 0; +out: + if (dict) + dict_unref (dict); + cli_cmd_broadcast_response (ret); + + free (rsp.dict.dict_val); + + return ret; +} + +int +gf_cli_copy_file_cbk (struct rpc_req *req, struct iovec *iov, + int count, void *myframe) +{ + int ret = -1; + gf_cli_rsp rsp = {0, }; + dict_t *dict = NULL; + call_frame_t *frame = NULL; + + if (req->rpc_status == -1) { + ret = -1; + goto out; + } + + 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; + } + + dict = dict_new (); + + if (!dict) { + ret = -1; + goto out; + } + + ret = dict_unserialize (rsp.dict.dict_val, rsp.dict.dict_len, &dict); + + if (ret) + goto out; + + if (rsp.op_ret) { + cli_err ("%s", rsp.op_errstr ? rsp.op_errstr : + "Copy unsuccessful"); + ret = rsp.op_ret; + goto out; + } + + cli_out ("Successfully copied file."); + +out: + if (dict) + dict_unref (dict); + cli_cmd_broadcast_response (ret); + + free (rsp.dict.dict_val); + + return ret; } int @@ -3861,6 +4302,8 @@ gf_cli_gsync_set_cbk (struct rpc_req *req, struct iovec *iov, char *slave = NULL; int32_t type = 0; call_frame_t *frame = NULL; + gf_boolean_t is_force = _gf_false; + if (req->rpc_status == -1) { ret = -1; @@ -3897,7 +4340,9 @@ gf_cli_gsync_set_cbk (struct rpc_req *req, struct iovec *iov, goto out; } - if (rsp.op_ret) { + is_force = dict_get_str_boolean (dict, "force", _gf_false); + + if (rsp.op_ret && !is_force) { cli_err ("%s", rsp.op_errstr ? rsp.op_errstr : GEOREP" command unsuccessful"); ret = rsp.op_ret; @@ -3937,7 +4382,26 @@ gf_cli_gsync_set_cbk (struct rpc_req *req, struct iovec *iov, case GF_GSYNC_OPTION_TYPE_STATUS: ret = gf_cli_gsync_out_status (dict); - goto out; + break; + + case GF_GSYNC_OPTION_TYPE_DELETE: + if (dict_get_str (dict, "master", &master) != 0) + master = "???"; + if (dict_get_str (dict, "slave", &slave) != 0) + slave = "???"; + cli_out ("Deleting " GEOREP " session between %s & %s" + " has been successful", master, slave); + break; + + case GF_GSYNC_OPTION_TYPE_CREATE: + if (dict_get_str (dict, "master", &master) != 0) + master = "???"; + if (dict_get_str (dict, "slave", &slave) != 0) + slave = "???"; + cli_out ("Creating " GEOREP " session between %s & %s" + " has been successful", master, slave); + break; + default: cli_out (GEOREP" command executed successfully"); } @@ -3952,6 +4416,54 @@ out: return ret; } +int32_t +gf_cli_sys_exec (call_frame_t *frame, xlator_t *this, void *data) +{ + int ret = 0; + dict_t *dict = NULL; + gf_cli_req req = {{0,}}; + + if (!frame || !this || !data) { + ret = -1; + gf_log ("cli", GF_LOG_ERROR, "Invalid data"); + goto out; + } + + dict = data; + + ret = cli_to_glusterd (&req, frame, gf_cli_sys_exec_cbk, + (xdrproc_t) xdr_gf_cli_req, dict, + GLUSTER_CLI_SYS_EXEC, this, cli_rpc_prog, + NULL); +out: + GF_FREE (req.dict.dict_val); + return ret; +} + +int32_t +gf_cli_copy_file (call_frame_t *frame, xlator_t *this, void *data) +{ + int ret = 0; + dict_t *dict = NULL; + gf_cli_req req = {{0,}}; + + if (!frame || !this || !data) { + ret = -1; + gf_log ("cli", GF_LOG_ERROR, "Invalid data"); + goto out; + } + + dict = data; + + ret = cli_to_glusterd (&req, frame, gf_cli_copy_file_cbk, + (xdrproc_t) xdr_gf_cli_req, dict, + GLUSTER_CLI_COPY_FILE, this, cli_rpc_prog, + NULL); +out: + GF_FREE (req.dict.dict_val); + return ret; +} + int32_t gf_cli_gsync_set (call_frame_t *frame, xlator_t *this, void *data) @@ -6822,6 +7334,8 @@ struct rpc_clnt_procedure gluster_cli_actors[GLUSTER_CLI_MAXVALUE] = { [GLUSTER_CLI_STATEDUMP_VOLUME] = {"STATEDUMP_VOLUME", gf_cli_statedump_volume}, [GLUSTER_CLI_LIST_VOLUME] = {"LIST_VOLUME", gf_cli_list_volume}, [GLUSTER_CLI_CLRLOCKS_VOLUME] = {"CLEARLOCKS_VOLUME", gf_cli_clearlocks_volume}, + [GLUSTER_CLI_COPY_FILE] = {"COPY_FILE", gf_cli_copy_file}, + [GLUSTER_CLI_SYS_EXEC] = {"SYS_EXEC", gf_cli_sys_exec}, #ifdef HAVE_BD_XLATOR [GLUSTER_CLI_BD_OP] = {"BD_OP", gf_cli_bd_op}, #endif -- cgit