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 --- .gitignore | 1 + 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 +++- configure.ac | 1 + extras/hook-scripts/Makefile.am | 2 +- .../S56glusterd-geo-rep-create-post.sh | 41 + geo-replication/src/Makefile.am | 6 +- geo-replication/src/gsyncd.c | 6 +- geo-replication/src/peer_add_secret_pub | 3 - geo-replication/src/peer_add_secret_pub.in | 9 + geo-replication/syncdaemon/README.md | 2 +- geo-replication/syncdaemon/gsyncd.py | 7 +- geo-replication/syncdaemon/resource.py | 1 + glusterfs.spec.in | 15 +- rpc/rpc-lib/src/protocol-common.h | 2 + rpc/xdr/src/cli1-xdr.h | 2 + rpc/xdr/src/cli1-xdr.x | 7 +- xlators/mgmt/glusterd/src/glusterd-geo-rep.c | 3611 ++++++++++++++------ xlators/mgmt/glusterd/src/glusterd-handler.c | 2 + xlators/mgmt/glusterd/src/glusterd-hooks.c | 14 + xlators/mgmt/glusterd/src/glusterd-op-sm.c | 47 +- xlators/mgmt/glusterd/src/glusterd-op-sm.h | 6 +- xlators/mgmt/glusterd/src/glusterd-rpc-ops.c | 16 + xlators/mgmt/glusterd/src/glusterd-syncop.c | 165 +- xlators/mgmt/glusterd/src/glusterd-utils.c | 233 +- xlators/mgmt/glusterd/src/glusterd-utils.h | 20 +- xlators/mgmt/glusterd/src/glusterd-volgen.h | 1 + xlators/mgmt/glusterd/src/glusterd.c | 42 +- xlators/mgmt/glusterd/src/glusterd.h | 18 +- 31 files changed, 4092 insertions(+), 1180 deletions(-) create mode 100755 extras/hook-scripts/S56glusterd-geo-rep-create-post.sh delete mode 100644 geo-replication/src/peer_add_secret_pub create mode 100644 geo-replication/src/peer_add_secret_pub.in diff --git a/.gitignore b/.gitignore index bac9ab97d..d3e1a01dd 100644 --- a/.gitignore +++ b/.gitignore @@ -41,3 +41,4 @@ glusterfsd/src/glusterfsd libglusterfs/src/spec.lex.c libglusterfs/src/y.tab.c libglusterfs/src/y.tab.h +libgfchangelog.pc \ No newline at end of file diff --git a/cli/src/cli-cmd-parser.c b/cli/src/cli-cmd-parser.c index 484c4a34b..c3f2cca9b 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 f73758ae3..8cfa5e70c 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 aa1c77553..97a47c2c9 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 28b92ee2f..0bab5d42b 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 diff --git a/configure.ac b/configure.ac index a1a52eebd..0aefdd283 100644 --- a/configure.ac +++ b/configure.ac @@ -30,6 +30,7 @@ AC_CONFIG_FILES([Makefile libglusterfs/Makefile libglusterfs/src/Makefile geo-replication/src/peer_gsec_create + geo-replication/src/peer_add_secret_pub glusterfsd/Makefile glusterfsd/src/Makefile rpc/Makefile diff --git a/extras/hook-scripts/Makefile.am b/extras/hook-scripts/Makefile.am index edfa5a6ac..f6bded20c 100644 --- a/extras/hook-scripts/Makefile.am +++ b/extras/hook-scripts/Makefile.am @@ -1 +1 @@ -EXTRA_DIST = S29CTDBsetup.sh S30samba-start.sh S30samba-stop.sh S30samba-set.sh Sglusterd-geo-rep-create-post.sh +EXTRA_DIST = S29CTDBsetup.sh S30samba-start.sh S30samba-stop.sh S30samba-set.sh S56glusterd-geo-rep-create-post.sh diff --git a/extras/hook-scripts/S56glusterd-geo-rep-create-post.sh b/extras/hook-scripts/S56glusterd-geo-rep-create-post.sh new file mode 100755 index 000000000..71e44b6ed --- /dev/null +++ b/extras/hook-scripts/S56glusterd-geo-rep-create-post.sh @@ -0,0 +1,41 @@ +#!/bin/bash + +key_val_pair1=`echo $2 | cut -d ' ' -f 1` +key_val_pair2=`echo $2 | cut -d ' ' -f 2` +key_val_pair3=`echo $2 | cut -d ' ' -f 3` + +key=`echo $key_val_pair1 | cut -d '=' -f 1` +val=`echo $key_val_pair1 | cut -d '=' -f 2` +if [ "$key" != "is_push_pem" ]; then + exit; +fi +if [ "$val" != '1' ]; then + exit; +fi + +key=`echo $key_val_pair2 | cut -d '=' -f 1` +val=`echo $key_val_pair2 | cut -d '=' -f 2` +if [ "$key" != "pub_file" ]; then + exit; +fi +if [ "$val" == "" ]; then + exit; +fi +pub_file=`echo $val` + +key=`echo $key_val_pair3 | cut -d '=' -f 1` +val=`echo $key_val_pair3 | cut -d '=' -f 2` +if [ "$key" != "slave_ip" ]; then + exit; +fi +if [ "$val" == "" ]; then + exit; +fi +slave_ip=`echo $val` + +if [ -f $pub_file ]; then + ssh $slave_ip "\rm -rf $pub_file" + scp $pub_file $slave_ip:$pub_file &> /dev/null + ssh $slave_ip "gluster system:: copy file /geo-replication/common_secret.pem.pub > /dev/null" + ssh $slave_ip "gluster system:: execute add_secret_pub > /dev/null" +fi diff --git a/geo-replication/src/Makefile.am b/geo-replication/src/Makefile.am index 6feeda8e6..324d8869f 100644 --- a/geo-replication/src/Makefile.am +++ b/geo-replication/src/Makefile.am @@ -3,9 +3,9 @@ gsyncddir = $(libexecdir)/glusterfs gsyncd_SCRIPTS = gverify.sh peer_add_secret_pub peer_gsec_create -# peer_gsec_create is not added to EXTRA_DIST as it's derived -# from a .in file -EXTRA_DIST = gverify.sh peer_add_secret_pub +# peer_gsec_create and peer_add_secret_pub are not added to +# EXTRA_DIST as it's derived from a .in file +EXTRA_DIST = gverify.sh gsyncd_PROGRAMS = gsyncd diff --git a/geo-replication/src/gsyncd.c b/geo-replication/src/gsyncd.c index 68446d9ad..0830e7f9b 100644 --- a/geo-replication/src/gsyncd.c +++ b/geo-replication/src/gsyncd.c @@ -37,7 +37,7 @@ #define _GLUSTERD_CALLED_ "_GLUSTERD_CALLED_" #define _GSYNCD_DISPATCHED_ "_GSYNCD_DISPATCHED_" -#define GSYNCD_CONF "geo-replication/gsyncd.conf" +#define GSYNCD_CONF_TEMPLATE "geo-replication/gsyncd_template.conf" #define GSYNCD_PY "gsyncd.py" #define RSYNC "rsync" @@ -127,11 +127,11 @@ invoke_gsyncd (int argc, char **argv) gluster_workdir_len = len - 1; if (gluster_workdir_len) { - if (gluster_workdir_len + 1 + strlen (GSYNCD_CONF) + 1 > + if (gluster_workdir_len + 1 + strlen (GSYNCD_CONF_TEMPLATE) + 1 > PATH_MAX) goto error; config_file[gluster_workdir_len] = '/'; - strcat (config_file, GSYNCD_CONF); + strcat (config_file, GSYNCD_CONF_TEMPLATE); } else goto error; diff --git a/geo-replication/src/peer_add_secret_pub b/geo-replication/src/peer_add_secret_pub deleted file mode 100644 index 1ce040d44..000000000 --- a/geo-replication/src/peer_add_secret_pub +++ /dev/null @@ -1,3 +0,0 @@ -#!/bin/bash - -cat $1 >> ~/.ssh/authorized_keys diff --git a/geo-replication/src/peer_add_secret_pub.in b/geo-replication/src/peer_add_secret_pub.in new file mode 100644 index 000000000..c036cf334 --- /dev/null +++ b/geo-replication/src/peer_add_secret_pub.in @@ -0,0 +1,9 @@ +#!/bin/bash + +if [ ! -d ~/.ssh ]; then + mkdir ~/.ssh; + chmod 700 ~/.ssh + chown root:root ~/.ssh +fi + +cat "$GLUSTERD_WORKING_DIR"/geo-replication/common_secret.pem.pub >> ~/.ssh/authorized_keys diff --git a/geo-replication/syncdaemon/README.md b/geo-replication/syncdaemon/README.md index 0eb15fa71..67f346ace 100644 --- a/geo-replication/syncdaemon/README.md +++ b/geo-replication/syncdaemon/README.md @@ -39,7 +39,7 @@ The config file format matches the following syntax: : # comment -By default (unless specified by the option `-c`), gsyncd looks for config file at _conf/gsyncd.conf_ +By default (unless specified by the option `-c`), gsyncd looks for config file at _conf/gsyncd_template.conf_ in the source tree. USAGE diff --git a/geo-replication/syncdaemon/gsyncd.py b/geo-replication/syncdaemon/gsyncd.py index ad498c39c..67ba07370 100644 --- a/geo-replication/syncdaemon/gsyncd.py +++ b/geo-replication/syncdaemon/gsyncd.py @@ -346,10 +346,9 @@ def main_i(): for name in rmap[x]: for j in range(3): namedict[mods[j](name)] = pa[j][i] - if x.scheme == 'gluster': - namedict[name + 'vol'] = x.volume + namedict[name + 'vol'] = x.volume if not 'config_file' in rconf: - rconf['config_file'] = os.path.join(os.path.dirname(sys.argv[0]), "conf/gsyncd.conf") + rconf['config_file'] = os.path.join(os.path.dirname(sys.argv[0]), "conf/gsyncd_template.conf") gcnf = GConffile(rconf['config_file'], canon_peers, defaults.__dict__, opts.__dict__, namedict) checkpoint_change = False @@ -399,6 +398,8 @@ def main_i(): if getattr(gconf, 'state_socket_unencoded', None): cleanup_paths.append(gconf.state_socket_unencoded) + cleanup_paths.append(rconf['config_file'][:-11] + "*"); + # Cleanup changelog working dirs if getattr(gconf, 'working_dir', None): try: diff --git a/geo-replication/syncdaemon/resource.py b/geo-replication/syncdaemon/resource.py index 52989fe28..4b0183b98 100644 --- a/geo-replication/syncdaemon/resource.py +++ b/geo-replication/syncdaemon/resource.py @@ -1056,6 +1056,7 @@ class SSH(AbstractUrl, SlaveRemote): self.remote_addr, inner_url = sup(self, path, '^((?:%s@)?%s):(.+)' % tuple([ r.pattern for r in (UserRX, HostRX) ])) self.inner_rsc = parse_url(inner_url) + self.volume = inner_url[1:] @staticmethod def parse_ssh_address(addr): diff --git a/glusterfs.spec.in b/glusterfs.spec.in index e92cd6e0a..b5f2d45f9 100644 --- a/glusterfs.spec.in +++ b/glusterfs.spec.in @@ -431,7 +431,7 @@ sed -i 's|option working-directory /etc/glusterd|option working-directory %{_sha %if ( 0%{!?_without_georeplication:1} ) # geo-rep ghosts %{__mkdir_p} %{buildroot}%{_sharedstatedir}/glusterd/geo-replication -touch %{buildroot}%{_sharedstatedir}/glusterd/geo-replication/gsyncd.conf +touch %{buildroot}%{_sharedstatedir}/glusterd/geo-replication/gsyncd_template.conf %endif # the rest of the ghosts @@ -460,6 +460,12 @@ touch %{buildroot}%{_sharedstatedir}/glusterd/options %{__mkdir_p} %{buildroot}%{_sharedstatedir}/glusterd/hooks/1/delete %{__mkdir_p} %{buildroot}%{_sharedstatedir}/glusterd/hooks/1/delete/post %{__mkdir_p} %{buildroot}%{_sharedstatedir}/glusterd/hooks/1/delete/pre +%{__mkdir_p} %{buildroot}%{_sharedstatedir}/glusterd/hooks/1/copy-file +%{__mkdir_p} %{buildroot}%{_sharedstatedir}/glusterd/hooks/1/copy-file/post +%{__mkdir_p} %{buildroot}%{_sharedstatedir}/glusterd/hooks/1/copy-file/pre +%{__mkdir_p} %{buildroot}%{_sharedstatedir}/glusterd/hooks/1/gsync-create +%{__mkdir_p} %{buildroot}%{_sharedstatedir}/glusterd/hooks/1/gsync-create/post +%{__mkdir_p} %{buildroot}%{_sharedstatedir}/glusterd/hooks/1/gsync-create/pre %{__mkdir_p} %{buildroot}%{_sharedstatedir}/glusterd/glustershd %{__mkdir_p} %{buildroot}%{_sharedstatedir}/glusterd/peers %{__mkdir_p} %{buildroot}%{_sharedstatedir}/glusterd/vols @@ -521,8 +527,10 @@ fi %{_libexecdir}/glusterfs/gsyncd %{_libexecdir}/glusterfs/python/syncdaemon/* %{_libexecdir}/glusterfs/gverify.sh +%{_libexecdir}/glusterfs/peer_add_secret_pub +%{_libexecdir}/glusterfs/peer_gsec_create %ghost %dir %attr(0755,-,-) %{_sharedstatedir}/glusterd/geo-replication -%ghost %attr(0644,-,-) %{_sharedstatedir}/glusterd/geo-replication/gsyncd.conf +%ghost %attr(0644,-,-) %{_sharedstatedir}/glusterd/geo-replication/gsyncd_template.conf %endif %files fuse @@ -697,6 +705,9 @@ if [ $1 -ge 1 ]; then fi %changelog +* Thu Jul 25 2013 Csaba Henk +- Added peer_add_secret_pub and peer_gsec_create to %{_libexecdir}/glusterfs + * Thu Jul 25 2013 Aravinda VK - Added gverify.sh to %{_libexecdir}/glusterfs directory. diff --git a/rpc/rpc-lib/src/protocol-common.h b/rpc/rpc-lib/src/protocol-common.h index b80a52bb6..704b1540a 100644 --- a/rpc/rpc-lib/src/protocol-common.h +++ b/rpc/rpc-lib/src/protocol-common.h @@ -158,6 +158,8 @@ enum gluster_cli_procnum { GLUSTER_CLI_UUID_RESET, GLUSTER_CLI_BD_OP, GLUSTER_CLI_UUID_GET, + GLUSTER_CLI_COPY_FILE, + GLUSTER_CLI_SYS_EXEC, GLUSTER_CLI_MAXVALUE, }; diff --git a/rpc/xdr/src/cli1-xdr.h b/rpc/xdr/src/cli1-xdr.h index e80d6f70c..20787c494 100644 --- a/rpc/xdr/src/cli1-xdr.h +++ b/rpc/xdr/src/cli1-xdr.h @@ -121,6 +121,8 @@ enum gf1_cli_gsync_set { GF_GSYNC_OPTION_TYPE_CONFIG = 3, GF_GSYNC_OPTION_TYPE_STATUS = 4, GF_GSYNC_OPTION_TYPE_ROTATE = 5, + GF_GSYNC_OPTION_TYPE_CREATE = 6, + GF_GSYNC_OPTION_TYPE_DELETE = 7, }; typedef enum gf1_cli_gsync_set gf1_cli_gsync_set; diff --git a/rpc/xdr/src/cli1-xdr.x b/rpc/xdr/src/cli1-xdr.x index 0bee19679..b85ecf87a 100644 --- a/rpc/xdr/src/cli1-xdr.x +++ b/rpc/xdr/src/cli1-xdr.x @@ -51,7 +51,8 @@ enum gf_quota_type { }; enum gf1_cli_friends_list { - GF_CLI_LIST_ALL = 1 + GF_CLI_LIST_PEERS = 1, + GF_CLI_LIST_POOL_NODES = 2 } ; enum gf1_cli_get_volume { @@ -74,7 +75,9 @@ enum gf1_cli_gsync_set { GF_GSYNC_OPTION_TYPE_STOP, GF_GSYNC_OPTION_TYPE_CONFIG, GF_GSYNC_OPTION_TYPE_STATUS, - GF_GSYNC_OPTION_TYPE_ROTATE + GF_GSYNC_OPTION_TYPE_ROTATE, + GF_GSYNC_OPTION_TYPE_DELETE, + GF_GSYNC_OPTION_TYPE_CREATE }; enum gf1_cli_stats_op { diff --git a/xlators/mgmt/glusterd/src/glusterd-geo-rep.c b/xlators/mgmt/glusterd/src/glusterd-geo-rep.c index 6440efa15..29a20f507 100644 --- a/xlators/mgmt/glusterd/src/glusterd-geo-rep.c +++ b/xlators/mgmt/glusterd/src/glusterd-geo-rep.c @@ -25,6 +25,24 @@ #include +static int +dict_get_param (dict_t *dict, char *key, char **param); + +static int +glusterd_get_statefile_name (glusterd_volinfo_t *volinfo, char *slave, + char *conf_path, char **statefile); + +static int +glusterd_get_slave_details_confpath (glusterd_volinfo_t *volinfo, dict_t *dict, + char **slave_ip, char **slave_vol, + char **conf_path); + +static int +glusterd_get_slave_info (dict_t *dict, char **slave_ip, char **slave_vol); + +static int +glusterd_gsync_read_frm_status (char *path, char *buf, size_t blen); + static char *gsync_reserved_opts[] = { "gluster-command-dir", "pid-file", @@ -40,6 +58,148 @@ static char *gsync_reserved_opts[] = { NULL }; +int +__glusterd_handle_sys_exec (rpcsvc_request_t *req) +{ + int32_t ret = 0; + dict_t *dict = NULL; + gf_cli_req cli_req = {{0},}; + glusterd_op_t cli_op = GD_OP_SYS_EXEC; + glusterd_conf_t *priv = NULL; + char *host_uuid = NULL; + char err_str[2048] = {0,}; + xlator_t *this = NULL; + + GF_ASSERT (req); + + this = THIS; + GF_ASSERT (this); + priv = this->private; + GF_ASSERT (priv); + + ret = xdr_to_generic (req->msg[0], &cli_req, + (xdrproc_t)xdr_gf_cli_req); + if (ret < 0) { + req->rpc_err = GARBAGE_ARGS; + goto out; + } + + if (cli_req.dict.dict_len) { + dict = dict_new (); + if (!dict) + goto out; + + + ret = dict_unserialize (cli_req.dict.dict_val, + cli_req.dict.dict_len, + &dict); + if (ret < 0) { + gf_log (this->name, GF_LOG_ERROR, "failed to " + "unserialize req-buffer to dictionary"); + snprintf (err_str, sizeof (err_str), "Unable to decode " + "the command"); + goto out; + } else { + dict->extra_stdfree = cli_req.dict.dict_val; + } + + host_uuid = gf_strdup (uuid_utoa(MY_UUID)); + if (host_uuid == NULL) { + snprintf (err_str, sizeof (err_str), "Failed to get " + "the uuid of local glusterd"); + ret = -1; + goto out; + } + + ret = dict_set_dynstr (dict, "host-uuid", host_uuid); + if (ret) + goto out; + } + + ret = glusterd_op_begin_synctask (req, cli_op, dict); + +out: + if (ret) { + if (err_str[0] == '\0') + snprintf (err_str, sizeof (err_str), + "Operation failed"); + ret = glusterd_op_send_cli_response (cli_op, ret, 0, req, + dict, err_str); + } + return ret; +} + +int +__glusterd_handle_copy_file (rpcsvc_request_t *req) +{ + int32_t ret = 0; + dict_t *dict = NULL; + gf_cli_req cli_req = {{0},}; + glusterd_op_t cli_op = GD_OP_COPY_FILE; + glusterd_conf_t *priv = NULL; + char *host_uuid = NULL; + char err_str[2048] = {0,}; + xlator_t *this = NULL; + + GF_ASSERT (req); + + this = THIS; + GF_ASSERT (this); + priv = this->private; + GF_ASSERT (priv); + + ret = xdr_to_generic (req->msg[0], &cli_req, + (xdrproc_t)xdr_gf_cli_req); + if (ret < 0) { + req->rpc_err = GARBAGE_ARGS; + goto out; + } + + if (cli_req.dict.dict_len) { + dict = dict_new (); + if (!dict) + goto out; + + + ret = dict_unserialize (cli_req.dict.dict_val, + cli_req.dict.dict_len, + &dict); + if (ret < 0) { + gf_log (this->name, GF_LOG_ERROR, "failed to " + "unserialize req-buffer to dictionary"); + snprintf (err_str, sizeof (err_str), "Unable to decode " + "the command"); + goto out; + } else { + dict->extra_stdfree = cli_req.dict.dict_val; + } + + host_uuid = gf_strdup (uuid_utoa(MY_UUID)); + if (host_uuid == NULL) { + snprintf (err_str, sizeof (err_str), "Failed to get " + "the uuid of local glusterd"); + ret = -1; + goto out; + } + + ret = dict_set_dynstr (dict, "host-uuid", host_uuid); + if (ret) + goto out; + } + + ret = glusterd_op_begin_synctask (req, cli_op, dict); + +out: + if (ret) { + if (err_str[0] == '\0') + snprintf (err_str, sizeof (err_str), + "Operation failed"); + ret = glusterd_op_send_cli_response (cli_op, ret, 0, req, + dict, err_str); + } + return ret; +} + int __glusterd_handle_gsync_set (rpcsvc_request_t *req) { @@ -104,13 +264,13 @@ __glusterd_handle_gsync_set (rpcsvc_request_t *req) ret = dict_get_str (dict, "master", &master); if (ret < 0) { gf_log (this->name, GF_LOG_INFO, "master not found, while " - "handling"GEOREP" options"); + "handling "GEOREP" options"); master = "(No Master)"; } ret = dict_get_str (dict, "slave", &slave); if (ret < 0) { - gf_log (this->name, GF_LOG_INFO, "slave not not found, while" + gf_log (this->name, GF_LOG_INFO, "slave not found, while" "handling "GEOREP" options"); slave = "(No Slave)"; } @@ -124,6 +284,10 @@ __glusterd_handle_gsync_set (rpcsvc_request_t *req) } switch (type) { + case GF_GSYNC_OPTION_TYPE_CREATE: + strncpy (operation, "create", sizeof (operation)); + cli_op = GD_OP_GSYNC_CREATE; + break; case GF_GSYNC_OPTION_TYPE_START: strncpy (operation, "start", sizeof (operation)); @@ -140,12 +304,9 @@ __glusterd_handle_gsync_set (rpcsvc_request_t *req) case GF_GSYNC_OPTION_TYPE_STATUS: strncpy (operation, "status", sizeof (operation)); break; - case GF_GSYNC_OPTION_TYPE_ROTATE: - strncpy (operation, "rotate", sizeof(operation)); - break; } - ret = glusterd_op_begin_synctask (req, GD_OP_GSYNC_SET, dict); + ret = glusterd_op_begin_synctask (req, cli_op, dict); out: if (ret) { @@ -158,6 +319,17 @@ out: return ret; } +int +glusterd_handle_sys_exec (rpcsvc_request_t *req) +{ + return glusterd_big_locked_handler (req, __glusterd_handle_sys_exec); +} + +int +glusterd_handle_copy_file (rpcsvc_request_t *req) +{ + return glusterd_big_locked_handler (req, __glusterd_handle_copy_file); +} int glusterd_handle_gsync_set (rpcsvc_request_t *req) @@ -448,7 +620,7 @@ _fcbk_conftodict (char *resbuf, size_t blen, FILE *fp, void *data) } static int -glusterd_gsync_get_config (char *master, char *slave, char *gl_workdir, dict_t *dict) +glusterd_gsync_get_config (char *master, char *slave, char *conf_path, dict_t *dict) { /* key + value, where value must be able to accommodate a path */ char resbuf[256 + PATH_MAX] = {0,}; @@ -456,7 +628,7 @@ glusterd_gsync_get_config (char *master, char *slave, char *gl_workdir, dict_t * runinit (&runner); runner_add_args (&runner, GSYNCD_PREFIX"/gsyncd", "-c", NULL); - runner_argprintf (&runner, "%s/"GSYNC_CONF, gl_workdir); + runner_argprintf (&runner, "%s", conf_path); runner_argprintf (&runner, ":%s", master); runner_add_args (&runner, slave, "--config-get-all", NULL); @@ -466,13 +638,13 @@ glusterd_gsync_get_config (char *master, char *slave, char *gl_workdir, dict_t * static int glusterd_gsync_get_param_file (char *prmfile, const char *param, char *master, - char *slave, char *gl_workdir) + char *slave, char *conf_path) { runner_t runner = {0,}; runinit (&runner); runner_add_args (&runner, GSYNCD_PREFIX"/gsyncd", "-c", NULL); - runner_argprintf (&runner, "%s/"GSYNC_CONF, gl_workdir); + runner_argprintf (&runner, "%s", conf_path); runner_argprintf (&runner, ":%s", master); runner_add_args (&runner, slave, "--config-get", NULL); runner_argprintf (&runner, "%s-file", param); @@ -481,83 +653,14 @@ glusterd_gsync_get_param_file (char *prmfile, const char *param, char *master, } static int -glusterd_gsync_get_session_owner (char *master, char *slave, char *session_owner, - char *gl_workdir) -{ - runner_t runner = {0,}; - - runinit(&runner); - runner_add_args (&runner, GSYNCD_PREFIX"/gsyncd", "-c", NULL); - runner_argprintf (&runner, "%s/"GSYNC_CONF, gl_workdir); - runner_argprintf (&runner, ":%s", master); - runner_add_args (&runner, slave, "--config-get", "session-owner", - NULL); - - return glusterd_query_extutil (session_owner, &runner); -} - -/* check whether @slave is local or remote. normalized - * urls starting with ssh are considered to be remote - * @returns - * 1 if slave is remote - * 0 is slave is local - */ -static int -glusterd_gsync_slave_is_remote (char *slave) -{ - int ret = 0; - char *ssh_pos = NULL; - - ssh_pos = strstr(slave, "ssh://"); - if ( ssh_pos && ((ssh_pos - slave) == 0) ) - ret = 1; - - return ret; -} - -static int -glusterd_gsync_get_slave_log_file (char *master, char *slave, char *log_file) -{ - int ret = -1; - runner_t runner = {0,}; - char uuid_str[64] = {0,}; - glusterd_conf_t *priv = NULL; - char *gl_workdir = NULL; - - GF_ASSERT(THIS); - GF_ASSERT(THIS->private); - - priv = THIS->private; - - GF_VALIDATE_OR_GOTO("gsyncd", master, out); - GF_VALIDATE_OR_GOTO("gsyncd", slave, out); - - gl_workdir = priv->workdir; - - /* get the session owner for the master-slave session */ - ret = glusterd_gsync_get_session_owner (master, slave, uuid_str, - gl_workdir); - if (ret) - goto out; - - /* get the log file for the slave */ - runinit(&runner); - runner_add_args (&runner, GSYNCD_PREFIX"/gsyncd", "-c", NULL); - runner_argprintf (&runner, "%s/"GSYNC_CONF, gl_workdir); - runner_argprintf (&runner, "--session-owner=%s", uuid_str); - runner_add_args (&runner, slave, "--config-get", "log-file", NULL); - - ret = glusterd_query_extutil (log_file, &runner); - - out: - return ret; -} - -static int -gsyncd_getpidfile (char *master, char *slave, char *pidfile) +gsyncd_getpidfile (char *master, char *slave, char *pidfile, char *conf_path) { int ret = -1; glusterd_conf_t *priv = NULL; + char *confpath = NULL; + char conf_buf[PATH_MAX] = ""; + struct stat stbuf = {0,}; + GF_ASSERT (THIS); GF_ASSERT (THIS->private); @@ -567,8 +670,22 @@ gsyncd_getpidfile (char *master, char *slave, char *pidfile) GF_VALIDATE_OR_GOTO ("gsync", master, out); GF_VALIDATE_OR_GOTO ("gsync", slave, out); + ret = lstat (conf_path, &stbuf); + if (!ret) { + gf_log ("", GF_LOG_DEBUG, "Using passed config template(%s).", + conf_path); + confpath = conf_path; + } else { + ret = snprintf (conf_buf, sizeof(conf_buf) - 1, + "%s/"GSYNC_CONF_TEMPLATE, priv->workdir); + conf_buf[ret] = '\0'; + confpath = conf_buf; + gf_log ("", GF_LOG_DEBUG, "Using default config template(%s).", + confpath); + } + ret = glusterd_gsync_get_param_file (pidfile, "pid", master, - slave, priv->workdir); + slave, confpath); if (ret == -1) { ret = -2; gf_log ("", GF_LOG_WARNING, "failed to create the pidfile string"); @@ -581,32 +698,6 @@ gsyncd_getpidfile (char *master, char *slave, char *pidfile) return ret; } -static int -glusterd_gsyncd_getlogfile (char *master, char *slave, char *log_file) -{ - int ret = -1; - glusterd_conf_t *priv = NULL; - - GF_ASSERT (THIS); - GF_ASSERT (THIS->private); - - priv = THIS->private; - - GF_VALIDATE_OR_GOTO ("gsync", master, out); - GF_VALIDATE_OR_GOTO ("gsync", slave, out); - - ret = glusterd_gsync_get_param_file (log_file, "log", master, - slave, priv->workdir); - if (ret == -1) { - ret = -2; - gf_log ("", GF_LOG_WARNING, "failed to gsyncd logfile"); - goto out; - } - - out: - return ret; -} - static int gsync_status_byfd (int fd) { @@ -624,12 +715,12 @@ gsync_status_byfd (int fd) * return -1 when not running */ int -gsync_status (char *master, char *slave, int *status) +gsync_status (char *master, char *slave, char *conf_path, int *status) { char pidfile[PATH_MAX] = {0,}; int fd = -1; - fd = gsyncd_getpidfile (master, slave, pidfile); + fd = gsyncd_getpidfile (master, slave, pidfile, conf_path); if (fd == -2) return -1; @@ -666,10 +757,38 @@ out: } static int -gsync_verify_config_options (dict_t *dict, char **op_errstr) +glusterd_verify_gsyncd_spawn (char *master, char *slave) +{ + int ret = 0; + runner_t runner = {0,}; + + runinit (&runner); + runner_add_args (&runner, GSYNCD_PREFIX"/gsyncd", + "--verify", "spawning", NULL); + runner_argprintf (&runner, ":%s", master); + runner_add_args (&runner, slave, NULL); + runner_redir (&runner, STDOUT_FILENO, RUN_PIPE); + ret = runner_start (&runner); + if (ret) { + gf_log ("", GF_LOG_ERROR, "spawning child failed"); + ret = -1; + goto out; + } + + if (runner_end (&runner) != 0) + ret = -1; + +out: + gf_log ("", GF_LOG_DEBUG, "returning %d", ret); + return ret; +} + +static int +gsync_verify_config_options (dict_t *dict, char **op_errstr, char *volname) { char **resopt = NULL; int i = 0; + int ret = -1; char *subop = NULL; char *slave = NULL; char *op_name = NULL; @@ -699,6 +818,12 @@ gsync_verify_config_options (dict_t *dict, char **op_errstr) } if (runcmd (GSYNCD_PREFIX"/gsyncd", "--config-check", op_name, NULL)) { + ret = glusterd_verify_gsyncd_spawn (volname, slave); + if (ret) { + gf_log ("", GF_LOG_ERROR, "Unable to spawn gsyncd"); + return 0; + } + gf_log ("", GF_LOG_WARNING, "Invalid option %s", op_name); *op_errstr = gf_strdup ("Invalid option"); @@ -748,30 +873,76 @@ gsync_verify_config_options (dict_t *dict, char **op_errstr) static int glusterd_get_gsync_status_mst_slv (glusterd_volinfo_t *volinfo, - char *slave, dict_t *rsp_dict, char *node); + char *slave, char *conf_path, + dict_t *rsp_dict, char *node); static int _get_status_mst_slv (dict_t *this, char *key, data_t *value, void *data) { glusterd_gsync_status_temp_t *param = NULL; char *slave = NULL; - int ret = 0; + char *slave_buf = NULL; + char *slave_vol = NULL; + char *tmp = NULL; + char *save_ptr = NULL; + char conf_path[PATH_MAX] = ""; + int ret = -1; + glusterd_conf_t *priv = NULL; param = (glusterd_gsync_status_temp_t *)data; GF_ASSERT (param); GF_ASSERT (param->volinfo); + if (THIS) + priv = THIS->private; + if (priv == NULL) { + gf_log ("", GF_LOG_ERROR, "priv of glusterd not present"); + goto out; + } + slave = strchr(value->data, ':'); - if (slave) + if (slave) { slave ++; - else + slave_buf = gf_strdup (slave); + if (!slave_buf) { + gf_log ("", GF_LOG_ERROR, + "Failed to gf_strdup"); + ret = -1; + goto out; + } + } else return 0; + tmp = strtok_r (slave_buf, ":", &save_ptr); + while (tmp) { + slave_vol = tmp; + tmp = strtok_r (NULL, ":", &save_ptr); + } + + if (!slave_vol) { + gf_log ("", GF_LOG_ERROR, "Invalid slave name"); + ret = -1; + goto out; + } + + ret = snprintf (conf_path, sizeof(conf_path) - 1, + "%s/"GEOREP"/%s-%s/gsyncd.conf", + priv->workdir, param->volinfo->volname, + slave_vol); + conf_path[ret] = '\0'; + ret = glusterd_get_gsync_status_mst_slv(param->volinfo, - slave, param->rsp_dict, + slave, conf_path, + param->rsp_dict, param->node); - return 0; +out: + + if (slave_buf) + GF_FREE(slave_buf); + + gf_log ("", GF_LOG_DEBUG, "Returning %d.", ret); + return ret; } @@ -792,19 +963,22 @@ static int glusterd_remove_slave_in_info (glusterd_volinfo_t *volinfo, char *slave, char **op_errstr) { + int zero_slave_entries = _gf_true; int ret = 0; char *slavekey = NULL; GF_ASSERT (volinfo); GF_ASSERT (slave); - ret = glusterd_get_slave (volinfo, slave, &slavekey); - if (ret < 0) { - ret++; - goto out; - } - - dict_del (volinfo->gsync_slaves, slavekey); + do { + ret = glusterd_get_slave (volinfo, slave, &slavekey); + if (ret < 0 && zero_slave_entries) { + ret++; + goto out; + } + zero_slave_entries = _gf_false; + dict_del (volinfo->gsync_slaves, slavekey); + } while (ret >= 0); ret = glusterd_store_volinfo (volinfo, GLUSTERD_VOLINFO_VER_AC_INCREMENT); @@ -859,6 +1033,7 @@ glusterd_gsync_get_uuid (char *slave, glusterd_volinfo_t *vol, static int glusterd_check_gsync_running_local (char *master, char *slave, + char *conf_path, gf_boolean_t *is_run) { int ret = -1; @@ -869,7 +1044,7 @@ glusterd_check_gsync_running_local (char *master, char *slave, GF_ASSERT (is_run); *is_run = _gf_false; - ret = gsync_status (master, slave, &ret_status); + ret = gsync_status (master, slave, conf_path, &ret_status); if (ret == 0 && ret_status == 0) { *is_run = _gf_true; } else if (ret == -1) { @@ -886,7 +1061,8 @@ glusterd_check_gsync_running_local (char *master, char *slave, static int glusterd_store_slave_in_info (glusterd_volinfo_t *volinfo, char *slave, - char *host_uuid, char **op_errstr) + char *host_uuid, char **op_errstr, + gf_boolean_t is_force) { int ret = 0; int maxslv = 0; @@ -909,7 +1085,8 @@ glusterd_store_slave_in_info (glusterd_volinfo_t *volinfo, char *slave, case -1: break; default: - GF_ASSERT (ret > 0); + if (!is_force) + GF_ASSERT (ret > 0); ret = dict_get_str (volinfo->gsync_slaves, slavekey, &slaveentry); GF_ASSERT (ret == 0); @@ -918,13 +1095,23 @@ glusterd_store_slave_in_info (glusterd_volinfo_t *volinfo, char *slave, * assert an uuid mismatch */ t = strtail (slaveentry, host_uuid); - GF_ASSERT (!t || *t != ':'); + if (!is_force) + GF_ASSERT (!t || *t != ':'); + + if (is_force) { + gf_log ("", GF_LOG_DEBUG, GEOREP" has already been " + "invoked for the %s (master) and %s (slave)." + " Allowing without saving info again due to" + " force command.", volinfo->volname, slave); + ret = 0; + goto out; + } gf_log ("", GF_LOG_ERROR, GEOREP" has already been invoked for " "the %s (master) and %s (slave) " "from a different machine", volinfo->volname, slave); - *op_errstr = gf_strdup (GEOREP" already running in an an" + *op_errstr = gf_strdup (GEOREP" already running in " "another machine"); ret = -1; goto out; @@ -957,23 +1144,26 @@ glusterd_store_slave_in_info (glusterd_volinfo_t *volinfo, char *slave, return ret; } - static int glusterd_op_verify_gsync_start_options (glusterd_volinfo_t *volinfo, - char *slave, char **op_errstr) + char *slave, char *conf_path, + char *statefile, char **op_errstr, + gf_boolean_t is_force) { int ret = -1; gf_boolean_t is_running = _gf_false; char msg[2048] = {0}; uuid_t uuid = {0}; - glusterd_conf_t *priv = NULL; - xlator_t *this = NULL; + glusterd_conf_t *priv = NULL; + xlator_t *this = NULL; + struct stat stbuf = {0,}; this = THIS; GF_ASSERT (volinfo); GF_ASSERT (slave); GF_ASSERT (op_errstr); + GF_ASSERT (conf_path); GF_ASSERT (this && this->private); priv = this->private; @@ -983,26 +1173,56 @@ glusterd_op_verify_gsync_start_options (glusterd_volinfo_t *volinfo, "before "GEOREP" start", volinfo->volname); goto out; } + + ret = lstat (statefile, &stbuf); + if (ret) { + snprintf (msg, sizeof (msg), "Session between %s and %s has" + " not been created. Please create session and retry.", + volinfo->volname, slave); + gf_log ("", GF_LOG_ERROR, "%s", msg); + *op_errstr = gf_strdup (msg); + goto out; + } + + /* Check if the gsync slave info is stored. If not + * session has not been created */ + ret = glusterd_gsync_get_uuid (slave, volinfo, uuid); + if (ret) { + snprintf (msg, sizeof (msg), "Session between %s and %s has" + " not been created. Please create session and retry.", + volinfo->volname, slave); + gf_log ("", GF_LOG_ERROR, "%s", msg); + goto out; + } + + if (is_force) { + ret = 0; + goto out; + } + /*Check if the gsync is already started in cmd. inited host * If so initiate add it into the glusterd's priv*/ - ret = glusterd_gsync_get_uuid (slave, volinfo, uuid); - if ((ret == 0) && (uuid_compare (MY_UUID, uuid) == 0)) { - ret = glusterd_check_gsync_running_local (volinfo->volname, - slave, &is_running); - if (ret) { - snprintf (msg, sizeof (msg), GEOREP" start option " - "validation failed "); - goto out; - } - if (_gf_true == is_running) { - snprintf (msg, sizeof (msg), GEOREP " session between" - " %s & %s already started", volinfo->volname, - slave); - ret = -1; - goto out; - } + ret = glusterd_check_gsync_running_local (volinfo->volname, + slave, conf_path, + &is_running); + if (ret) { + snprintf (msg, sizeof (msg), GEOREP" start option " + "validation failed "); + goto out; + } + if (_gf_true == is_running) { + snprintf (msg, sizeof (msg), GEOREP " session between" + " %s & %s already started", volinfo->volname, + slave); + ret = -1; + goto out; + } + + ret = glusterd_verify_gsyncd_spawn (volinfo->volname, slave); + if (ret) { + snprintf (msg, sizeof (msg), "Unable to spawn gsyncd"); + gf_log ("", GF_LOG_ERROR, "%s", msg); } - ret = 0; out: if (ret && (msg[0] != '\0')) { *op_errstr = gf_strdup (msg); @@ -1028,11 +1248,13 @@ glusterd_check_gsync_running (glusterd_volinfo_t *volinfo, gf_boolean_t *flag) static int glusterd_op_verify_gsync_running (glusterd_volinfo_t *volinfo, - char *slave, char **op_errstr) + char *slave, char *conf_path, + char **op_errstr) { - int ret = -1; - char msg[2048] = {0}; - uuid_t uuid = {0}; + int pfd = -1; + int ret = -1; + char msg[2048] = {0}; + char pidfile[PATH_MAX] = {0,}; GF_ASSERT (THIS && THIS->private); GF_ASSERT (volinfo); @@ -1045,13 +1267,26 @@ glusterd_op_verify_gsync_running (glusterd_volinfo_t *volinfo, goto out; } - ret = glusterd_gsync_get_uuid (slave, volinfo, uuid); - if (ret == -1) { - snprintf (msg, sizeof (msg), GEOREP" session between %s & %s" - " not active", volinfo->volname, slave); + + pfd = gsyncd_getpidfile (volinfo->volname, slave, pidfile, conf_path); + if (pfd == -2) { + gf_log ("", GF_LOG_ERROR, GEOREP" stop validation " + "failed for %s & %s", volinfo->volname, slave); + ret = -1; + goto out; + } + if (gsync_status_byfd (pfd) == -1) { + snprintf (msg, sizeof (msg), GEOREP" session b/w %s & %s is not" + " running on this node.", volinfo->volname, slave); + gf_log ("", GF_LOG_ERROR, "%s", msg); + ret = -1; + /* monitor gsyncd already dead */ goto out; } + if (pfd < 0) + goto out; + ret = 0; out: if (ret && (msg[0] != '\0')) { @@ -1070,6 +1305,18 @@ glusterd_verify_gsync_status_opts (dict_t *dict, char **op_errstr) gf_boolean_t exists = _gf_false; glusterd_volinfo_t *volinfo = NULL; int ret = 0; + char *conf_path = NULL; + char *slave_ip = NULL; + char *slave_vol = NULL; + glusterd_conf_t *priv = NULL; + + if (THIS) + priv = THIS->private; + if (priv == NULL) { + gf_log ("", GF_LOG_ERROR, "priv of glusterd not present"); + *op_errstr = gf_strdup ("glusterd defunct"); + goto out; + } ret = dict_get_str (dict, "master", &volname); if (ret < 0) { @@ -1094,7 +1341,17 @@ glusterd_verify_gsync_status_opts (dict_t *dict, char **op_errstr) goto out; } - out: + ret = glusterd_get_slave_details_confpath (volinfo, dict, &slave_ip, + &slave_vol, &conf_path); + if (ret) { + snprintf (errmsg, sizeof (errmsg), + "Unable to fetch slave or confpath details."); + gf_log ("", GF_LOG_ERROR, "%s", errmsg); + ret = -1; + goto out; + } + +out: gf_log ("", GF_LOG_DEBUG, "Returning %d", ret); return ret; @@ -1103,7 +1360,7 @@ glusterd_verify_gsync_status_opts (dict_t *dict, char **op_errstr) int glusterd_op_gsync_args_get (dict_t *dict, char **op_errstr, - char **master, char **slave) + char **master, char **slave, char **host_uuid) { int ret = -1; @@ -1128,6 +1385,14 @@ glusterd_op_gsync_args_get (dict_t *dict, char **op_errstr, } } + if (host_uuid) { + ret = dict_get_str (dict, "host-uuid", host_uuid); + if (ret < 0) { + gf_log ("", GF_LOG_WARNING, "host_uuid not found"); + *op_errstr = gf_strdup ("host_uuid not found"); + goto out; + } + } ret = 0; out: @@ -1136,1138 +1401,2544 @@ out: } int -glusterd_op_stage_gsync_set (dict_t *dict, char **op_errstr) +glusterd_op_stage_sys_exec (dict_t *dict, char **op_errstr) { - int ret = 0; - int type = 0; - char *volname = NULL; - char *slave = NULL; - gf_boolean_t exists = _gf_false; - glusterd_volinfo_t *volinfo = NULL; - char errmsg[PATH_MAX] = {0,}; - dict_t *ctx = NULL; - + char errmsg[PATH_MAX] = ""; + char *command = NULL; + char command_path[PATH_MAX] = ""; + struct stat st = {0,}; + int ret = -1; - ret = dict_get_int32 (dict, "type", &type); - if (ret < 0) { - gf_log ("", GF_LOG_WARNING, "command type not found"); - *op_errstr = gf_strdup ("command unsuccessful"); + ret = dict_get_str (dict, "command", &command); + if (ret) { + strcpy (errmsg, "internal error"); + gf_log ("", GF_LOG_ERROR, + "Unable to get command from dict"); goto out; } - switch (type) { - case GF_GSYNC_OPTION_TYPE_STATUS: - ret = glusterd_verify_gsync_status_opts (dict, op_errstr); - + /* enforce local occurrence of the command */ + if (strchr (command, '/')) { + strcpy (errmsg, "invalid command name"); + ret = -1; goto out; - case GF_GSYNC_OPTION_TYPE_CONFIG: - ret = gsync_verify_config_options (dict, op_errstr); + } - goto out; + sprintf (command_path, GSYNCD_PREFIX"/peer_%s", command); + /* check if it's executable */ + ret = access (command_path, X_OK); + if (!ret) + /* check if it's a regular file */ + ret = stat (command_path, &st); + if (!ret && !S_ISREG (st.st_mode)) + ret = -1; - case GF_GSYNC_OPTION_TYPE_ROTATE: - /* checks same as status mode */ - ret = glusterd_verify_gsync_status_opts(dict, op_errstr); - goto out; +out: + if (ret) { + if (errmsg[0] == '\0') + snprintf (errmsg, sizeof (errmsg), "%s not found.", + command); + *op_errstr = gf_strdup (errmsg); + gf_log ("", GF_LOG_ERROR, "%s", errmsg); } - ret = glusterd_op_gsync_args_get (dict, op_errstr, &volname, &slave); - if (ret) + gf_log ("", GF_LOG_DEBUG, "Returning %d", ret); + return ret; +} + +int +glusterd_op_stage_copy_file (dict_t *dict, char **op_errstr) +{ + char abs_filename[PATH_MAX] = ""; + char errmsg[PATH_MAX] = ""; + char *filename = NULL; + char *host_uuid = NULL; + char uuid_str [64] = {0}; + int ret = -1; + glusterd_conf_t *priv = NULL; + struct stat stbuf = {0,}; + + if (THIS) + priv = THIS->private; + if (priv == NULL) { + gf_log ("", GF_LOG_ERROR, "priv of glusterd not present"); + *op_errstr = gf_strdup ("glusterd defunct"); goto out; + } - exists = glusterd_check_volume_exists (volname); - ret = glusterd_volinfo_find (volname, &volinfo); - if ((ret) || (!exists)) { - gf_log ("", GF_LOG_WARNING, "volume name does not exist"); - snprintf (errmsg, sizeof(errmsg), "Volume name %s does not" - " exist", volname); - *op_errstr = gf_strdup (errmsg); - ret = -1; + ret = dict_get_str (dict, "host-uuid", &host_uuid); + if (ret < 0) { + gf_log ("", GF_LOG_ERROR, "Unable to fetch" + " host-uuid from dict."); goto out; } - switch (type) { - case GF_GSYNC_OPTION_TYPE_START: - /* don't attempt to start gsync if replace-brick is - * in progress */ - if (glusterd_is_rb_ongoing (volinfo)) { - snprintf (errmsg, sizeof(errmsg),"replace-brick is in" - " progress, not starting geo-replication"); - *op_errstr = gf_strdup (errmsg); - ret = -1; + uuid_utoa_r (MY_UUID, uuid_str); + if (!strcmp (uuid_str, host_uuid)) { + ret = dict_get_str (dict, "source", &filename); + if (ret < 0) { + gf_log ("", GF_LOG_ERROR, "Unable to fetch" + " filename from dict."); + *op_errstr = gf_strdup ("command unsuccessful"); goto out; } + snprintf (abs_filename, sizeof(abs_filename), + "%s/%s", priv->workdir, filename); - ret = glusterd_op_verify_gsync_start_options (volinfo, slave, - op_errstr); - if (ret) + ret = lstat (abs_filename, &stbuf); + if (ret) { + snprintf (errmsg, sizeof (errmsg), "Source file" + " does not exist in %s", priv->workdir); + *op_errstr = gf_strdup (errmsg); goto out; - ctx = glusterd_op_get_ctx(); - if (ctx) { - /*gsyncd does a fuse mount to start the geo-rep session*/ - if (!glusterd_is_fuse_available ()) { - gf_log ("glusterd", GF_LOG_ERROR, "Unable to open" - " /dev/fuse (%s), geo-replication start" - " failed", strerror (errno)); - snprintf (errmsg, sizeof(errmsg), - "fuse unvailable"); - *op_errstr = gf_strdup (errmsg); - ret = -1; - goto out; - } } - break; - case GF_GSYNC_OPTION_TYPE_STOP: - ret = glusterd_op_verify_gsync_running (volinfo, slave, - op_errstr); - break; + if (!S_ISREG(stbuf.st_mode)) { + snprintf (errmsg, sizeof (errmsg), "Source file" + " is not a regular file."); + *op_errstr = gf_strdup (errmsg); + gf_log ("", GF_LOG_ERROR, "%s", errmsg); + ret = -1; + goto out; + } } + ret = 0; out: + gf_log ("", GF_LOG_DEBUG, "Returning %d", ret); return ret; } static int -stop_gsync (char *master, char *slave, char **msg) +glusterd_get_statefile_name (glusterd_volinfo_t *volinfo, char *slave, + char *conf_path, char **statefile) { - int32_t ret = 0; - int pfd = -1; - pid_t pid = 0; - char pidfile[PATH_MAX] = {0,}; - char buf [1024] = {0,}; - int i = 0; + glusterd_conf_t *priv = NULL; + int ret = -1; + char *master = NULL; + char *buf = NULL; + dict_t *confd = NULL; + char *confpath = NULL; + char conf_buf[PATH_MAX] = ""; + struct stat stbuf = {0,}; GF_ASSERT (THIS); GF_ASSERT (THIS->private); + GF_ASSERT (volinfo); - pfd = gsyncd_getpidfile (master, slave, pidfile); - if (pfd == -2) { - gf_log ("", GF_LOG_ERROR, GEOREP" stop validation " - " failed for %s & %s", master, slave); - ret = -1; + master = volinfo->volname; + + confd = dict_new (); + if (!confd) { + gf_log ("", GF_LOG_ERROR, "Unable to create new dict"); goto out; } - if (gsync_status_byfd (pfd) == -1) { - gf_log ("", GF_LOG_ERROR, "gsyncd b/w %s & %s is not" - " running", master, slave); - if (msg) - *msg = gf_strdup ("Warning: "GEOREP" session was " - "defunct at stop time"); - /* monitor gsyncd already dead */ + + priv = THIS->private; + + ret = lstat (conf_path, &stbuf); + if (!ret) { + gf_log ("", GF_LOG_DEBUG, "Using passed config template(%s).", + conf_path); + confpath = conf_path; + } else { + ret = snprintf (conf_buf, sizeof(conf_buf) - 1, + "%s/"GSYNC_CONF_TEMPLATE, priv->workdir); + conf_buf[ret] = '\0'; + confpath = conf_buf; + gf_log ("", GF_LOG_DEBUG, "Using default config template(%s).", + confpath); + } + + ret = glusterd_gsync_get_config (master, slave, confpath, + confd); + if (ret) { + gf_log ("", GF_LOG_ERROR, "Unable to get configuration data" + "for %s(master), %s(slave)", master, slave); goto out; + } - if (pfd < 0) + ret = dict_get_param (confd, "state_file", &buf); + if (ret) { + gf_log ("", GF_LOG_ERROR, "Unable to get state_file's name."); goto out; + } - ret = read (pfd, buf, 1024); - if (ret > 0) { - pid = strtol (buf, NULL, 10); - ret = kill (-pid, SIGTERM); - if (ret) { - gf_log ("", GF_LOG_WARNING, - "failed to kill gsyncd"); - goto out; - } - for (i = 0; i < 20; i++) { - if (gsync_status_byfd (pfd) == -1) { - /* monitor gsyncd is dead but worker may - * still be alive, give some more time - * before SIGKILL (hack) - */ - usleep (50000); - break; - } - usleep (50000); - } - kill (-pid, SIGKILL); - unlink (pidfile); + *statefile = gf_strdup(buf); + if (!*statefile) { + gf_log ("", GF_LOG_ERROR, "Unable to gf_strdup."); + ret = -1; + goto out; } + ret = 0; + out: + if (confd) + dict_destroy (confd); -out: - sys_close (pfd); + gf_log ("", GF_LOG_DEBUG, "Returning %d ", ret); return ret; } static int -glusterd_check_restart_gsync_session (glusterd_volinfo_t *volinfo, char *slave, - dict_t *resp_dict); - -static int -glusterd_gsync_configure (glusterd_volinfo_t *volinfo, char *slave, - dict_t *dict, dict_t *resp_dict, char **op_errstr) +glusterd_create_status_file (char *master, char *slave, + char *slave_vol, char *status) { - int32_t ret = -1; - char *op_name = NULL; - char *op_value = NULL; - runner_t runner = {0,}; - glusterd_conf_t *priv = NULL; - char *subop = NULL; - char *master = NULL; + int ret = -1; + runner_t runner = {0,}; + glusterd_conf_t *priv = NULL; - GF_ASSERT (slave); - GF_ASSERT (op_errstr); - GF_ASSERT (dict); - GF_ASSERT (resp_dict); + if (THIS) + priv = THIS->private; + if (priv == NULL) { + gf_log ("", GF_LOG_ERROR, "priv of glusterd not present"); + goto out; + } - ret = dict_get_str (dict, "subop", &subop); - if (ret != 0) + if (!status) { + gf_log ("", GF_LOG_ERROR, "Status Empty"); goto out; + } + gf_log ("", GF_LOG_DEBUG, "slave = %s", slave); - if (strcmp (subop, "get") == 0 || strcmp (subop, "get-all") == 0) { - /* deferred to cli */ - gf_log ("", GF_LOG_DEBUG, "Returning 0"); - return 0; + runinit (&runner); + runner_add_args (&runner, GSYNCD_PREFIX"/gsyncd", "--create", + status, "-c", NULL); + runner_argprintf (&runner, "%s/"GEOREP"/%s-%s/gsyncd.conf", + priv->workdir, master, slave_vol); + runner_argprintf (&runner, ":%s", master); + runner_add_args (&runner, slave, NULL); + synclock_unlock (&priv->big_lock); + ret = runner_run (&runner); + synclock_lock (&priv->big_lock); + if (ret) { + gf_log ("", GF_LOG_ERROR, "Creating status file failed."); + ret = -1; + goto out; } - ret = dict_get_str (dict, "op_name", &op_name); - if (ret != 0) - goto out; + ret = 0; +out: + gf_log ("", GF_LOG_DEBUG, "returning %d", ret); + return ret; +} - if (strtail (subop, "set")) { - ret = dict_get_str (dict, "op_value", &op_value); - if (ret != 0) - goto out; - } +static int +glusterd_verify_slave (char *volname, char *slave_ip, char *slave, + char **op_errstr) +{ + int32_t ret = -1; + runner_t runner = {0,}; + glusterd_conf_t *priv = NULL; + char log_file_path[PATH_MAX] = ""; + char buf[PATH_MAX] = ""; + + GF_ASSERT (volname); + GF_ASSERT (slave_ip); + GF_ASSERT (slave); if (THIS) priv = THIS->private; if (priv == NULL) { gf_log ("", GF_LOG_ERROR, "priv of glusterd not present"); - *op_errstr = gf_strdup ("glusterd defunct"); goto out; } - master = ""; + snprintf (log_file_path, sizeof(log_file_path), + DEFAULT_LOG_FILE_DIRECTORY"/create_verify_log"); + runinit (&runner); - runner_add_args (&runner, GSYNCD_PREFIX"/gsyncd", "-c", NULL); - runner_argprintf (&runner, "%s/"GSYNC_CONF, priv->workdir); - if (volinfo) { - master = volinfo->volname; - runner_argprintf (&runner, ":%s", master); - } - runner_add_arg (&runner, slave); - runner_argprintf (&runner, "--config-%s", subop); - runner_add_arg (&runner, op_name); - if (op_value) - runner_add_arg (&runner, op_value); + runner_add_args (&runner, GSYNCD_PREFIX"/gverify.sh", NULL); + runner_argprintf (&runner, "%s", volname); + runner_argprintf (&runner, "%s", slave_ip); + runner_argprintf (&runner, "%s", slave); + runner_argprintf (&runner, "%s", log_file_path); + runner_redir (&runner, STDOUT_FILENO, RUN_PIPE); synclock_unlock (&priv->big_lock); ret = runner_run (&runner); synclock_lock (&priv->big_lock); if (ret) { - gf_log ("", GF_LOG_WARNING, "gsyncd failed to " - "%s %s option for %s %s peers", - subop, op_name, master, slave); - - gf_asprintf (op_errstr, GEOREP" config-%s failed for %s %s", - subop, master, slave); - + gf_log ("", GF_LOG_ERROR, "Not a valid slave"); + ret = glusterd_gsync_read_frm_status (log_file_path, + buf, sizeof(buf)); + if (ret) { + gf_log ("", GF_LOG_ERROR, "Unable to read from %s", + log_file_path); + goto out; + } + *op_errstr = gf_strdup (buf); + ret = -1; goto out; } ret = 0; - gf_asprintf (op_errstr, "config-%s successful", subop); - out: - if (!ret && volinfo) { - ret = glusterd_check_restart_gsync_session (volinfo, slave, - resp_dict); - if (ret) - *op_errstr = gf_strdup ("internal error"); - } - + unlink (log_file_path); gf_log ("", GF_LOG_DEBUG, "Returning %d", ret); return ret; } -static int -glusterd_gsync_read_frm_status (char *path, char *buf, size_t blen) +int +glusterd_op_stage_gsync_create (dict_t *dict, char **op_errstr) { - int ret = 0; - int status_fd = -1; + char *down_peerstr = NULL; + char *slave = NULL; + char *volname = NULL; + char *host_uuid = NULL; + char *statefile = NULL; + char *slave_ip = NULL; + char *slave_vol = NULL; + char *conf_path = NULL; + char errmsg[PATH_MAX] = ""; + char common_pem_file[PATH_MAX] = ""; + char uuid_str [64] = ""; + int ret = -1; + int is_pem_push = -1; + gf_boolean_t is_force = -1; + gf_boolean_t exists = _gf_false; + glusterd_conf_t *conf = NULL; + glusterd_volinfo_t *volinfo = NULL; + struct stat stbuf = {0,}; + xlator_t *this = NULL; - GF_ASSERT (path); - GF_ASSERT (buf); - status_fd = open (path, O_RDONLY); - if (status_fd == -1) { - gf_log ("", GF_LOG_ERROR, "Unable to read gsyncd status" - " file"); + this = THIS; + GF_ASSERT (this); + conf = this->private; + GF_ASSERT (conf); + + ret = glusterd_op_gsync_args_get (dict, op_errstr, &volname, + &slave, &host_uuid); + if (ret) { + gf_log ("", GF_LOG_ERROR, "Unable to fetch arguments"); + gf_log ("", GF_LOG_DEBUG, "Returning %d", ret); return -1; } - ret = read (status_fd, buf, blen - 1); - if (ret > 0) { - size_t len = strnlen (buf, ret); - /* Ensure there is a NUL byte and that it's not the first. */ - if (len == 0 || len == blen - 1) { - ret = -1; - } else { - char *p = buf + len - 1; - while (isspace (*p)) - *p-- = '\0'; - ret = 0; - } - } else if (ret < 0) - gf_log ("", GF_LOG_ERROR, "Status file of gsyncd is corrupt"); - close (status_fd); - return ret; -} + exists = glusterd_check_volume_exists (volname); + ret = glusterd_volinfo_find (volname, &volinfo); + if ((ret) || (!exists)) { + gf_log ("", GF_LOG_WARNING, "volume name does not exist"); + snprintf (errmsg, sizeof(errmsg), "Volume name %s does not" + " exist", volname); + *op_errstr = gf_strdup (errmsg); + gf_log ("", GF_LOG_DEBUG, "Returning %d", ret); + return -1; + } -static int -glusterd_gsync_fetch_status_extra (char *path, char *buf, size_t blen) -{ - char sockpath[PATH_MAX] = {0,}; - struct sockaddr_un sa = {0,}; - size_t l = 0; - int s = -1; - struct pollfd pfd = {0,}; - int ret = 0; + is_force = dict_get_str_boolean (dict, "force", _gf_false); - l = strlen (buf); - /* seek to end of data in buf */ - buf += l; - blen -= l; + ret = glusterd_get_slave_details_confpath (volinfo, dict, &slave_ip, + &slave_vol, &conf_path); + if (ret) { + snprintf (errmsg, sizeof (errmsg), + "Unable to fetch slave or confpath details."); + gf_log ("", GF_LOG_ERROR, "%s", errmsg); + ret = -1; + goto out; + } - glusterd_set_socket_filepath (path, sockpath, sizeof (sockpath)); + uuid_utoa_r (MY_UUID, uuid_str); + if (!strcmp (uuid_str, host_uuid)) { + ret = glusterd_are_vol_all_peers_up (volinfo, + &conf->peers, + &down_peerstr); + if (ret == _gf_false) { + snprintf (errmsg, sizeof (errmsg), "Peer %s," + " which is a part of %s volume, is" + " down. Please bring up the peer and" + " retry.", down_peerstr, + volinfo->volname); + gf_log ("", GF_LOG_ERROR, "%s", errmsg); + *op_errstr = gf_strdup (errmsg); + GF_FREE (down_peerstr); + down_peerstr = NULL; + gf_log ("", GF_LOG_DEBUG, "Returning %d", ret); + return -1; + } - strncpy(sa.sun_path, sockpath, sizeof(sa.sun_path)); - if (sa.sun_path[sizeof (sa.sun_path) - 1]) - return -1; - sa.sun_family = AF_UNIX; + ret = glusterd_verify_slave (volname, slave_ip, slave_vol, + op_errstr); + if (ret) { + gf_log ("", GF_LOG_ERROR, + "%s is not a valid slave volume.", + slave); + ret = -1; + goto out; + } - s = socket(AF_UNIX, SOCK_STREAM, 0); - if (s == -1) - return -1; - ret = fcntl (s, F_GETFL); - if (ret != -1) - ret = fcntl (s, F_SETFL, ret | O_NONBLOCK); - if (ret == -1) - goto out; + ret = dict_get_int32 (dict, "push_pem", &is_pem_push); + if (!ret && is_pem_push) { + snprintf (common_pem_file, sizeof(common_pem_file), + "%s"GLUSTERD_COMMON_PEM_PUB_FILE, + conf->workdir); + + ret = lstat (common_pem_file, &stbuf); + if (ret) { + snprintf (errmsg, sizeof (errmsg), "%s" + " required for push-pem is" + " not present.", common_pem_file); + gf_log ("", GF_LOG_ERROR, "%s", errmsg); + ret = -1; + goto out; + } - ret = connect (s, (struct sockaddr *)&sa, sizeof (sa)); - if (ret == -1) - goto out; - pfd.fd = s; - pfd.events = POLLIN; - /* we don't want to hang on gsyncd */ - if (poll (&pfd, 1, 5000) < 1 || - !(pfd.revents & POLLIN)) { + if (!S_ISREG(stbuf.st_mode)) { + snprintf (errmsg, sizeof (errmsg), "%s" + " required for push-pem is" + " not a regular file.", + common_pem_file); + gf_log ("", GF_LOG_ERROR, "%s", errmsg); + ret = -1; + goto out; + } + } + } + + ret = glusterd_get_statefile_name (volinfo, slave, conf_path, &statefile); + if (ret) { + if (!strstr(slave, "::")) + snprintf (errmsg, sizeof (errmsg), + "%s is not a valid slave url.", slave); + else + snprintf (errmsg, sizeof (errmsg), "Unable to get " + "statefile's name"); + gf_log ("", GF_LOG_ERROR, "%s", errmsg); + goto out; + } + + ret = lstat (statefile, &stbuf); + if (!ret) { + snprintf (errmsg, sizeof (errmsg), "Session between %s" + " and %s is already created.", + volinfo->volname, slave); + gf_log ("", GF_LOG_ERROR, "%s", errmsg); ret = -1; goto out; } - ret = read(s, buf, blen); - /* we expect a terminating 0 byte */ - if (ret == 0 || (ret > 0 && buf[ret - 1])) - ret = -1; - if (ret > 0) - ret = 0; - - out: - close (s); - return ret; -} -static int -dict_get_param (dict_t *dict, char *key, char **param) -{ - char *dk = NULL; - char *s = NULL; - char x = '\0'; - int ret = 0; + ret = dict_set_str (dict, "statefile", statefile); + if (ret) { + gf_log ("", GF_LOG_ERROR, + "Unable to store statefile path"); + goto out; + } - if (dict_get_str (dict, key, param) == 0) - return 0; + ret = glusterd_verify_gsyncd_spawn (volinfo->volname, slave); + if (ret) { + snprintf (errmsg, sizeof (errmsg), "Unable to spawn gsyncd"); + gf_log ("", GF_LOG_ERROR, "%s", errmsg); + goto out; + } - dk = gf_strdup (key); - if (!key) - return -1; + ret = 0; +out: - s = strpbrk (dk, "-_"); - if (!s) - return -1; - x = (*s == '-') ? '_' : '-'; - *s++ = x; - while ((s = strpbrk (s, "-_"))) - *s++ = x; + if (is_force) + ret = 0; - ret = dict_get_str (dict, dk, param); + if (ret && errmsg[0] != '\0') + *op_errstr = gf_strdup (errmsg); - GF_FREE (dk); + gf_log ("", GF_LOG_DEBUG, "Returning %d", ret); return ret; } -static int -glusterd_read_status_file (char *master, char *slave, - dict_t *dict, char *node) +int +glusterd_op_stage_gsync_set (dict_t *dict, char **op_errstr) { - glusterd_conf_t *priv = NULL; - int ret = 0; - char *statefile = NULL; - char buf[1024] = {0, }; - char nds[1024] = {0, }; - char mst[1024] = {0, }; - char slv[1024] = {0, }; - char sts[1024] = {0, }; - char *bufp = NULL; - dict_t *confd = NULL; - int gsync_count = 0; - int status = 0; - char *dyn_node = NULL; - - GF_ASSERT (THIS); - GF_ASSERT (THIS->private); + int ret = 0; + int type = 0; + char *volname = NULL; + char *slave = NULL; + char *slave_ip = NULL; + char *slave_vol = NULL; + char *down_peerstr = NULL; + char *statefile = NULL; + char *path_list = NULL; + char *conf_path = NULL; + gf_boolean_t exists = _gf_false; + glusterd_volinfo_t *volinfo = NULL; + char errmsg[PATH_MAX] = {0,}; + dict_t *ctx = NULL; + gf_boolean_t is_force = 0; + gf_boolean_t is_running = _gf_false; + uuid_t uuid = {0}; + char uuid_str [64] = {0}; + char *host_uuid = NULL; + xlator_t *this = NULL; + glusterd_conf_t *conf = NULL; + struct stat stbuf = {0,}; - confd = dict_new (); - if (!dict) - return -1; + this = THIS; + GF_ASSERT (this); + conf = this->private; + GF_ASSERT (conf); - priv = THIS->private; - ret = glusterd_gsync_get_config (master, slave, priv->workdir, - confd); - if (ret) { - gf_log ("", GF_LOG_ERROR, "Unable to get configuration data" - "for %s(master), %s(slave)", master, slave); + ret = dict_get_int32 (dict, "type", &type); + if (ret < 0) { + gf_log ("", GF_LOG_WARNING, "command type not found"); + *op_errstr = gf_strdup ("command unsuccessful"); goto out; - } - ret = gsync_status (master, slave, &status); - if (ret == 0 && status == -1) { - strncpy (buf, "defunct", sizeof (buf)); - goto done; - } else if (ret == -1) + if (type == GF_GSYNC_OPTION_TYPE_STATUS) { + ret = glusterd_verify_gsync_status_opts (dict, op_errstr); goto out; + } - ret = dict_get_param (confd, "state_file", &statefile); + ret = glusterd_op_gsync_args_get (dict, op_errstr, + &volname, &slave, NULL); if (ret) goto out; - ret = glusterd_gsync_read_frm_status (statefile, buf, sizeof (buf)); - if (ret) { - gf_log ("", GF_LOG_ERROR, "Unable to read the status" + + exists = glusterd_check_volume_exists (volname); + ret = glusterd_volinfo_find (volname, &volinfo); + if ((ret) || (!exists)) { + gf_log ("", GF_LOG_WARNING, "volume name does not exist"); + snprintf (errmsg, sizeof(errmsg), "Volume name %s does not" + " exist", volname); + *op_errstr = gf_strdup (errmsg); + ret = -1; + goto out; + } + + ret = glusterd_get_slave_details_confpath (volinfo, dict, &slave_ip, + &slave_vol, &conf_path); + if (ret) { + snprintf (errmsg, sizeof (errmsg), + "Unable to fetch slave or confpath details."); + gf_log ("", GF_LOG_ERROR, "%s", errmsg); + ret = -1; + goto out; + } + + ret = glusterd_get_statefile_name (volinfo, slave, conf_path, &statefile); + if (ret) { + if (!strstr(slave, "::")) + snprintf (errmsg, sizeof (errmsg), + "%s is not a valid slave url.", slave); + else + snprintf (errmsg, sizeof (errmsg), + "Unable to get statefile's name"); + gf_log ("", GF_LOG_ERROR, "%s", errmsg); + ret = -1; + goto out; + } + + ret = dict_set_str (dict, "statefile", statefile); + if (ret) { + gf_log ("", GF_LOG_ERROR, + "Unable to store statefile path"); + goto out; + } + + if ((type == GF_GSYNC_OPTION_TYPE_CONFIG) || + (type == GF_GSYNC_OPTION_TYPE_DELETE)) { + ret = lstat (statefile, &stbuf); + if (ret) { + snprintf (errmsg, sizeof(errmsg), "Geo-replication" + " session between %s and %s does not exist.", + volinfo->volname, slave); + gf_log ("", GF_LOG_ERROR, "%s. statefile = %s", + errmsg, statefile); + *op_errstr = gf_strdup (errmsg); + ret = -1; + goto out; + } + } + + is_force = dict_get_str_boolean (dict, "force", _gf_false); + + /* Check if all peers that are a part of the volume are up or not */ + if ((type == GF_GSYNC_OPTION_TYPE_DELETE) || + ((type == GF_GSYNC_OPTION_TYPE_STOP) && !is_force)) { + ret = dict_get_str (dict, "host-uuid", &host_uuid); + if (ret < 0) + goto out; + + uuid_utoa_r (MY_UUID, uuid_str); + if (!strcmp (uuid_str, host_uuid)) { + ret = glusterd_are_vol_all_peers_up (volinfo, + &conf->peers, + &down_peerstr); + if (ret == _gf_false) { + snprintf (errmsg, sizeof (errmsg), "Peer %s," + " which is a part of %s volume, is" + " down. Please bring up the peer and" + " retry.", down_peerstr, + volinfo->volname); + *op_errstr = gf_strdup (errmsg); + ret = -1; + GF_FREE (down_peerstr); + down_peerstr = NULL; + goto out; + } + } + } + + switch (type) { + case GF_GSYNC_OPTION_TYPE_START: + /* don't attempt to start gsync if replace-brick is + * in progress */ + if (glusterd_is_rb_ongoing (volinfo)) { + snprintf (errmsg, sizeof(errmsg), "replace-brick is in" + " progress, not starting geo-replication"); + *op_errstr = gf_strdup (errmsg); + ret = -1; + goto out; + } + + ret = glusterd_op_verify_gsync_start_options (volinfo, slave, + conf_path, statefile, + op_errstr, is_force); + if (ret) + goto out; + ctx = glusterd_op_get_ctx(); + if (ctx) { + /* gsyncd does a fuse mount to start + * the geo-rep session */ + if (!glusterd_is_fuse_available ()) { + gf_log ("glusterd", GF_LOG_ERROR, "Unable to " + "open /dev/fuse (%s), geo-replication " + "start failed", strerror (errno)); + snprintf (errmsg, sizeof(errmsg), + "fuse unvailable"); + *op_errstr = gf_strdup (errmsg); + ret = -1; + goto out; + } + } + break; + + case GF_GSYNC_OPTION_TYPE_STOP: + if (!is_force) { + ret = glusterd_op_verify_gsync_running (volinfo, slave, + conf_path, + op_errstr); + if (ret) { + ret = glusterd_get_local_brickpaths (volinfo, + &path_list); + if (path_list) + ret = -1; + } + } + break; + + case GF_GSYNC_OPTION_TYPE_CONFIG: + ret = gsync_verify_config_options (dict, op_errstr, volname); + goto out; + break; + + case GF_GSYNC_OPTION_TYPE_DELETE: + /* Check if the gsync session is still running + * If so ask the user to stop geo-replication first.*/ + ret = glusterd_gsync_get_uuid (slave, volinfo, uuid); + if (ret) { + snprintf (errmsg, sizeof(errmsg), "Geo-replication" + " session between %s and %s does not exist.", + volinfo->volname, slave); + gf_log ("", GF_LOG_ERROR, "%s", errmsg); + *op_errstr = gf_strdup (errmsg); + ret = -1; + goto out; + } else { + ret = glusterd_check_gsync_running_local (volinfo->volname, + slave, conf_path, + &is_running); + if (_gf_true == is_running) { + snprintf (errmsg, sizeof (errmsg), GEOREP + " session between %s & %s is " + "still active. Please stop the " + "session and retry.", + volinfo->volname, slave); + gf_log ("", GF_LOG_ERROR, "%s", errmsg); + *op_errstr = gf_strdup (errmsg); + ret = -1; + goto out; + } + } + + ret = glusterd_verify_gsyncd_spawn (volinfo->volname, slave); + if (ret) { + snprintf (errmsg, sizeof (errmsg), + "Unable to spawn gsyncd"); + *op_errstr = gf_strdup (errmsg); + gf_log ("", GF_LOG_ERROR, "%s", errmsg); + } + + break; + } + +out: + gf_log ("", GF_LOG_DEBUG, "Returning %d", ret); + return ret; +} + +static int +stop_gsync (char *master, char *slave, char **msg, + char *conf_path, gf_boolean_t is_force) +{ + int32_t ret = 0; + int pfd = -1; + pid_t pid = 0; + char pidfile[PATH_MAX] = {0,}; + char buf [1024] = {0,}; + int i = 0; + + GF_ASSERT (THIS); + GF_ASSERT (THIS->private); + + pfd = gsyncd_getpidfile (master, slave, pidfile, conf_path); + if (pfd == -2 && !is_force) { + gf_log ("", GF_LOG_ERROR, GEOREP" stop validation " + " failed for %s & %s", master, slave); + ret = -1; + goto out; + } + if (gsync_status_byfd (pfd) == -1 && !is_force) { + gf_log ("", GF_LOG_ERROR, "gsyncd b/w %s & %s is not" + " running", master, slave); + /* monitor gsyncd already dead */ + goto out; + } + + if (pfd < 0) + goto out; + + ret = read (pfd, buf, 1024); + if (ret > 0) { + pid = strtol (buf, NULL, 10); + ret = kill (-pid, SIGTERM); + if (ret) { + gf_log ("", GF_LOG_WARNING, + "failed to kill gsyncd"); + goto out; + } + for (i = 0; i < 20; i++) { + if (gsync_status_byfd (pfd) == -1) { + /* monitor gsyncd is dead but worker may + * still be alive, give some more time + * before SIGKILL (hack) + */ + usleep (50000); + break; + } + usleep (50000); + } + kill (-pid, SIGKILL); + unlink (pidfile); + } + ret = 0; + +out: + sys_close (pfd); + + if (is_force) + ret = 0; + return ret; +} + +static int +glusterd_check_restart_gsync_session (glusterd_volinfo_t *volinfo, char *slave, + dict_t *resp_dict, char *path_list, + char *conf_path, gf_boolean_t is_force); + +static int +glusterd_gsync_configure (glusterd_volinfo_t *volinfo, char *slave, + char *path_list, dict_t *dict, + dict_t *resp_dict, char **op_errstr) +{ + int32_t ret = -1; + char *op_name = NULL; + char *op_value = NULL; + runner_t runner = {0,}; + glusterd_conf_t *priv = NULL; + char *subop = NULL; + char *master = NULL; + char *conf_path = NULL; + char *slave_vol = NULL; + struct stat stbuf = {0, }; + + GF_ASSERT (slave); + GF_ASSERT (op_errstr); + GF_ASSERT (dict); + GF_ASSERT (resp_dict); + + ret = dict_get_str (dict, "subop", &subop); + if (ret != 0) + goto out; + + if (strcmp (subop, "get") == 0 || strcmp (subop, "get-all") == 0) { + /* deferred to cli */ + gf_log ("", GF_LOG_DEBUG, "Returning 0"); + return 0; + } + + ret = dict_get_str (dict, "op_name", &op_name); + if (ret != 0) + goto out; + + if (strtail (subop, "set")) { + ret = dict_get_str (dict, "op_value", &op_value); + if (ret != 0) + goto out; + } + + if (THIS) + priv = THIS->private; + if (priv == NULL) { + gf_log ("", GF_LOG_ERROR, "priv of glusterd not present"); + *op_errstr = gf_strdup ("glusterd defunct"); + goto out; + } + + ret = dict_get_str (dict, "conf_path", &conf_path); + if (ret) { + gf_log ("", GF_LOG_ERROR, + "Unable to fetch conf file path."); + goto out; + } + + master = ""; + runinit (&runner); + runner_add_args (&runner, GSYNCD_PREFIX"/gsyncd", "-c", NULL); + runner_argprintf (&runner, "%s", conf_path); + if (volinfo) { + master = volinfo->volname; + runner_argprintf (&runner, ":%s", master); + } + runner_add_arg (&runner, slave); + runner_argprintf (&runner, "--config-%s", subop); + runner_add_arg (&runner, op_name); + if (op_value) + runner_add_arg (&runner, op_value); + synclock_unlock (&priv->big_lock); + ret = runner_run (&runner); + synclock_lock (&priv->big_lock); + if (ret) { + gf_log ("", GF_LOG_WARNING, "gsyncd failed to " + "%s %s option for %s %s peers", + subop, op_name, master, slave); + + gf_asprintf (op_errstr, GEOREP" config-%s failed for %s %s", + subop, master, slave); + + goto out; + } + + if (!strcmp (op_name, "state_file")) { + + ret = lstat (op_value, &stbuf); + if (ret) { + ret = dict_get_str (dict, "slave_vol", &slave_vol); + if (ret) { + gf_log ("", GF_LOG_ERROR, + "Unable to fetch slave volume name."); + goto out; + } + + ret = glusterd_create_status_file (volinfo->volname, slave, + slave_vol, + "Switching Status File"); + if (ret || lstat (op_value, &stbuf)) { + gf_log ("", GF_LOG_ERROR, "Unable to create %s" + ". Error : %s", op_value, + strerror (errno)); + ret = -1; + goto out; + } + } + } + + ret = 0; + gf_asprintf (op_errstr, "config-%s successful", subop); + +out: + if (!ret && volinfo) { + ret = glusterd_check_restart_gsync_session (volinfo, slave, + resp_dict, path_list, + conf_path, 0); + if (ret) + *op_errstr = gf_strdup ("internal error"); + } + + gf_log ("", GF_LOG_DEBUG, "Returning %d", ret); + return ret; +} + +static int +glusterd_gsync_read_frm_status (char *path, char *buf, size_t blen) +{ + int ret = 0; + int status_fd = -1; + + GF_ASSERT (path); + GF_ASSERT (buf); + status_fd = open (path, O_RDONLY); + if (status_fd == -1) { + gf_log ("", GF_LOG_ERROR, "Unable to read gsyncd status" + " file"); + return -1; + } + ret = read (status_fd, buf, blen - 1); + if (ret > 0) { + size_t len = strnlen (buf, ret); + /* Ensure there is a NUL byte and that it's not the first. */ + if (len == 0 || len == blen - 1) { + ret = -1; + } else { + char *p = buf + len - 1; + while (isspace (*p)) + *p-- = '\0'; + ret = 0; + } + } else if (ret < 0) + gf_log ("", GF_LOG_ERROR, "Status file of gsyncd is corrupt"); + + close (status_fd); + return ret; +} + +static int +glusterd_gsync_fetch_status_extra (char *path, char *buf, size_t blen) +{ + char sockpath[PATH_MAX] = {0,}; + struct sockaddr_un sa = {0,}; + size_t l = 0; + int s = -1; + struct pollfd pfd = {0,}; + int ret = 0; + + l = strlen (buf); + /* seek to end of data in buf */ + buf += l; + blen -= l; + + glusterd_set_socket_filepath (path, sockpath, sizeof (sockpath)); + + strncpy(sa.sun_path, sockpath, sizeof(sa.sun_path)); + if (sa.sun_path[sizeof (sa.sun_path) - 1]) + return -1; + sa.sun_family = AF_UNIX; + + s = socket(AF_UNIX, SOCK_STREAM, 0); + if (s == -1) + return -1; + ret = fcntl (s, F_GETFL); + if (ret != -1) + ret = fcntl (s, F_SETFL, ret | O_NONBLOCK); + if (ret == -1) + goto out; + + ret = connect (s, (struct sockaddr *)&sa, sizeof (sa)); + if (ret == -1) + goto out; + pfd.fd = s; + pfd.events = POLLIN; + /* we don't want to hang on gsyncd */ + if (poll (&pfd, 1, 5000) < 1 || + !(pfd.revents & POLLIN)) { + ret = -1; + goto out; + } + ret = read(s, buf, blen); + /* we expect a terminating 0 byte */ + if (ret == 0 || (ret > 0 && buf[ret - 1])) + ret = -1; + if (ret > 0) + ret = 0; + + out: + close (s); + return ret; +} + +static int +dict_get_param (dict_t *dict, char *key, char **param) +{ + char *dk = NULL; + char *s = NULL; + char x = '\0'; + int ret = 0; + + if (dict_get_str (dict, key, param) == 0) + return 0; + + dk = gf_strdup (key); + if (!key) + return -1; + + s = strpbrk (dk, "-_"); + if (!s) + return -1; + x = (*s == '-') ? '_' : '-'; + *s++ = x; + while ((s = strpbrk (s, "-_"))) + *s++ = x; + + ret = dict_get_str (dict, dk, param); + + GF_FREE (dk); + return ret; +} + +static int +glusterd_read_status_file (glusterd_volinfo_t *volinfo, char *slave, + char *conf_path, dict_t *dict, char *node) +{ + glusterd_conf_t *priv = NULL; + int ret = 0; + char *statefile = NULL; + char *master = NULL; + char buf[1024] = {0, }; + char nds[1024] = {0, }; + char mst[1024] = {0, }; + char slv[1024] = {0, }; + char sts[1024] = {0, }; + char *bufp = NULL; + dict_t *confd = NULL; + int gsync_count = 0; + int status = 0; + char *dyn_node = NULL; + char *path_list = NULL; + + GF_ASSERT (THIS); + GF_ASSERT (THIS->private); + GF_ASSERT (volinfo); + + master = volinfo->volname; + + confd = dict_new (); + if (!dict) + return -1; + + priv = THIS->private; + + ret = glusterd_gsync_get_config (master, slave, conf_path, + confd); + if (ret) { + gf_log ("", GF_LOG_ERROR, "Unable to get configuration data" + "for %s(master), %s(slave)", master, slave); + goto out; + + } + + ret = dict_get_param (confd, "state_file", &statefile); + if (ret) + goto out; + ret = glusterd_gsync_read_frm_status (statefile, buf, sizeof (buf)); + if (ret) { + gf_log ("", GF_LOG_ERROR, "Unable to read the status" "file for %s(master), %s(slave)", master, slave); strncpy (buf, "defunct", sizeof (buf)); goto done; } - if (strcmp (buf, "OK") != 0) + + ret = gsync_status (master, slave, conf_path, &status); + if (ret == 0 && status == -1) { + if ((strcmp (buf, "Not Started")) && + (strcmp (buf, "Stopped"))) + strncpy (buf, "defunct", sizeof (buf)); + goto done; + } else if (ret == -1) + goto out; + + if (strcmp (buf, "Stable") != 0) + goto done; + + ret = dict_get_param (confd, "state_socket_unencoded", &statefile); + if (ret) + goto out; + ret = glusterd_gsync_fetch_status_extra (statefile, buf, sizeof (buf)); + if (ret) { + gf_log ("", GF_LOG_ERROR, "Unable to fetch extra status" + "for %s(master), %s(slave)", master, slave); + /* there is a slight chance that this occurs due to race + * -- in that case, the following options all seem bad: + * + * - suppress irregurlar behavior by just leaving status + * on "OK" + * - freak out users with a misleading "defunct" + * - overload the meaning of the regular error signal + * mechanism of gsyncd, that is, when status is "faulty" + * + * -- so we just come up with something new... + */ + strncpy (buf, "N/A", sizeof (buf)); goto done; + } + + done: + if ((!strcmp (buf, "defunct")) || + (!strcmp (buf, "Not Started")) || + (!strcmp (buf, "Stopped"))) { + ret = glusterd_get_local_brickpaths (volinfo, &path_list); + if (!path_list) { + gf_log ("", GF_LOG_DEBUG, "This node not being part of" + " volume should not be running gsyncd. Hence" + " shouldn't display status for this node."); + ret = 0; + goto out; + } + } + + ret = dict_get_int32 (dict, "gsync-count", &gsync_count); + + if (ret) + gsync_count = 1; + else + gsync_count++; + + (void) snprintf (nds, sizeof (nds), "node%d", gsync_count); + dyn_node = gf_strdup (node); + if (!dyn_node) + goto out; + ret = dict_set_dynstr (dict, nds, dyn_node); + if (ret) { + GF_FREE (dyn_node); + goto out; + } + + snprintf (mst, sizeof (mst), "master%d", gsync_count); + master = gf_strdup (master); + if (!master) + goto out; + ret = dict_set_dynstr (dict, mst, master); + if (ret) { + GF_FREE (master); + goto out; + } + + snprintf (slv, sizeof (slv), "slave%d", gsync_count); + slave = gf_strdup (slave); + if (!slave) + goto out; + ret = dict_set_dynstr (dict, slv, slave); + if (ret) { + GF_FREE (slave); + goto out; + } + + snprintf (sts, sizeof (slv), "status%d", gsync_count); + bufp = gf_strdup (buf); + if (!bufp) + goto out; + ret = dict_set_dynstr (dict, sts, bufp); + if (ret) { + GF_FREE (bufp); + goto out; + } + ret = dict_set_int32 (dict, "gsync-count", gsync_count); + if (ret) + goto out; + + ret = 0; + out: + dict_destroy (confd); + + gf_log ("", GF_LOG_DEBUG, "Returning %d ", ret); + return ret; +} + +static int +glusterd_check_restart_gsync_session (glusterd_volinfo_t *volinfo, char *slave, + dict_t *resp_dict, char *path_list, + char *conf_path, gf_boolean_t is_force) +{ + + int ret = 0; + glusterd_conf_t *priv = NULL; + char *status_msg = NULL; + gf_boolean_t is_running = _gf_false; + + GF_ASSERT (volinfo); + GF_ASSERT (slave); + GF_ASSERT (THIS); + GF_ASSERT (THIS->private); + + priv = THIS->private; + + ret = glusterd_check_gsync_running_local (volinfo->volname, + slave, conf_path, + &is_running); + if (!ret && (_gf_true != is_running)) + /* gsynd not running, nothing to do */ + goto out; + + ret = stop_gsync (volinfo->volname, slave, &status_msg, + conf_path, is_force); + if (ret == 0 && status_msg) + ret = dict_set_str (resp_dict, "gsync-status", + status_msg); + if (ret == 0) + ret = glusterd_start_gsync (volinfo, slave, path_list, + conf_path, uuid_utoa(MY_UUID), + NULL); + + out: + gf_log ("", GF_LOG_DEBUG, "Returning %d", ret); + return ret; +} + +static int32_t +glusterd_marker_changelog_create_volfile (glusterd_volinfo_t *volinfo) +{ + int32_t ret = 0; + + ret = glusterd_create_volfiles_and_notify_services (volinfo); + if (ret) { + gf_log ("", GF_LOG_ERROR, "Unable to create volfile" + " for setting of marker while '"GEOREP" start'"); + ret = -1; + goto out; + } + + ret = glusterd_store_volinfo (volinfo, GLUSTERD_VOLINFO_VER_AC_INCREMENT); + if (ret) + goto out; + + if (GLUSTERD_STATUS_STARTED == volinfo->status) + ret = glusterd_nodesvcs_handle_graph_change (volinfo); + ret = 0; +out: + return ret; +} + +static int +glusterd_set_gsync_knob (glusterd_volinfo_t *volinfo, char *key, int *vc) +{ + int ret = -1; + int conf_enabled = _gf_false; + char *knob_on = NULL; + + GF_ASSERT (THIS); + GF_ASSERT (THIS->private); + + conf_enabled = glusterd_volinfo_get_boolean (volinfo, key); + if (conf_enabled == -1) { + gf_log ("", GF_LOG_ERROR, + "failed to get key %s from volinfo", key); + goto out; + } + + ret = 0; + if (conf_enabled == _gf_false) { + *vc = 1; + knob_on = gf_strdup ("on"); + if (knob_on == NULL) { + ret = -1; + goto out; + } + + ret = glusterd_gsync_volinfo_dict_set (volinfo, + key, knob_on); + } + + out: + gf_log ("", GF_LOG_DEBUG, "Returning %d", ret); + return ret; +} + +static int +glusterd_set_gsync_confs (glusterd_volinfo_t *volinfo) +{ + int ret = -1; + int volfile_changed = 0; + + ret = glusterd_set_gsync_knob (volinfo, + VKEY_MARKER_XTIME, &volfile_changed); + if (ret) + goto out; + + ret = glusterd_set_gsync_knob (volinfo, + VKEY_CHANGELOG, &volfile_changed); + if (ret) + goto out; + + if (volfile_changed) + ret = glusterd_marker_changelog_create_volfile (volinfo); + + out: + return ret; +} + +static int +glusterd_get_gsync_status_mst_slv (glusterd_volinfo_t *volinfo, + char *slave, char *conf_path, + dict_t *rsp_dict, char *node) +{ + char *statefile = NULL; + uuid_t uuid = {0, }; + glusterd_conf_t *priv = NULL; + int ret = 0; + struct stat stbuf = {0, }; + + GF_ASSERT (volinfo); + GF_ASSERT (slave); + GF_ASSERT (THIS); + GF_ASSERT (THIS->private); - ret = dict_get_param (confd, "state_socket_unencoded", &statefile); - if (ret) - goto out; - ret = glusterd_gsync_fetch_status_extra (statefile, buf, sizeof (buf)); + priv = THIS->private; + + ret = glusterd_gsync_get_uuid (slave, volinfo, uuid); if (ret) { - gf_log ("", GF_LOG_ERROR, "Unable to fetch extra status" - "for %s(master), %s(slave)", master, slave); - /* there is a slight chance that this occurs due to race - * -- in that case, the following options all seem bad: - * - * - suppress irregurlar behavior by just leaving status - * on "OK" - * - freak out users with a misleading "defunct" - * - overload the meaning of the regular error signal - * mechanism of gsyncd, that is, when status is "faulty" - * - * -- so we just come up with something new... - */ - strncpy (buf, "N/A", sizeof (buf)); - goto done; + gf_log ("", GF_LOG_INFO, "geo-replication status %s %s :" + "session is not active", volinfo->volname, slave); + + ret = glusterd_get_statefile_name (volinfo, slave, + conf_path, &statefile); + if (ret) { + if (!strstr(slave, "::")) + gf_log ("", GF_LOG_INFO, + "%s is not a valid slave url.", slave); + else + gf_log ("", GF_LOG_INFO, "Unable to get" + " statefile's name"); + ret = 0; + goto out; + } + + ret = lstat (statefile, &stbuf); + if (ret) { + gf_log ("", GF_LOG_INFO, "%s statefile not present.", + statefile); + ret = 0; + goto out; + } } - done: - ret = dict_get_int32 (dict, "gsync-count", &gsync_count); + ret = glusterd_read_status_file (volinfo, slave, conf_path, + rsp_dict, node); +out: + if (statefile) + GF_FREE (statefile); - if (ret) - gsync_count = 1; - else - gsync_count++; + gf_log ("", GF_LOG_DEBUG, "Returning with %d", ret); + return ret; +} - (void) snprintf (nds, sizeof (nds), "node%d", gsync_count); - dyn_node = gf_strdup (node); - if (!dyn_node) - goto out; - ret = dict_set_dynstr (dict, nds, dyn_node); - if (ret) { - GF_FREE (dyn_node); - goto out; +static int +glusterd_get_gsync_status_mst (glusterd_volinfo_t *volinfo, dict_t *rsp_dict, + char *node) +{ + glusterd_gsync_status_temp_t param = {0, }; + + GF_ASSERT (volinfo); + + param.rsp_dict = rsp_dict; + param.volinfo = volinfo; + param.node = node; + dict_foreach (volinfo->gsync_slaves, _get_status_mst_slv, ¶m); + + return 0; +} + +static int +glusterd_get_gsync_status_all (dict_t *rsp_dict, char *node) +{ + + int32_t ret = 0; + glusterd_conf_t *priv = NULL; + glusterd_volinfo_t *volinfo = NULL; + + GF_ASSERT (THIS); + priv = THIS->private; + + GF_ASSERT (priv); + + list_for_each_entry (volinfo, &priv->volumes, vol_list) { + ret = glusterd_get_gsync_status_mst (volinfo, rsp_dict, node); + if (ret) + goto out; } - snprintf (mst, sizeof (mst), "master%d", gsync_count); - master = gf_strdup (master); - if (!master) - goto out; - ret = dict_set_dynstr (dict, mst, master); +out: + gf_log ("", GF_LOG_DEBUG, "Returning with %d", ret); + return ret; + +} + +static int +glusterd_get_gsync_status (dict_t *dict, char **op_errstr, dict_t *rsp_dict) +{ + char *slave = NULL; + char *volname = NULL; + char *conf_path = NULL; + char errmsg[PATH_MAX] = {0, }; + gf_boolean_t exists = _gf_false; + glusterd_volinfo_t *volinfo = NULL; + int ret = 0; + char my_hostname[256] = {0,}; + + ret = gethostname(my_hostname, 256); if (ret) { - GF_FREE (master); - goto out; + /* stick to N/A */ + (void) strcpy (my_hostname, "N/A"); } - snprintf (slv, sizeof (slv), "slave%d", gsync_count); - slave = gf_strdup (slave); - if (!slave) + ret = dict_get_str (dict, "master", &volname); + if (ret < 0){ + ret = glusterd_get_gsync_status_all (rsp_dict, my_hostname); goto out; - ret = dict_set_dynstr (dict, slv, slave); - if (ret) { - GF_FREE (slave); + } + + exists = glusterd_check_volume_exists (volname); + ret = glusterd_volinfo_find (volname, &volinfo); + if ((ret) || (!exists)) { + gf_log ("", GF_LOG_WARNING, "volume name does not exist"); + snprintf (errmsg, sizeof(errmsg), "Volume name %s does not" + " exist", volname); + *op_errstr = gf_strdup (errmsg); + ret = -1; goto out; } - snprintf (sts, sizeof (slv), "status%d", gsync_count); - bufp = gf_strdup (buf); - if (!bufp) + + ret = dict_get_str (dict, "slave", &slave); + if (ret < 0) { + ret = glusterd_get_gsync_status_mst (volinfo, + rsp_dict, my_hostname); goto out; - ret = dict_set_dynstr (dict, sts, bufp); + } + + ret = dict_get_str (dict, "conf_path", &conf_path); if (ret) { - GF_FREE (bufp); + gf_log ("", GF_LOG_ERROR, + "Unable to fetch conf file path."); goto out; } - ret = dict_set_int32 (dict, "gsync-count", gsync_count); - if (ret) - goto out; - ret = 0; - out: - dict_destroy (confd); + ret = glusterd_get_gsync_status_mst_slv (volinfo, slave, conf_path, + rsp_dict, my_hostname); - gf_log ("", GF_LOG_DEBUG, "Returning %d ", ret); + out: + gf_log ("", GF_LOG_DEBUG, "Returning %d", ret); return ret; } static int -glusterd_check_restart_gsync_session (glusterd_volinfo_t *volinfo, char *slave, - dict_t *resp_dict) +glusterd_gsync_delete (glusterd_volinfo_t *volinfo, char *slave, + char *slave_vol, char *path_list, dict_t *dict, + dict_t *resp_dict, char **op_errstr) { + int32_t ret = -1; + runner_t runner = {0,}; + glusterd_conf_t *priv = NULL; + char *master = NULL; + char *gl_workdir = NULL; + char geo_rep_dir[PATH_MAX] = ""; + char *conf_path = NULL; - int ret = 0; - uuid_t uuid = {0, }; - glusterd_conf_t *priv = NULL; - char *status_msg = NULL; - - GF_ASSERT (volinfo); GF_ASSERT (slave); - GF_ASSERT (THIS); - GF_ASSERT (THIS->private); + GF_ASSERT (slave_vol); + GF_ASSERT (op_errstr); + GF_ASSERT (dict); + GF_ASSERT (resp_dict); - priv = THIS->private; + if (THIS) + priv = THIS->private; + if (priv == NULL) { + gf_log ("", GF_LOG_ERROR, "priv of glusterd not present"); + *op_errstr = gf_strdup ("glusterd defunct"); + goto out; + } - if (glusterd_gsync_get_uuid (slave, volinfo, uuid)) - /* session does not exist, nothing to do */ + ret = dict_get_str (dict, "conf_path", &conf_path); + if (ret) { + gf_log ("", GF_LOG_ERROR, + "Unable to fetch conf file path."); goto out; - if (uuid_compare (MY_UUID, uuid) == 0) { - ret = stop_gsync (volinfo->volname, slave, &status_msg); - if (ret == 0 && status_msg) - ret = dict_set_str (resp_dict, "gsync-status", - status_msg); - if (ret == 0) - ret = glusterd_start_gsync (volinfo, slave, - uuid_utoa(MY_UUID), NULL); } - out: + gl_workdir = priv->workdir; + master = ""; + runinit (&runner); + runner_add_args (&runner, GSYNCD_PREFIX"/gsyncd", + "--delete", "-c", NULL); + runner_argprintf (&runner, "%s", conf_path); + + if (volinfo) { + master = volinfo->volname; + runner_argprintf (&runner, ":%s", master); + } + runner_add_arg (&runner, slave); + runner_redir (&runner, STDOUT_FILENO, RUN_PIPE); + synclock_unlock (&priv->big_lock); + ret = runner_run (&runner); + synclock_lock (&priv->big_lock); + if (ret) { + gf_log ("", GF_LOG_ERROR, "gsyncd failed to " + "delete session info for %s and %s peers", + master, slave); + + gf_asprintf (op_errstr, "gsyncd failed to " + "delete session info for %s and %s peers", + master, slave); + + goto out; + } + + ret = snprintf (geo_rep_dir, sizeof(geo_rep_dir) - 1, + "%s/"GEOREP"/%s-%s", gl_workdir, + volinfo->volname, slave_vol); + geo_rep_dir[ret] = '\0'; + + ret = rmdir (geo_rep_dir); + if (ret) { + if (errno == ENOENT) + gf_log ("", GF_LOG_DEBUG, "Geo Rep Dir(%s) Not Present.", + geo_rep_dir); + else { + gf_log ("", GF_LOG_ERROR, "Unable to delete " + "Geo Rep Dir(%s). Error: %s", geo_rep_dir, + strerror (errno)); + goto out; + } + } + + ret = 0; + + gf_asprintf (op_errstr, "delete successful"); + +out: gf_log ("", GF_LOG_DEBUG, "Returning %d", ret); return ret; } -static int32_t -glusterd_marker_create_volfile (glusterd_volinfo_t *volinfo) +int +glusterd_op_sys_exec (dict_t *dict, char **op_errstr, dict_t *rsp_dict) { - int32_t ret = 0; + char buf[PATH_MAX] = ""; + char cmd_arg_name[PATH_MAX] = ""; + char output_name[PATH_MAX] = ""; + char errmsg[PATH_MAX] = ""; + char *ptr = NULL; + char *bufp = NULL; + char *command = NULL; + char **cmd_args = NULL; + int ret = -1; + int i = -1; + int cmd_args_count = 0; + int output_count = 0; + glusterd_conf_t *priv = NULL; + runner_t runner = {0,}; - ret = glusterd_create_volfiles_and_notify_services (volinfo); + GF_ASSERT (dict); + GF_ASSERT (op_errstr); + GF_ASSERT (rsp_dict); + + if (THIS) + priv = THIS->private; + if (priv == NULL) { + gf_log ("", GF_LOG_ERROR, "priv of glusterd not present"); + *op_errstr = gf_strdup ("glusterd defunct"); + goto out; + } + + ret = dict_get_str (dict, "command", &command); if (ret) { - gf_log ("", GF_LOG_ERROR, "Unable to create volfile" - " for setting of marker while '"GEOREP" start'"); + gf_log ("", GF_LOG_ERROR, + "Unable to get command from dict"); + goto out; + } + + ret = dict_get_int32 (dict, "cmd_args_count", &cmd_args_count); + if (ret) + gf_log ("", GF_LOG_INFO, "No cmd_args_count"); + + if (cmd_args_count) { + cmd_args = GF_CALLOC (cmd_args_count, sizeof (char*), + gf_common_mt_char); + if (!cmd_args) { + gf_log ("", GF_LOG_ERROR, "Unable to calloc. " + "Errno = %s", strerror(errno)); + goto out; + } + + for (i=1; i <= cmd_args_count; i++) { + memset (cmd_arg_name, '\0', sizeof(cmd_arg_name)); + snprintf (cmd_arg_name, sizeof(cmd_arg_name), + "cmd_arg_%d", i); + ret = dict_get_str (dict, cmd_arg_name, &cmd_args[i-1]); + if (ret) { + gf_log ("", GF_LOG_ERROR, + "Unable to get %s in dict", + cmd_arg_name); + goto out; + } + } + } + + runinit (&runner); + runner_argprintf (&runner, GSYNCD_PREFIX"/peer_%s", command); + for (i=0; i < cmd_args_count; i++) + runner_add_arg (&runner, cmd_args[i]); + runner_redir (&runner, STDOUT_FILENO, RUN_PIPE); + synclock_unlock (&priv->big_lock); + ret = runner_start (&runner); + if (ret == -1) { + snprintf (errmsg, sizeof (errmsg), "Unable to " + "execute command. Error : %s", + strerror (errno)); + *op_errstr = gf_strdup (errmsg); + gf_log ("", GF_LOG_ERROR, "%s", errmsg); + ret = -1; + synclock_lock (&priv->big_lock); + goto out; + } + + ptr = fgets(buf, sizeof(buf), runner_chio (&runner, STDOUT_FILENO)); + if (ptr) { + ret = dict_get_int32 (rsp_dict, "output_count", &output_count); + if (ret) + output_count = 1; + else + output_count++; + memset (output_name, '\0', sizeof (output_name)); + snprintf (output_name, sizeof (output_name), + "output_%d", output_count); + if (buf[strlen(buf) - 1] == '\n') + buf[strlen(buf) - 1] = '\0'; + bufp = gf_strdup (buf); + if (!bufp) + gf_log ("", GF_LOG_ERROR, "gf_strdup failed."); + ret = dict_set_dynstr (rsp_dict, output_name, bufp); + if (ret) { + GF_FREE (bufp); + gf_log ("", GF_LOG_ERROR, "output set failed."); + } + ret = dict_set_int32 (rsp_dict, "output_count", output_count); + if (ret) + gf_log ("", GF_LOG_ERROR, "output_count set failed."); + } + + ret = runner_end (&runner); + if (ret) { + snprintf (errmsg, sizeof (errmsg), "Unable to " + "end. Error : %s", + strerror (errno)); + *op_errstr = gf_strdup (errmsg); + gf_log ("", GF_LOG_ERROR, "%s", errmsg); ret = -1; + synclock_lock (&priv->big_lock); goto out; } + synclock_lock (&priv->big_lock); - ret = glusterd_store_volinfo (volinfo, GLUSTERD_VOLINFO_VER_AC_INCREMENT); - if (ret) - goto out; - - if (GLUSTERD_STATUS_STARTED == volinfo->status) - ret = glusterd_nodesvcs_handle_graph_change (volinfo); ret = 0; out: + if (cmd_args) { + GF_FREE (cmd_args); + cmd_args = NULL; + } + + gf_log ("", GF_LOG_DEBUG, "Returning %d", ret); return ret; } -static int -glusterd_set_marker_gsync (glusterd_volinfo_t *volinfo) +int +glusterd_op_copy_file (dict_t *dict, char **op_errstr) { - int ret = -1; - int marker_set = _gf_false; - char *gsync_status = NULL; + char abs_filename[PATH_MAX] = ""; + char errmsg[PATH_MAX] = ""; + char *filename = NULL; + char *host_uuid = NULL; + char uuid_str [64] = {0}; + char *contents = NULL; + char buf[1024] = ""; + int ret = -1; + int fd = -1; + int bytes_writen = 0; + int bytes_read = 0; + int contents_size = -1; + int file_mode = -1; + glusterd_conf_t *priv = NULL; + struct stat stbuf = {0,}; - GF_ASSERT (THIS); - GF_ASSERT (THIS->private); - marker_set = glusterd_volinfo_get_boolean (volinfo, VKEY_MARKER_XTIME); - if (marker_set == -1) { - gf_log ("", GF_LOG_ERROR, "failed to get the marker status"); - ret = -1; + if (THIS) + priv = THIS->private; + if (priv == NULL) { + gf_log ("", GF_LOG_ERROR, "priv of glusterd not present"); + *op_errstr = gf_strdup ("glusterd defunct"); + goto out; + } + + ret = dict_get_str (dict, "host-uuid", &host_uuid); + if (ret < 0) goto out; + + ret = dict_get_str (dict, "source", &filename); + if (ret < 0) { + gf_log ("", GF_LOG_ERROR, "Unable to fetch" + " filename from dict."); + *op_errstr = gf_strdup ("command unsuccessful"); + goto out; } + snprintf (abs_filename, sizeof(abs_filename), + "%s/%s", priv->workdir, filename); + + uuid_utoa_r (MY_UUID, uuid_str); + if (!strcmp (uuid_str, host_uuid)) { + ret = lstat (abs_filename, &stbuf); + if (ret) { + snprintf (errmsg, sizeof (errmsg), "Source file" + " does not exist in %s", priv->workdir); + *op_errstr = gf_strdup (errmsg); + gf_log ("", GF_LOG_ERROR, "%s", errmsg); + goto out; + } - if (marker_set == _gf_false) { - gsync_status = gf_strdup ("on"); - if (gsync_status == NULL) { + contents = GF_CALLOC(1, stbuf.st_size+1, gf_common_mt_char); + if (!contents) { + snprintf (errmsg, sizeof (errmsg), + "Unable to allocate memory"); + *op_errstr = gf_strdup (errmsg); + gf_log ("", GF_LOG_ERROR, "%s", errmsg); ret = -1; goto out; } - ret = glusterd_gsync_volinfo_dict_set (volinfo, - VKEY_MARKER_XTIME, gsync_status); - if (ret < 0) + fd = open (abs_filename, O_RDONLY); + if (fd < 0) { + snprintf (errmsg, sizeof (errmsg), "Unable to open %s", + abs_filename); + *op_errstr = gf_strdup (errmsg); + gf_log ("", GF_LOG_ERROR, "%s", errmsg); + ret = -1; goto out; + } - ret = glusterd_marker_create_volfile (volinfo); - if (ret) { - gf_log ("", GF_LOG_ERROR, "Setting dict failed"); + do { + ret = read (fd, buf, sizeof(buf)); + if (ret > 0) { + memcpy (contents+bytes_read, buf, ret); + bytes_read += ret; + memset (buf, '\0', sizeof(buf)); + } + } while (ret > 0); + + if (bytes_read != stbuf.st_size) { + snprintf (errmsg, sizeof (errmsg), "Unable to read all " + "the data from %s", abs_filename); + *op_errstr = gf_strdup (errmsg); + gf_log ("", GF_LOG_ERROR, "%s", errmsg); + ret = -1; goto out; } - } - ret = 0; -out: - gf_log ("", GF_LOG_DEBUG, "Returning %d", ret); - return ret; -} + ret = dict_set_int32 (dict, "contents_size", stbuf.st_size); + if (ret) { + snprintf (errmsg, sizeof (errmsg), "Unable to set" + " contents size in dict."); + *op_errstr = gf_strdup (errmsg); + gf_log ("", GF_LOG_ERROR, "%s", errmsg); + goto out; + } + ret = dict_set_int32 (dict, "file_mode", + (int32_t)stbuf.st_mode); + if (ret) { + snprintf (errmsg, sizeof (errmsg), "Unable to set" + " file mode in dict."); + *op_errstr = gf_strdup (errmsg); + gf_log ("", GF_LOG_ERROR, "%s", errmsg); + goto out; + } + ret = dict_set_bin (dict, "common_pem_contents", + contents, stbuf.st_size); + if (ret) { + snprintf (errmsg, sizeof (errmsg), "Unable to set" + " pem contents in dict."); + *op_errstr = gf_strdup (errmsg); + gf_log ("", GF_LOG_ERROR, "%s", errmsg); + goto out; + } + close (fd); + } else { + ret = dict_get_bin (dict, "common_pem_contents", + (void **) &contents); + if (ret) { + snprintf (errmsg, sizeof (errmsg), "Unable to get" + " pem contents in dict."); + *op_errstr = gf_strdup (errmsg); + gf_log ("", GF_LOG_ERROR, "%s", errmsg); + goto out; + } + ret = dict_get_int32 (dict, "contents_size", &contents_size); + if (ret) { + snprintf (errmsg, sizeof (errmsg), "Unable to set" + " contents size in dict."); + *op_errstr = gf_strdup (errmsg); + gf_log ("", GF_LOG_ERROR, "%s", errmsg); + goto out; + } -static int -glusterd_get_gsync_status_mst_slv (glusterd_volinfo_t *volinfo, - char *slave, dict_t *rsp_dict, - char *node) -{ - uuid_t uuid = {0, }; - glusterd_conf_t *priv = NULL; - int ret = 0; + ret = dict_get_int32 (dict, "file_mode", &file_mode); + if (ret) { + snprintf (errmsg, sizeof (errmsg), "Unable to get" + " file mode in dict."); + *op_errstr = gf_strdup (errmsg); + gf_log ("", GF_LOG_ERROR, "%s", errmsg); + goto out; + } - GF_ASSERT (volinfo); - GF_ASSERT (slave); - GF_ASSERT (THIS); - GF_ASSERT (THIS->private); + fd = open (abs_filename, O_WRONLY | O_TRUNC | O_CREAT, 0600); + if (fd < 0) { + snprintf (errmsg, sizeof (errmsg), "Unable to open %s", + abs_filename); + *op_errstr = gf_strdup (errmsg); + gf_log ("", GF_LOG_ERROR, "%s", errmsg); + ret = -1; + goto out; + } - priv = THIS->private; + bytes_writen = write (fd, contents, contents_size); - ret = glusterd_gsync_get_uuid (slave, volinfo, uuid); - if ((ret == 0) && (uuid_compare (MY_UUID, uuid) != 0)) - goto out; + if (bytes_writen != contents_size) { + snprintf (errmsg, sizeof (errmsg), "Failed to write" + " to %s", abs_filename); + *op_errstr = gf_strdup (errmsg); + gf_log ("", GF_LOG_ERROR, "%s", errmsg); + ret = -1; + goto out; + } - if (ret) { - ret = 0; - gf_log ("", GF_LOG_INFO, "geo-replication status %s %s :" - "session is not active", volinfo->volname, slave); - goto out; + fchmod (fd, file_mode); + close (fd); } - ret = glusterd_read_status_file (volinfo->volname, - slave, rsp_dict, node); - out: - gf_log ("", GF_LOG_DEBUG, "Returning with %d", ret); + ret = 0; +out: + gf_log ("", GF_LOG_DEBUG, "Returning %d", ret); return ret; } -static int -glusterd_get_gsync_status_mst (glusterd_volinfo_t *volinfo, dict_t *rsp_dict, - char *node) -{ - glusterd_gsync_status_temp_t param = {0, }; - - GF_ASSERT (volinfo); - - param.rsp_dict = rsp_dict; - param.volinfo = volinfo; - param.node = node; - dict_foreach (volinfo->gsync_slaves, _get_status_mst_slv, ¶m); - - return 0; -} - -static int -glusterd_get_gsync_status_all (dict_t *rsp_dict, char *node) +int +glusterd_op_gsync_set (dict_t *dict, char **op_errstr, dict_t *rsp_dict) { - - int32_t ret = 0; - glusterd_conf_t *priv = NULL; - glusterd_volinfo_t *volinfo = NULL; + int32_t ret = -1; + int32_t type = -1; + dict_t *ctx = NULL; + dict_t *resp_dict = NULL; + char *host_uuid = NULL; + char *slave = NULL; + char *slave_vol = NULL; + char *volname = NULL; + char *path_list = NULL; + glusterd_volinfo_t *volinfo = NULL; + glusterd_conf_t *priv = NULL; + gf_boolean_t is_force = _gf_false; + char *status_msg = NULL; + gf_boolean_t is_running = _gf_false; + char *conf_path = NULL; GF_ASSERT (THIS); + GF_ASSERT (THIS->private); + GF_ASSERT (dict); + GF_ASSERT (op_errstr); + priv = THIS->private; - GF_ASSERT (priv); + ret = dict_get_int32 (dict, "type", &type); + if (ret < 0) + goto out; - list_for_each_entry (volinfo, &priv->volumes, vol_list) { - ret = glusterd_get_gsync_status_mst (volinfo, rsp_dict, node); - if (ret) - goto out; - } + ret = dict_get_str (dict, "host-uuid", &host_uuid); + if (ret < 0) + goto out; -out: - gf_log ("", GF_LOG_DEBUG, "Returning with %d", ret); - return ret; + ctx = glusterd_op_get_ctx (); + resp_dict = ctx ? ctx : rsp_dict; + GF_ASSERT (resp_dict); -} + if (type == GF_GSYNC_OPTION_TYPE_STATUS) { + ret = glusterd_get_gsync_status (dict, op_errstr, resp_dict); + goto out; + } -static int -glusterd_get_gsync_status (dict_t *dict, char **op_errstr, dict_t *rsp_dict) -{ - char *slave = NULL; - char *volname = NULL; - char errmsg[PATH_MAX] = {0, }; - gf_boolean_t exists = _gf_false; - glusterd_volinfo_t *volinfo = NULL; - int ret = 0; - char my_hostname[256] = {0,}; + ret = dict_get_str (dict, "slave", &slave); + if (ret < 0) + goto out; - ret = gethostname(my_hostname, 256); + ret = dict_get_str (dict, "slave_vol", &slave_vol); if (ret) { - /* stick to N/A */ - (void) strcpy (my_hostname, "N/A"); + gf_log ("", GF_LOG_ERROR, "Unable to fetch slave volume name."); + goto out; } - ret = dict_get_str (dict, "master", &volname); - if (ret < 0){ - ret = glusterd_get_gsync_status_all (rsp_dict, my_hostname); + ret = dict_get_str (dict, "conf_path", &conf_path); + if (ret) { + gf_log ("", GF_LOG_ERROR, + "Unable to fetch conf file path."); goto out; } - exists = glusterd_check_volume_exists (volname); - ret = glusterd_volinfo_find (volname, &volinfo); - if ((ret) || (!exists)) { - gf_log ("", GF_LOG_WARNING, "volume name does not exist"); - snprintf (errmsg, sizeof(errmsg), "Volume name %s does not" - " exist", volname); - *op_errstr = gf_strdup (errmsg); - ret = -1; + if (dict_get_str (dict, "master", &volname) == 0) { + ret = glusterd_volinfo_find (volname, &volinfo); + if (ret) { + gf_log ("", GF_LOG_WARNING, "Volinfo for %s (master) not found", + volname); + goto out; + } + + ret = glusterd_get_local_brickpaths (volinfo, &path_list); + } + + if (type == GF_GSYNC_OPTION_TYPE_CONFIG) { + ret = glusterd_gsync_configure (volinfo, slave, path_list, + dict, resp_dict, op_errstr); goto out; } + if (type == GF_GSYNC_OPTION_TYPE_DELETE) { + ret = glusterd_remove_slave_in_info(volinfo, slave, op_errstr); + if (ret && !is_force && path_list) + goto out; - ret = dict_get_str (dict, "slave", &slave); - if (ret < 0) { - ret = glusterd_get_gsync_status_mst (volinfo, - rsp_dict, my_hostname); + ret = glusterd_gsync_delete (volinfo, slave, slave_vol, + path_list, dict, resp_dict, + op_errstr); goto out; } - ret = glusterd_get_gsync_status_mst_slv (volinfo, slave, - rsp_dict, my_hostname); + if (!volinfo) { + ret = -1; + goto out; + } - out: - gf_log ("", GF_LOG_DEBUG, "Returning %d", ret); - return ret; -} + is_force = dict_get_str_boolean (dict, "force", _gf_false); -static int -glusterd_send_sigstop (pid_t pid) -{ - int ret = 0; - ret = kill (pid, SIGSTOP); - if (ret) - gf_log ("", GF_LOG_ERROR, GEOREP"failed to send SIGSTOP signal"); - return ret; -} + if (type == GF_GSYNC_OPTION_TYPE_START) { -static int -glusterd_send_sigcont (pid_t pid) -{ - int ret = 0; - ret = kill (pid, SIGCONT); - if (ret) - gf_log ("", GF_LOG_ERROR, GEOREP"failed to send SIGCONT signal"); - return ret; -} + ret = glusterd_set_gsync_confs (volinfo); + if (ret != 0) { + gf_log ("", GF_LOG_WARNING, "marker/changelog start failed"); + *op_errstr = gf_strdup ("failed to initialize indexing"); + ret = -1; + goto out; + } -/* - * Log rotations flow is something like this: - * - Send SIGSTOP to process group (this will stop monitor/worker process - * and also the slave if it's local) - * - Rotate log file for monitor/worker - * - Rotate log file for slave if it's local - * - Send SIGCONT to the process group. Monitor wakes up, kills the worker - * (this is done in the SIGCONT handler), which results in the termination - * of the slave (local/remote). After returning from signal handler, - * monitor detects absence of worker and starts it again, which in-turn - * starts the slave. - */ -static int -glusterd_send_log_rotate_signal (pid_t pid, char *logfile1, char *logfile2) -{ - int ret = 0; - char rlogfile[PATH_MAX] = {0,}; - time_t rottime = 0; + ret = glusterd_start_gsync (volinfo, slave, path_list, + conf_path, host_uuid, op_errstr); + } - ret = glusterd_send_sigstop (-pid); - rottime = time (NULL); + if (type == GF_GSYNC_OPTION_TYPE_STOP) { + ret = glusterd_check_gsync_running_local (volinfo->volname, + slave, conf_path, + &is_running); + if (!ret && !is_force && path_list && + (_gf_true != is_running)) { + gf_log ("", GF_LOG_WARNING, GEOREP" is not set up for" + "%s(master) and %s(slave)", volname, slave); + *op_errstr = strdup (GEOREP" is not set up"); + goto out; + } - snprintf (rlogfile, sizeof (rlogfile), "%s.%"PRIu64, logfile1, - (uint64_t) rottime); - ret = rename (logfile1, rlogfile); - if (ret) - gf_log ("", GF_LOG_ERROR, "rename failed for geo-rep log file"); + ret = stop_gsync (volname, slave, &status_msg, conf_path, is_force); + if (ret == 0 && status_msg) + ret = dict_set_str (resp_dict, "gsync-status", + status_msg); + if (ret != 0 && !is_force && path_list) + *op_errstr = gf_strdup ("internal error"); - if (!*logfile2) { - gf_log ("", GF_LOG_DEBUG, "Slave is not local," - " skipping rotation"); - ret = 0; - goto out; + if (!ret) { + ret = glusterd_create_status_file (volinfo->volname, + slave, slave_vol, "Stopped"); + if (ret) { + gf_log ("", GF_LOG_ERROR, "Unable to update" + "state_file. Error : %s", + strerror (errno)); + } + } } - (void) snprintf (rlogfile, sizeof (rlogfile), "%s.%"PRIu64, logfile2, - (uint64_t) rottime); - ret = rename (logfile2, rlogfile); - if (ret) - gf_log ("", GF_LOG_ERROR, "rename failed for geo-rep slave" - " log file"); - - out: - ret = glusterd_send_sigcont (-pid); +out: + if (path_list) { + GF_FREE (path_list); + path_list = NULL; + } + gf_log ("", GF_LOG_DEBUG, "Returning %d", ret); return ret; } static int -glusterd_get_pid_from_file (char *master, char *slave, pid_t *pid) +glusterd_get_slave_details_confpath (glusterd_volinfo_t *volinfo, dict_t *dict, + char **slave_ip, char **slave_vol, + char **conf_path) { - int ret = -1; - int pfd = 0; - char pidfile[PATH_MAX] = {0,}; - char buff[1024] = {0,}; + int ret = -1; + char confpath[PATH_MAX] = ""; + glusterd_conf_t *priv = NULL; - pfd = gsyncd_getpidfile (master, slave, pidfile); - if (pfd == -2) { - gf_log ("", GF_LOG_ERROR, GEOREP" log-rotate validation " - " failed for %s & %s", master, slave); - goto out; - } - if (gsync_status_byfd (pfd) == -1) { - gf_log ("", GF_LOG_ERROR, "gsyncd b/w %s & %s is not" - " running", master, slave); + GF_ASSERT (THIS); + priv = THIS->private; + GF_ASSERT (priv); + + ret = glusterd_get_slave_info (dict, slave_ip, slave_vol); + if (ret) { + gf_log ("", GF_LOG_ERROR, + "Unable to fetch slave details."); + ret = -1; goto out; } - if (pfd < 0) + ret = snprintf (confpath, sizeof(confpath) - 1, + "%s/"GEOREP"/%s-%s/gsyncd.conf", + priv->workdir, volinfo->volname, *slave_vol); + confpath[ret] = '\0'; + *conf_path = gf_strdup (confpath); + if (!(*conf_path)) { + gf_log ("", GF_LOG_ERROR, + "Unable to gf_strdup. Error: %s", strerror (errno)); + ret = -1; goto out; + } - ret = read (pfd, buff, 1024); - if (ret < 0) { - gf_log ("", GF_LOG_ERROR, GEOREP" cannot read pid from pid-file"); + ret = dict_set_str (dict, "conf_path", *conf_path); + if (ret) { + gf_log ("", GF_LOG_ERROR, + "Unable to store conf_path"); goto out; } - - *pid = strtol (buff, NULL, 10); - ret = 0; - out: - sys_close(pfd); + gf_log ("", GF_LOG_DEBUG,"Returning %d", ret); return ret; + } static int -glusterd_do_gsync_log_rotate (char *master, char *slave, uuid_t *uuid, char **op_errstr) +glusterd_get_slave_info (dict_t *dict, char **slave_ip, char **slave_vol) { - int ret = 0; - glusterd_conf_t *priv = NULL; - pid_t pid = 0; - char log_file1[PATH_MAX] = {0,}; - char log_file2[PATH_MAX] = {0,}; - - GF_ASSERT (THIS); - GF_ASSERT (THIS->private); + char *tmp = NULL; + char *save_ptr = NULL; + char *slave = NULL; + char **linearr = NULL; + int32_t ret = -1; - priv = THIS->private; + GF_ASSERT (dict); - ret = glusterd_get_pid_from_file (master, slave, &pid); - if (ret) - goto out; + ret = dict_get_str (dict, "slave", &slave); + if (slave) { + ret = glusterd_urltransform_single (slave, "normalize", + &linearr); + if (ret == -1) { + gf_log ("", GF_LOG_ERROR, "Failed to normalize url"); + goto out; + } - /* log file */ - ret = glusterd_gsyncd_getlogfile (master, slave, log_file1); - if (ret) - goto out; + tmp = strtok_r (linearr[0], "/", &save_ptr); + tmp = strtok_r (NULL, "/", &save_ptr); + slave = strtok_r (tmp, ":", &save_ptr); + if (slave) { + *slave_ip = gf_strdup (slave); + if (!*slave_ip) { + gf_log ("", GF_LOG_ERROR, + "Failed to gf_strdup"); + ret = -1; + goto out; + } + gf_log ("", GF_LOG_DEBUG, "Slave IP : %s", *slave_ip); + ret = 0; + } else { + gf_log ("", GF_LOG_ERROR, "Invalid slave name"); + goto out; + } - /* check if slave is local or remote */ - ret = glusterd_gsync_slave_is_remote (slave); - if (ret) - goto do_rotate; + slave = strtok_r (NULL, ":", &save_ptr); + if (slave) { + *slave_vol = gf_strdup (slave); + 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; + } - /* slave log file - slave is local and it's log can be rotated */ - ret = glusterd_gsync_get_slave_log_file (master, slave, log_file2); - if (ret) - goto out; + ret = dict_set_str (dict, "slave_ip", *slave_ip); + if (ret) { + gf_log ("", GF_LOG_ERROR, + "Unable to store slave IP."); + goto out; + } - do_rotate: - ret = glusterd_send_log_rotate_signal (pid, log_file1, log_file2); + ret = dict_set_str (dict, "slave_vol", *slave_vol); + if (ret) { + gf_log ("", GF_LOG_ERROR, + "Unable to store slave volume name."); + goto out; + } + } else + gf_log ("", GF_LOG_ERROR, "Unable to fetch slave from dict"); - out: - if (ret && op_errstr) - *op_errstr = gf_strdup("Error rotating log file"); +out: + gf_log ("", GF_LOG_DEBUG, "Returning %d", ret); return ret; } -static int -glusterd_do_gsync_log_rotation_mst_slv (glusterd_volinfo_t *volinfo, char *slave, - char **op_errstr) +static void +runinit_gsyncd_setrx (runner_t *runner, char *conf_path) { - uuid_t uuid = {0, }; - glusterd_conf_t *priv = NULL; - int ret = 0; - char errmsg[1024] = {0,}; - xlator_t *this = NULL; + runinit (runner); + runner_add_args (runner, GSYNCD_PREFIX"/gsyncd", "-c", NULL); + runner_argprintf (runner, "%s", conf_path); + runner_add_arg (runner, "--config-set-rx"); +} - GF_ASSERT (volinfo); - GF_ASSERT (slave); - GF_ASSERT (THIS); - this = THIS; - GF_ASSERT (this->private); - priv = this->private; +static int +glusterd_check_gsync_present (int *valid_state) +{ + char buff[PATH_MAX] = {0, }; + runner_t runner = {0,}; + char *ptr = NULL; + int ret = 0; - ret = glusterd_gsync_get_uuid (slave, volinfo, uuid); - if ((ret == 0) && (uuid_compare (MY_UUID, uuid) != 0)) + runinit (&runner); + runner_add_args (&runner, GSYNCD_PREFIX"/gsyncd", "--version", NULL); + runner_redir (&runner, STDOUT_FILENO, RUN_PIPE); + ret = runner_start (&runner); + if (ret == -1) { + if (errno == ENOENT) { + gf_log ("glusterd", GF_LOG_INFO, GEOREP + " module not installed in the system"); + *valid_state = 0; + } + else { + gf_log ("glusterd", GF_LOG_ERROR, GEOREP + " module not working as desired"); + *valid_state = -1; + } goto out; + } - if (ret) { - snprintf(errmsg, sizeof(errmsg), "geo-replication session b/w %s %s not active", - volinfo->volname, slave); - gf_log (this->name, GF_LOG_WARNING, "%s", errmsg); - if (op_errstr) - *op_errstr = gf_strdup(errmsg); + ptr = fgets(buff, sizeof(buff), runner_chio (&runner, STDOUT_FILENO)); + if (ptr) { + if (!strstr (buff, "gsyncd")) { + ret = -1; + gf_log ("glusterd", GF_LOG_ERROR, GEOREP" module not " + "working as desired"); + *valid_state = -1; + goto out; + } + } else { + ret = -1; + gf_log ("glusterd", GF_LOG_ERROR, GEOREP" module not " + "working as desired"); + *valid_state = -1; goto out; } - ret = glusterd_do_gsync_log_rotate (volinfo->volname, slave, &uuid, op_errstr); - + ret = 0; out: - gf_log (this->name, GF_LOG_DEBUG, "Returning with %d", ret); - return ret; -} - -static int -_iterate_log_rotate_mst_slv (dict_t *this, char *key, data_t *value, void *data) -{ - glusterd_gsync_status_temp_t *param = NULL; - char *slave = NULL; - param = (glusterd_gsync_status_temp_t *) data; + runner_end (&runner); - GF_ASSERT (param); - GF_ASSERT (param->volinfo); - - slave = strchr (value->data, ':'); - if (slave) - slave++; - else { - gf_log ("", GF_LOG_ERROR, "geo-replication log-rotate: slave (%s) " - "not conforming to format", slave); - return -1; - } + gf_log ("glusterd", GF_LOG_DEBUG, "Returning %d", ret); + return ret; - (void) glusterd_do_gsync_log_rotation_mst_slv (param->volinfo, slave, NULL); - return 0; } static int -glusterd_do_gsync_log_rotation_mst (glusterd_volinfo_t *volinfo) +create_conf_file (glusterd_conf_t *conf, char *conf_path) +#define RUN_GSYNCD_CMD do { \ + ret = runner_run_reuse (&runner); \ + if (ret == -1) { \ + runner_log (&runner, "glusterd", GF_LOG_ERROR, "command failed"); \ + runner_end (&runner); \ + goto out; \ + } \ + runner_end (&runner); \ +} while (0) { - glusterd_gsync_status_temp_t param = {0, }; - - GF_ASSERT (volinfo); + int ret = 0; + runner_t runner = {0,}; + char georepdir[PATH_MAX] = {0,}; + int valid_state = 0; + + valid_state = -1; + ret = glusterd_check_gsync_present (&valid_state); + if (-1 == ret) { + ret = valid_state; + goto out; + } + + ret = snprintf (georepdir, sizeof(georepdir) - 1, "%s/"GEOREP, + conf->workdir); + georepdir[ret] = '\0'; + + /************ + * master pre-configuration + ************/ + + /* remote-gsyncd */ + runinit_gsyncd_setrx (&runner, conf_path); + runner_add_args (&runner, "remote-gsyncd", GSYNCD_PREFIX"/gsyncd", ".", ".", NULL); + RUN_GSYNCD_CMD; + + runinit_gsyncd_setrx (&runner, conf_path); + runner_add_args (&runner, "remote-gsyncd", "/nonexistent/gsyncd", + ".", "^ssh:", NULL); + RUN_GSYNCD_CMD; + + /* gluster-command-dir */ + runinit_gsyncd_setrx (&runner, conf_path); + runner_add_args (&runner, "gluster-command-dir", SBIN_DIR"/", + ".", ".", NULL); + RUN_GSYNCD_CMD; + + /* gluster-params */ + runinit_gsyncd_setrx (&runner, conf_path); + runner_add_args (&runner, "gluster-params", + "aux-gfid-mount xlator-option=*-dht.assert-no-child-down=true", + ".", ".", NULL); + RUN_GSYNCD_CMD; + + /* ssh-command */ + runinit_gsyncd_setrx (&runner, conf_path); + runner_add_arg (&runner, "ssh-command"); + runner_argprintf (&runner, + "ssh -oPasswordAuthentication=no " + "-oStrictHostKeyChecking=no " + "-i %s/secret.pem", georepdir); + runner_add_args (&runner, ".", ".", NULL); + RUN_GSYNCD_CMD; + + /* pid-file */ + runinit_gsyncd_setrx (&runner, conf_path); + runner_add_arg (&runner, "pid-file"); + runner_argprintf (&runner, "%s/${mastervol}-${slavevol}/${eSlave}.pid", georepdir); + runner_add_args (&runner, ".", ".", NULL); + RUN_GSYNCD_CMD; + + /* state-file */ + runinit_gsyncd_setrx (&runner, conf_path); + runner_add_arg (&runner, "state-file"); + runner_argprintf (&runner, "%s/${mastervol}-${slavevol}/${eSlave}.status", georepdir); + runner_add_args (&runner, ".", ".", NULL); + RUN_GSYNCD_CMD; + + /* state-detail-file */ + runinit_gsyncd_setrx (&runner, conf_path); + runner_add_arg (&runner, "state-detail-file"); + runner_argprintf (&runner, "%s/${mastervol}-${slavevol}/${eSlave}-detail.status", georepdir); + runner_add_args (&runner, ".", ".", NULL); + RUN_GSYNCD_CMD; + + /* state-socket */ + runinit_gsyncd_setrx (&runner, conf_path); + runner_add_arg (&runner, "state-socket-unencoded"); + runner_argprintf (&runner, "%s/${mastervol}-${slavevol}/${eSlave}.socket", georepdir); + runner_add_args (&runner, ".", ".", NULL); + RUN_GSYNCD_CMD; + + /* socketdir */ + runinit_gsyncd_setrx (&runner, conf_path); + runner_add_args (&runner, "socketdir", GLUSTERD_SOCK_DIR, ".", ".", NULL); + RUN_GSYNCD_CMD; + + /* log-file */ + runinit_gsyncd_setrx (&runner, conf_path); + runner_add_args (&runner, + "log-file", + DEFAULT_LOG_FILE_DIRECTORY"/"GEOREP"/${mastervol}/${eSlave}.log", + ".", ".", NULL); + RUN_GSYNCD_CMD; + + /* gluster-log-file */ + runinit_gsyncd_setrx (&runner, conf_path); + runner_add_args (&runner, + "gluster-log-file", + DEFAULT_LOG_FILE_DIRECTORY"/"GEOREP"/${mastervol}/${eSlave}${local_id}.gluster.log", + ".", ".", NULL); + RUN_GSYNCD_CMD; + + /* ignore-deletes */ + runinit_gsyncd_setrx (&runner, conf_path); + runner_add_args (&runner, "ignore-deletes", "true", ".", ".", NULL); + RUN_GSYNCD_CMD; + + /* special-sync-mode */ + runinit_gsyncd_setrx (&runner, conf_path); + runner_add_args (&runner, "special-sync-mode", "partial", ".", ".", NULL); + RUN_GSYNCD_CMD; + + /* change-detector == changelog */ + runinit_gsyncd_setrx (&runner, conf_path); + runner_add_args(&runner, "change-detector", "changelog", ".", ".", NULL); + RUN_GSYNCD_CMD; + + runinit_gsyncd_setrx (&runner, conf_path); + runner_add_arg(&runner, "working-dir"); + runner_argprintf(&runner, "%s/${mastervol}/${eSlave}", + DEFAULT_VAR_RUN_DIRECTORY); + runner_add_args (&runner, ".", ".", NULL); + RUN_GSYNCD_CMD; + + /************ + * slave pre-configuration + ************/ + + /* gluster-command-dir */ + runinit_gsyncd_setrx (&runner, conf_path); + runner_add_args (&runner, "gluster-command-dir", SBIN_DIR"/", + ".", NULL); + RUN_GSYNCD_CMD; + + /* gluster-params */ + runinit_gsyncd_setrx (&runner, conf_path); + runner_add_args (&runner, "gluster-params", + "aux-gfid-mount xlator-option=*-dht.assert-no-child-down=true", + ".", NULL); + RUN_GSYNCD_CMD; + + /* log-file */ + runinit_gsyncd_setrx (&runner, conf_path); + runner_add_args (&runner, + "log-file", + DEFAULT_LOG_FILE_DIRECTORY"/"GEOREP"-slaves/${session_owner}:${eSlave}.log", + ".", NULL); + RUN_GSYNCD_CMD; + + /* MountBroker log-file */ + runinit_gsyncd_setrx (&runner, conf_path); + runner_add_args (&runner, + "log-file-mbr", + DEFAULT_LOG_FILE_DIRECTORY"/"GEOREP"-slaves/mbr/${session_owner}:${eSlave}.log", + ".", NULL); + RUN_GSYNCD_CMD; + + /* gluster-log-file */ + runinit_gsyncd_setrx (&runner, conf_path); + runner_add_args (&runner, + "gluster-log-file", + DEFAULT_LOG_FILE_DIRECTORY"/"GEOREP"-slaves/${session_owner}:${eSlave}.gluster.log", + ".", NULL); + RUN_GSYNCD_CMD; - param.volinfo = volinfo; - dict_foreach (volinfo->gsync_slaves, _iterate_log_rotate_mst_slv, ¶m); - return 0; + out: + return ret ? -1 : 0; } static int -glusterd_rotate_gsync_all () +glusterd_create_essential_dir_files (glusterd_volinfo_t *volinfo, dict_t *dict, char *slave, char *slave_vol, char **op_errstr) { - int32_t ret = 0; - glusterd_conf_t *priv = NULL; - glusterd_volinfo_t *volinfo = NULL; + int ret = -1; + char *conf_path = NULL; + char *statefile = NULL; + char buf[PATH_MAX] = ""; + char errmsg[PATH_MAX] = ""; + glusterd_conf_t *conf = NULL; + struct stat stbuf = {0,}; GF_ASSERT (THIS); - priv = THIS->private; - - GF_ASSERT (priv); + conf = THIS->private; - list_for_each_entry (volinfo, &priv->volumes, vol_list) { - ret = glusterd_do_gsync_log_rotation_mst (volinfo); - if (ret) - goto out; + ret = dict_get_str (dict, "conf_path", &conf_path); + if (ret) { + snprintf (errmsg, sizeof (errmsg), + "Unable to fetch conf file path."); + gf_log ("", GF_LOG_ERROR, "%s", errmsg); + goto out; } - out: - gf_log ("", GF_LOG_DEBUG, "Returning with %d", ret); - return ret; -} - -static int -glusterd_rotate_gsync_logs (dict_t *dict, char **op_errstr, dict_t *rsp_dict) -{ - char *slave = NULL; - char *volname = NULL; - char errmsg[1024] = {0,}; - gf_boolean_t exists = _gf_false; - glusterd_volinfo_t *volinfo = NULL; - char **linearr = NULL; - int ret = 0; - - ret = dict_get_str (dict, "master", &volname); - if (ret < 0) { - ret = glusterd_rotate_gsync_all (); + ret = dict_get_str (dict, "statefile", &statefile); + if (ret) { + snprintf (errmsg, sizeof (errmsg), + "Unable to fetch statefile path."); + gf_log ("", GF_LOG_ERROR, "%s", errmsg); goto out; } - exists = glusterd_check_volume_exists (volname); - ret = glusterd_volinfo_find (volname, &volinfo); - if ((ret) || (!exists)) { - snprintf (errmsg, sizeof(errmsg), "Volume %s does not" - " exist", volname); - gf_log ("", GF_LOG_WARNING, "%s", errmsg); + ret = snprintf (buf, sizeof(buf) - 1, "%s/"GEOREP"/%s-%s", + conf->workdir, volinfo->volname, slave_vol); + buf[ret] = '\0'; + ret = mkdir_p (buf, 0777, _gf_true); + if (ret) { + snprintf (errmsg, sizeof (errmsg), "Unable to create %s" + ". Error : %s", buf, strerror (errno)); *op_errstr = gf_strdup (errmsg); - ret = -1; + gf_log ("", GF_LOG_ERROR, "%s", errmsg); goto out; } - ret = dict_get_str (dict, "slave", &slave); - if (ret < 0) { - ret = glusterd_do_gsync_log_rotation_mst (volinfo); + ret = snprintf (buf, PATH_MAX, DEFAULT_LOG_FILE_DIRECTORY"/"GEOREP"/%s", + volinfo->volname); + buf[ret] = '\0'; + ret = mkdir_p (buf, 0777, _gf_true); + if (ret) { + snprintf (errmsg, sizeof (errmsg), "Unable to create %s" + ". Error : %s", buf, strerror (errno)); + *op_errstr = gf_strdup (errmsg); + gf_log ("", GF_LOG_ERROR, "%s", errmsg); goto out; } - /* for the given slave use the normalized url */ - ret = glusterd_urltransform_single (slave, "normalize", &linearr); - if (ret == -1) - goto out; + ret = lstat (conf_path, &stbuf); + if (!ret) { + gf_log ("", GF_LOG_DEBUG, "Session already running." + " Not creating config file again."); + } else { + ret = create_conf_file (conf, conf_path); + if (ret || lstat (conf_path, &stbuf)) { + snprintf (errmsg, sizeof (errmsg), "Failed to create" + " config file(%s).", conf_path); + gf_log ("", GF_LOG_ERROR, "%s", errmsg); + goto out; + } + } - ret = glusterd_do_gsync_log_rotation_mst_slv (volinfo, linearr[0], - op_errstr); - if (ret) - gf_log ("gsyncd", GF_LOG_ERROR, "gsyncd log-rotate failed for" - " %s & %s", volname, slave); + ret = lstat (statefile, &stbuf); + if (!ret) { + gf_log ("", GF_LOG_DEBUG, "Session already running." + " Not creating status file again."); + goto out; + } else { + ret = glusterd_create_status_file (volinfo->volname, slave, slave_vol, + "Not Started"); + if (ret || lstat (statefile, &stbuf)) { + snprintf (errmsg, sizeof (errmsg), "Unable to create %s" + ". Error : %s", statefile, strerror (errno)); + *op_errstr = gf_strdup (errmsg); + gf_log ("", GF_LOG_ERROR, "%s", errmsg); + ret = -1; + goto out; + } + } - glusterd_urltransform_free (linearr, 1); - out: +out: + gf_log ("", GF_LOG_DEBUG,"Returning %d", ret); return ret; } - int -glusterd_op_gsync_set (dict_t *dict, char **op_errstr, dict_t *rsp_dict) +glusterd_op_gsync_create (dict_t *dict, char **op_errstr, dict_t *rsp_dict) { - int32_t ret = -1; - int32_t type = -1; - dict_t *ctx = NULL; - dict_t *resp_dict = NULL; - char *host_uuid = NULL; - char *slave = NULL; - char *volname = NULL; - glusterd_volinfo_t *volinfo = NULL; - glusterd_conf_t *priv = NULL; - char *status_msg = NULL; - uuid_t uuid = {0, }; + char common_pem_file[PATH_MAX] = ""; + char errmsg[PATH_MAX] = ""; + char hooks_args[PATH_MAX] = ""; + char uuid_str [64] = ""; + char *host_uuid = NULL; + char *slave_ip = NULL; + char *slave_vol = NULL; + char *arg_buf = NULL; + char *volname = NULL; + char *slave = NULL; + int32_t ret = -1; + int32_t is_pem_push = -1; + gf_boolean_t is_force = -1; + glusterd_conf_t *conf = NULL; + glusterd_volinfo_t *volinfo = NULL; GF_ASSERT (THIS); - GF_ASSERT (THIS->private); + conf = THIS->private; + GF_ASSERT (conf); GF_ASSERT (dict); GF_ASSERT (op_errstr); - priv = THIS->private; - - ret = dict_get_int32 (dict, "type", &type); - if (ret < 0) - goto out; - - ret = dict_get_str (dict, "host-uuid", &host_uuid); - if (ret < 0) + ret = glusterd_op_gsync_args_get (dict, op_errstr, + &volname, &slave, &host_uuid); + if (ret) goto out; - ctx = glusterd_op_get_ctx (); - resp_dict = ctx ? ctx : rsp_dict; - GF_ASSERT (resp_dict); + snprintf (common_pem_file, sizeof(common_pem_file), + "%s"GLUSTERD_COMMON_PEM_PUB_FILE, conf->workdir); - if (type == GF_GSYNC_OPTION_TYPE_STATUS) { - ret = glusterd_get_gsync_status (dict, op_errstr, resp_dict); + ret = glusterd_volinfo_find (volname, &volinfo); + if (ret) { + gf_log ("", GF_LOG_ERROR, "Volinfo for %s" + " (master) not found", volname); goto out; } - if (type == GF_GSYNC_OPTION_TYPE_ROTATE) { - ret = glusterd_rotate_gsync_logs (dict, op_errstr, resp_dict); + ret = dict_get_str (dict, "slave_vol", &slave_vol); + if (ret) { + snprintf (errmsg, sizeof (errmsg), + "Unable to fetch slave volume name."); + gf_log ("", GF_LOG_ERROR, "%s", errmsg); goto out; - } - ret = dict_get_str (dict, "slave", &slave); - if (ret < 0) - goto out; + is_force = dict_get_str_boolean (dict, "force", _gf_false); - if (dict_get_str (dict, "master", &volname) == 0) { - ret = glusterd_volinfo_find (volname, &volinfo); + uuid_utoa_r (MY_UUID, uuid_str); + if (!strcmp (uuid_str, host_uuid)) { + ret = dict_get_str (dict, "slave_ip", &slave_ip); if (ret) { - gf_log ("", GF_LOG_WARNING, "Volinfo for %s (master) not found", - volname); + snprintf (errmsg, sizeof (errmsg), + "Unable to fetch slave IP." + " No Hooks Arguments."); + gf_log ("", GF_LOG_ERROR, "%s", errmsg); + if (is_force) { + ret = 0; + goto create_essentials; + } + ret = -1; goto out; } - } - - if (type == GF_GSYNC_OPTION_TYPE_CONFIG) { - ret = glusterd_gsync_configure (volinfo, slave, dict, resp_dict, - op_errstr); - goto out; - } - if (!volinfo) { + ret = dict_get_int32 (dict, "push_pem", &is_pem_push); + if (!ret && is_pem_push) { + gf_log ("", GF_LOG_DEBUG, "Trying to setup" + " pem files in slave"); + is_pem_push = 1; + } else + is_pem_push = 0; + + snprintf(hooks_args, sizeof(hooks_args), + "is_push_pem=%d pub_file=%s slave_ip=%s", + is_pem_push, common_pem_file, slave_ip); + + } else + snprintf(hooks_args, sizeof(hooks_args), + "This argument will stop the hooks script"); + + arg_buf = gf_strdup (hooks_args); + if (!arg_buf) { + gf_log ("", GF_LOG_ERROR, "Failed to" + " gf_strdup"); + if (is_force) { + ret = 0; + goto create_essentials; + } ret = -1; goto out; } - if (type == GF_GSYNC_OPTION_TYPE_START) { - - ret = glusterd_set_marker_gsync (volinfo); - if (ret != 0) { - gf_log ("", GF_LOG_WARNING, "marker start failed"); - *op_errstr = gf_strdup ("failed to initialize indexing"); - ret = -1; - goto out; + ret = dict_set_str (dict, "hooks_args", arg_buf); + if (ret) { + gf_log ("", GF_LOG_ERROR, "Failed to set" + " hooks_args in dict."); + if (is_force) { + ret = 0; + goto create_essentials; } - ret = glusterd_store_slave_in_info(volinfo, slave, - host_uuid, op_errstr); - if (ret) - goto out; - - ret = glusterd_start_gsync (volinfo, slave, host_uuid, - op_errstr); + goto out; } - if (type == GF_GSYNC_OPTION_TYPE_STOP) { - - ret = glusterd_gsync_get_uuid (slave, volinfo, uuid); - if (ret) { - gf_log ("", GF_LOG_WARNING, GEOREP" is not set up for" - "%s(master) and %s(slave)", volname, slave); - *op_errstr = strdup (GEOREP" is not set up"); - goto out; - } - - ret = glusterd_remove_slave_in_info(volinfo, slave, op_errstr); - if (ret) - goto out; +create_essentials: - if (uuid_compare (MY_UUID, uuid) != 0) { - goto out; - } + ret = glusterd_create_essential_dir_files (volinfo, dict, slave, slave_vol, op_errstr); + if (ret) + goto out; - ret = stop_gsync (volname, slave, &status_msg); - if (ret == 0 && status_msg) - ret = dict_set_str (resp_dict, "gsync-status", - status_msg); - if (ret != 0) - *op_errstr = gf_strdup ("internal error"); + ret = glusterd_store_slave_in_info (volinfo, slave, + host_uuid, op_errstr, + is_force); + if (ret) { + snprintf (errmsg, sizeof (errmsg), "Unable to store" + " slave info."); + gf_log ("", GF_LOG_ERROR, "%s", errmsg); + goto out; } out: diff --git a/xlators/mgmt/glusterd/src/glusterd-handler.c b/xlators/mgmt/glusterd/src/glusterd-handler.c index 480ee01b0..38427d822 100644 --- a/xlators/mgmt/glusterd/src/glusterd-handler.c +++ b/xlators/mgmt/glusterd/src/glusterd-handler.c @@ -3922,6 +3922,8 @@ rpcsvc_actor_t gd_svc_cli_actors[] = { #ifdef HAVE_BD_XLATOR [GLUSTER_CLI_BD_OP] = {"BD_OP", GLUSTER_CLI_BD_OP, glusterd_handle_cli_bd_op, NULL, 0, DRC_NA}, #endif + [GLUSTER_CLI_COPY_FILE] = {"COPY_FILE", GLUSTER_CLI_COPY_FILE, glusterd_handle_copy_file, NULL, 0, DRC_NA}, + [GLUSTER_CLI_SYS_EXEC] = {"SYS_EXEC", GLUSTER_CLI_SYS_EXEC, glusterd_handle_sys_exec, NULL, 0, DRC_NA}, }; struct rpcsvc_program gd_svc_cli_prog = { diff --git a/xlators/mgmt/glusterd/src/glusterd-hooks.c b/xlators/mgmt/glusterd/src/glusterd-hooks.c index a61e1e85f..2b43a452e 100644 --- a/xlators/mgmt/glusterd/src/glusterd-hooks.c +++ b/xlators/mgmt/glusterd/src/glusterd-hooks.c @@ -49,6 +49,7 @@ char glusterd_hook_dirnames[GD_OP_MAX][256] = [GD_OP_RESET_VOLUME] = EMPTY, [GD_OP_SYNC_VOLUME] = EMPTY, [GD_OP_LOG_ROTATE] = EMPTY, + [GD_OP_GSYNC_CREATE] = "gsync-create", [GD_OP_GSYNC_SET] = EMPTY, [GD_OP_PROFILE_VOLUME] = EMPTY, [GD_OP_QUOTA] = EMPTY, @@ -185,6 +186,7 @@ static int glusterd_hooks_add_op_args (runner_t *runner, glusterd_op_t op, dict_t *op_ctx, glusterd_commit_hook_type_t type) { + char *hooks_args = NULL; int vol_count = 0; gf_boolean_t truth = _gf_false; glusterd_volinfo_t *voliter = NULL; @@ -236,6 +238,18 @@ glusterd_hooks_add_op_args (runner_t *runner, glusterd_op_t op, ret = glusterd_hooks_set_volume_args (op_ctx, runner); break; + case GD_OP_GSYNC_CREATE: + ret = dict_get_str (op_ctx, "hooks_args", &hooks_args); + if (ret) + gf_log ("", GF_LOG_DEBUG, + "No Hooks Arguments."); + else + gf_log ("", GF_LOG_DEBUG, + "Hooks Args = %s", hooks_args); + if (hooks_args) + runner_argprintf (runner, "%s", hooks_args); + break; + default: break; diff --git a/xlators/mgmt/glusterd/src/glusterd-op-sm.c b/xlators/mgmt/glusterd/src/glusterd-op-sm.c index fb8d1f17e..1774b133b 100644 --- a/xlators/mgmt/glusterd/src/glusterd-op-sm.c +++ b/xlators/mgmt/glusterd/src/glusterd-op-sm.c @@ -2504,12 +2504,13 @@ glusterd_op_build_payload (dict_t **req, char **op_errstr, dict_t *op_ctx) } break; + case GD_OP_GSYNC_CREATE: case GD_OP_GSYNC_SET: { ret = glusterd_op_gsync_args_get (dict, &errstr, &volname, - NULL); + NULL, NULL); if (ret == 0) { ret = glusterd_dict_set_volid (dict, volname, op_errstr); @@ -2622,6 +2623,18 @@ glusterd_op_build_payload (dict_t **req, char **op_errstr, dict_t *op_ctx) } break; + case GD_OP_COPY_FILE: + { + dict_copy (dict, req_dict); + break; + } + + case GD_OP_SYS_EXEC: + { + dict_copy (dict, req_dict); + break; + } + default: break; } @@ -3755,6 +3768,10 @@ glusterd_op_stage_validate (glusterd_op_t op, dict_t *dict, char **op_errstr, ret = glusterd_op_stage_sync_volume (dict, op_errstr); break; + case GD_OP_GSYNC_CREATE: + ret = glusterd_op_stage_gsync_create (dict, op_errstr); + break; + case GD_OP_GSYNC_SET: ret = glusterd_op_stage_gsync_set (dict, op_errstr); break; @@ -3793,13 +3810,21 @@ glusterd_op_stage_validate (glusterd_op_t op, dict_t *dict, char **op_errstr, ret = glusterd_op_stage_bd (dict, op_errstr); break; #endif + + case GD_OP_COPY_FILE: + ret = glusterd_op_stage_copy_file (dict, op_errstr); + break; + + case GD_OP_SYS_EXEC: + ret = glusterd_op_stage_sys_exec (dict, op_errstr); + break; + default: gf_log (this->name, GF_LOG_ERROR, "Unknown op %s", gd_op_list[op]); } - gf_log (this->name, GF_LOG_DEBUG, "Returning %d", ret); - + gf_log (this->name, GF_LOG_DEBUG, "OP = %d. Returning %d", op, ret); return ret; } @@ -3857,6 +3882,11 @@ glusterd_op_commit_perform (glusterd_op_t op, dict_t *dict, char **op_errstr, ret = glusterd_op_sync_volume (dict, op_errstr, rsp_dict); break; + case GD_OP_GSYNC_CREATE: + ret = glusterd_op_gsync_create (dict, op_errstr, + rsp_dict); + break; + case GD_OP_GSYNC_SET: ret = glusterd_op_gsync_set (dict, op_errstr, rsp_dict); break; @@ -3896,6 +3926,15 @@ glusterd_op_commit_perform (glusterd_op_t op, dict_t *dict, char **op_errstr, ret = 0; break; #endif + + case GD_OP_COPY_FILE: + ret = glusterd_op_copy_file (dict, op_errstr); + break; + + case GD_OP_SYS_EXEC: + ret = glusterd_op_sys_exec (dict, op_errstr, rsp_dict); + break; + default: gf_log (this->name, GF_LOG_ERROR, "Unknown op %s", gd_op_list[op]); @@ -3904,8 +3943,8 @@ glusterd_op_commit_perform (glusterd_op_t op, dict_t *dict, char **op_errstr, if (ret == 0) glusterd_op_commit_hook (op, dict, GD_COMMIT_HOOK_POST); - gf_log (this->name, GF_LOG_DEBUG, "Returning %d", ret); + gf_log (this->name, GF_LOG_DEBUG, "Returning %d", ret); return ret; } diff --git a/xlators/mgmt/glusterd/src/glusterd-op-sm.h b/xlators/mgmt/glusterd/src/glusterd-op-sm.h index df8b8c141..321c5c484 100644 --- a/xlators/mgmt/glusterd/src/glusterd-op-sm.h +++ b/xlators/mgmt/glusterd/src/glusterd-op-sm.h @@ -15,8 +15,8 @@ #include "config.h" #endif -#ifndef GSYNC_CONF -#define GSYNC_CONF GEOREP"/gsyncd.conf" +#ifndef GSYNC_CONF_TEMPLATE +#define GSYNC_CONF_TEMPLATE GEOREP"/gsyncd_template.conf" #endif #include @@ -270,7 +270,7 @@ glusterd_are_all_volumes_stopped (); int glusterd_stop_bricks (glusterd_volinfo_t *volinfo); int -gsync_status (char *master, char *slave, int *status); +gsync_status (char *master, char *slave, char *conf_path, int *status); int glusterd_check_gsync_running (glusterd_volinfo_t *volinfo, gf_boolean_t *flag); diff --git a/xlators/mgmt/glusterd/src/glusterd-rpc-ops.c b/xlators/mgmt/glusterd/src/glusterd-rpc-ops.c index 18a743494..2d8d381bf 100644 --- a/xlators/mgmt/glusterd/src/glusterd-rpc-ops.c +++ b/xlators/mgmt/glusterd/src/glusterd-rpc-ops.c @@ -84,6 +84,7 @@ glusterd_op_send_cli_response (glusterd_op_t op, int32_t op_ret, } break; } + case GD_OP_GSYNC_CREATE: case GD_OP_GSYNC_SET: { if (ctx) { @@ -146,6 +147,21 @@ glusterd_op_send_cli_response (glusterd_op_t op, int32_t op_ret, /*nothing specific to be done*/ break; } + case GD_OP_COPY_FILE: + { + if (ctx) + ret = dict_get_str (ctx, "errstr", &errstr); + break; + } + case GD_OP_SYS_EXEC: + { + if (ctx) { + ret = dict_get_str (ctx, "errstr", &errstr); + ret = dict_set_str (ctx, "glusterd_workdir", + conf->workdir); + } + break; + } } rsp.op_ret = op_ret; diff --git a/xlators/mgmt/glusterd/src/glusterd-syncop.c b/xlators/mgmt/glusterd/src/glusterd-syncop.c index 7b0c28baf..a694cae84 100644 --- a/xlators/mgmt/glusterd/src/glusterd-syncop.c +++ b/xlators/mgmt/glusterd/src/glusterd-syncop.c @@ -32,14 +32,77 @@ gd_synctask_barrier_wait (struct syncargs *args, int count) static void gd_collate_errors (struct syncargs *args, int op_ret, int op_errno, - char *op_errstr) + char *op_errstr, int op_code, + glusterd_peerinfo_t *peerinfo, u_char *uuid) { - if (args->op_ret) - return; - args->op_ret = op_ret; - args->op_errno = op_errno; - if (op_ret && op_errstr && strcmp (op_errstr, "")) - args->errstr = gf_strdup (op_errstr); + char err_str[PATH_MAX] = "Please check log file for details."; + char op_err[PATH_MAX] = ""; + int len = -1; + char *peer_str = NULL; + + if (op_ret) { + args->op_ret = op_ret; + args->op_errno = op_errno; + + if (peerinfo) + peer_str = peerinfo->hostname; + else + peer_str = uuid_utoa (uuid); + + if (op_errstr && strcmp (op_errstr, "")) { + len = snprintf (err_str, sizeof(err_str) - 1, + "Error: %s", op_errstr); + err_str[len] = '\0'; + } + + switch (op_code){ + case GLUSTERD_MGMT_CLUSTER_LOCK : + { + len = snprintf (op_err, sizeof(op_err) - 1, + "Locking failed on %s. %s", + peer_str, err_str); + break; + } + case GLUSTERD_MGMT_CLUSTER_UNLOCK : + { + len = snprintf (op_err, sizeof(op_err) - 1, + "Unlocking failed on %s. %s", + peer_str, err_str); + break; + } + case GLUSTERD_MGMT_STAGE_OP : + { + len = snprintf (op_err, sizeof(op_err) - 1, + "Staging failed on %s. %s", + peer_str, err_str); + break; + } + case GLUSTERD_MGMT_COMMIT_OP : + { + len = snprintf (op_err, sizeof(op_err) - 1, + "Commit failed on %s. %s", + peer_str, err_str); + break; + } + } + op_err[len] = '\0'; + + if (args->errstr) { + len = snprintf (err_str, sizeof(err_str) - 1, + "%s\n%s", args->errstr, + op_err); + GF_FREE (args->errstr); + args->errstr = NULL; + } else + len = snprintf (err_str, sizeof(err_str) - 1, + "%s", op_err); + err_str[len] = '\0'; + + gf_log ("", GF_LOG_ERROR, "%s", op_err); + args->errstr = gf_strdup (err_str); + } + + return; } static void @@ -169,6 +232,9 @@ glusterd_syncop_aggr_rsp_dict (glusterd_op_t op, dict_t *aggr, dict_t *rsp) goto out; break; + case GD_OP_GSYNC_CREATE: + break; + case GD_OP_GSYNC_SET: ret = glusterd_gsync_use_rsp_dict (aggr, rsp, NULL); if (ret) @@ -203,6 +269,12 @@ glusterd_syncop_aggr_rsp_dict (glusterd_op_t op, dict_t *aggr, dict_t *rsp) break; + case GD_OP_SYS_EXEC: + ret = glusterd_sys_exec_output_rsp_dict (aggr, rsp); + if (ret) + goto out; + break; + default: break; } @@ -246,7 +318,8 @@ _gd_syncop_mgmt_lock_cbk (struct rpc_req *req, struct iovec *iov, op_ret = rsp.op_ret; op_errno = rsp.op_errno; out: - gd_collate_errors (args, op_ret, op_errno, NULL); + gd_collate_errors (args, op_ret, op_errno, NULL, + GLUSTERD_MGMT_CLUSTER_LOCK, peerinfo, rsp.uuid); STACK_DESTROY (frame->root); synctask_barrier_wake(args); return 0; @@ -312,7 +385,8 @@ _gd_syncop_mgmt_unlock_cbk (struct rpc_req *req, struct iovec *iov, op_ret = rsp.op_ret; op_errno = rsp.op_errno; out: - gd_collate_errors (args, op_ret, op_errno, NULL); + gd_collate_errors (args, op_ret, op_errno, NULL, + GLUSTERD_MGMT_CLUSTER_UNLOCK, peerinfo, rsp.uuid); STACK_DESTROY (frame->root); synctask_barrier_wake(args); return 0; @@ -356,6 +430,7 @@ _gd_syncop_stage_op_cbk (struct rpc_req *req, struct iovec *iov, xlator_t *this = NULL; dict_t *rsp_dict = NULL; call_frame_t *frame = NULL; + glusterd_peerinfo_t *peerinfo = NULL; int op_ret = -1; int op_errno = -1; @@ -389,6 +464,15 @@ _gd_syncop_stage_op_cbk (struct rpc_req *req, struct iovec *iov, } } + ret = glusterd_friend_find (rsp.uuid, NULL, &peerinfo); + if (ret) { + gf_log (this->name, GF_LOG_CRITICAL, "Staging response " + "for 'Volume %s' received from unknown " + "peer: %s", gd_op_list[rsp.op], + uuid_utoa (rsp.uuid)); + goto out; + } + uuid_copy (args->uuid, rsp.uuid); if (rsp.op == GD_OP_REPLACE_BRICK) { pthread_mutex_lock (&args->lock_dict); @@ -407,7 +491,9 @@ _gd_syncop_stage_op_cbk (struct rpc_req *req, struct iovec *iov, op_errno = rsp.op_errno; out: - gd_collate_errors (args, op_ret, op_errno, rsp.op_errstr); + gd_collate_errors (args, op_ret, op_errno, rsp.op_errstr, + GLUSTERD_MGMT_STAGE_OP, peerinfo, rsp.uuid); + if (rsp_dict) dict_unref (rsp_dict); @@ -588,14 +674,15 @@ int32_t _gd_syncop_commit_op_cbk (struct rpc_req *req, struct iovec *iov, int count, void *myframe) { - int ret = -1; - gd1_mgmt_commit_op_rsp rsp = {{0},}; - struct syncargs *args = NULL; - xlator_t *this = NULL; - dict_t *rsp_dict = NULL; - call_frame_t *frame = NULL; - int op_ret = -1; - int op_errno = -1; + int ret = -1; + gd1_mgmt_commit_op_rsp rsp = {{0},}; + struct syncargs *args = NULL; + xlator_t *this = NULL; + dict_t *rsp_dict = NULL; + call_frame_t *frame = NULL; + glusterd_peerinfo_t *peerinfo = NULL; + int op_ret = -1; + int op_errno = -1; this = THIS; frame = myframe; @@ -628,6 +715,15 @@ _gd_syncop_commit_op_cbk (struct rpc_req *req, struct iovec *iov, } } + ret = glusterd_friend_find (rsp.uuid, NULL, &peerinfo); + if (ret) { + gf_log (this->name, GF_LOG_CRITICAL, "Commit response " + "for 'Volume %s' received from unknown " + "peer: %s", gd_op_list[rsp.op], + uuid_utoa (rsp.uuid)); + goto out; + } + uuid_copy (args->uuid, rsp.uuid); pthread_mutex_lock (&args->lock_dict); { @@ -642,8 +738,10 @@ _gd_syncop_commit_op_cbk (struct rpc_req *req, struct iovec *iov, op_ret = rsp.op_ret; op_errno = rsp.op_errno; + out: - gd_collate_errors (args, op_ret, op_errno, rsp.op_errstr); + gd_collate_errors (args, op_ret, op_errno, rsp.op_errstr, + GLUSTERD_MGMT_COMMIT_OP, peerinfo, rsp.uuid); if (rsp_dict) dict_unref (rsp_dict); @@ -816,12 +914,16 @@ stage_done: peer_cnt++; } gd_synctask_barrier_wait((&args), peer_cnt); - ret = args.op_ret; - if (dict_get_str (op_ctx, "errstr", &errstr) == 0) + + if (args.errstr) + *op_errstr = gf_strdup (args.errstr); + else if (dict_get_str (op_ctx, "errstr", &errstr) == 0) *op_errstr = gf_strdup (errstr); - else if (args.errstr) - *op_errstr = gf_strdup (args.errstr); + ret = args.op_ret; + + gf_log (this->name, GF_LOG_DEBUG, "Sent stage op req for 'Volume %s' " + "to %d peers", gd_op_list[op], peer_cnt); out: if (rsp_dict) dict_unref (rsp_dict); @@ -881,6 +983,7 @@ commit_done: ret = 0; goto out; } + gd_syncargs_init (&args, op_ctx); synctask_barrier_init((&args)); peer_cnt = 0; @@ -892,17 +995,23 @@ commit_done: } gd_synctask_barrier_wait((&args), peer_cnt); ret = args.op_ret; - if (dict_get_str (op_ctx, "errstr", &errstr) == 0) + if (args.errstr) + *op_errstr = gf_strdup (args.errstr); + else if (dict_get_str (op_ctx, "errstr", &errstr) == 0) *op_errstr = gf_strdup (errstr); - else if (args.errstr) - *op_errstr = gf_strdup (args.errstr); + gf_log (this->name, GF_LOG_DEBUG, "Sent commit op req for 'Volume %s' " + "to %d peers", gd_op_list[op], peer_cnt); out: if (!ret) glusterd_op_modify_op_ctx (op, op_ctx); if (rsp_dict) dict_unref (rsp_dict); + + GF_FREE (args.errstr); + args.errstr = NULL; + return ret; } @@ -1108,8 +1217,10 @@ out: if (req_dict) dict_unref (req_dict); - if (op_errstr) + if (op_errstr) { GF_FREE (op_errstr); + op_errstr = NULL; + } return; } diff --git a/xlators/mgmt/glusterd/src/glusterd-utils.c b/xlators/mgmt/glusterd/src/glusterd-utils.c index be5941830..6a760087c 100644 --- a/xlators/mgmt/glusterd/src/glusterd-utils.c +++ b/xlators/mgmt/glusterd/src/glusterd-utils.c @@ -3969,10 +3969,13 @@ glusterd_restart_bricks (glusterd_conf_t *conf) int _local_gsyncd_start (dict_t *this, char *key, data_t *value, void *data) { + char *path_list = NULL; char *slave = NULL; int uuid_len = 0; + int ret = 0; char uuid_str[64] = {0}; glusterd_volinfo_t *volinfo = NULL; + char *conf_path = NULL; volinfo = data; GF_ASSERT (volinfo); @@ -3984,9 +3987,24 @@ _local_gsyncd_start (dict_t *this, char *key, data_t *value, void *data) uuid_len = (slave - value->data - 1); strncpy (uuid_str, (char*)value->data, uuid_len); - glusterd_start_gsync (volinfo, slave, uuid_str, NULL); - return 0; + ret = glusterd_get_local_brickpaths (volinfo, &path_list); + + ret = dict_get_str (this, "conf_path", &conf_path); + if (ret) { + gf_log ("", GF_LOG_ERROR, + "Unable to fetch conf file path."); + goto out; + } + + glusterd_start_gsync (volinfo, slave, path_list, conf_path, + uuid_str, NULL); + + GF_FREE (path_list); + path_list = NULL; + +out: + return ret; } int @@ -5424,13 +5442,93 @@ glusterd_delete_all_bricks (glusterd_volinfo_t* volinfo) return ret; } +int +glusterd_get_local_brickpaths (glusterd_volinfo_t *volinfo, char **pathlist) +{ + char **path_tokens = NULL; + char *tmp_path_list = NULL; + char path[PATH_MAX] = ""; + int32_t count = 0; + int32_t pathlen = 0; + int32_t total_len = 0; + int32_t ret = 0; + int i = 0; + glusterd_brickinfo_t *brickinfo = NULL; + + if ((!volinfo) || (!pathlist)) + goto out; + + path_tokens = GF_CALLOC (sizeof(char*), volinfo->brick_count, + gf_gld_mt_charptr); + if (!path_tokens) { + gf_log ("", GF_LOG_DEBUG, "Could not allocate memory."); + ret = -1; + goto out; + } + + list_for_each_entry (brickinfo, &volinfo->bricks, brick_list) { + if (uuid_compare (brickinfo->uuid, MY_UUID)) + continue; + + pathlen = snprintf (path, sizeof(path), + "--path=%s ", brickinfo->path); + if (pathlen < sizeof(path)) + path[pathlen] = '\0'; + else + path[sizeof(path)-1] = '\0'; + path_tokens[count] = gf_strdup (path); + if (!path_tokens[count]) { + gf_log ("", GF_LOG_DEBUG, + "Could not allocate memory."); + ret = -1; + goto out; + } + count++; + total_len += pathlen; + } + + tmp_path_list = GF_CALLOC (sizeof(char), total_len + 1, + gf_gld_mt_char); + if (!tmp_path_list) { + gf_log ("", GF_LOG_DEBUG, "Could not allocate memory."); + ret = -1; + goto out; + } + + for (i = 0; i < count; i++) + strcat (tmp_path_list, path_tokens[i]); + + if (count) + *pathlist = tmp_path_list; + + ret = count; +out: + for (i = 0; i < count; i++) { + GF_FREE (path_tokens[i]); + path_tokens[i] = NULL; + } + + GF_FREE (path_tokens); + path_tokens = NULL; + + if (ret == 0) { + gf_log ("", GF_LOG_DEBUG, "No Local Bricks Present."); + GF_FREE (tmp_path_list); + tmp_path_list = NULL; + } + + gf_log ("", GF_LOG_DEBUG, "Returning %d", ret); + return ret; +} + int glusterd_start_gsync (glusterd_volinfo_t *master_vol, char *slave, - char *glusterd_uuid_str, char **op_errstr) + char *path_list, char *conf_path, + char *glusterd_uuid_str, + char **op_errstr) { int32_t ret = 0; int32_t status = 0; - char buf[PATH_MAX] = {0,}; char uuid_str [64] = {0}; runner_t runner = {0,}; xlator_t *this = NULL; @@ -5443,32 +5541,23 @@ glusterd_start_gsync (glusterd_volinfo_t *master_vol, char *slave, GF_ASSERT (priv); uuid_utoa_r (MY_UUID, uuid_str); - if (strcmp (uuid_str, glusterd_uuid_str)) - goto out; - - ret = gsync_status (master_vol->volname, slave, &status); - if (status == 0) - goto out; - snprintf (buf, PATH_MAX, "%s/"GEOREP"/%s", priv->workdir, master_vol->volname); - ret = mkdir_p (buf, 0777, _gf_true); - if (ret) { - errcode = -1; + if (!path_list) { + ret = 0; + gf_log ("", GF_LOG_DEBUG, "No Bricks in this node." + " Not starting gsyncd."); goto out; } - snprintf (buf, PATH_MAX, DEFAULT_LOG_FILE_DIRECTORY"/"GEOREP"/%s", - master_vol->volname); - ret = mkdir_p (buf, 0777, _gf_true); - if (ret) { - errcode = -1; + ret = gsync_status (master_vol->volname, slave, conf_path, &status); + if (status == 0) goto out; - } uuid_utoa_r (master_vol->volume_id, uuid_str); runinit (&runner); - runner_add_args (&runner, GSYNCD_PREFIX"/gsyncd", "-c", NULL); - runner_argprintf (&runner, "%s/"GSYNC_CONF, priv->workdir); + runner_add_args (&runner, GSYNCD_PREFIX"/gsyncd", + path_list, "-c", NULL); + runner_argprintf (&runner, "%s", conf_path); runner_argprintf (&runner, ":%s", master_vol->volname); runner_add_args (&runner, slave, "--config-set", "session-owner", uuid_str, NULL); @@ -5481,9 +5570,12 @@ glusterd_start_gsync (glusterd_volinfo_t *master_vol, char *slave, } runinit (&runner); - runner_add_args (&runner, GSYNCD_PREFIX"/gsyncd", "--monitor", "-c", NULL); - runner_argprintf (&runner, "%s/"GSYNC_CONF, priv->workdir); + runner_add_args (&runner, GSYNCD_PREFIX"/gsyncd", + path_list, "--monitor", "-c", NULL); + runner_argprintf (&runner, "%s", conf_path); runner_argprintf (&runner, ":%s", master_vol->volname); + runner_argprintf (&runner, "--glusterd-uuid=%s", + uuid_utoa (priv->uuid)); runner_add_arg (&runner, slave); synclock_unlock (&priv->big_lock); ret = runner_run (&runner); @@ -5499,7 +5591,7 @@ glusterd_start_gsync (glusterd_volinfo_t *master_vol, char *slave, out: if ((ret != 0) && errcode == -1) { if (op_errstr) - *op_errstr = gf_strdup ("internal error, cannot start" + *op_errstr = gf_strdup ("internal error, cannot start " "the " GEOREP " session"); } @@ -6852,6 +6944,61 @@ out: return ret; } +int +glusterd_sys_exec_output_rsp_dict (dict_t *dst, dict_t *src) +{ + char output_name[PATH_MAX] = ""; + char *output = NULL; + int ret = 0; + int i = 0; + int len = 0; + int src_output_count = 0; + int dst_output_count = 0; + + if (!dst || !src) { + gf_log ("", GF_LOG_ERROR, "Source or Destination " + "dict is empty."); + goto out; + } + + ret = dict_get_int32 (dst, "output_count", &dst_output_count); + + ret = dict_get_int32 (src, "output_count", &src_output_count); + if (ret) { + gf_log ("", GF_LOG_DEBUG, "No output from source"); + ret = 0; + goto out; + } + + for (i = 1; i <= src_output_count; i++) { + len = snprintf (output_name, sizeof(output_name) - 1, + "output_%d", i); + output_name[len] = '\0'; + ret = dict_get_str (src, output_name, &output); + if (ret) { + gf_log ("", GF_LOG_ERROR, "Unable to fetch %s", + output_name); + goto out; + } + + len = snprintf (output_name, sizeof(output_name) - 1, + "output_%d", i+dst_output_count); + output_name[len] = '\0'; + ret = dict_set_dynstr (dst, output_name, gf_strdup (output)); + if (ret) { + gf_log ("", GF_LOG_ERROR, "Unable to set %s", + output_name); + goto out; + } + } + + ret = dict_set_int32 (dst, "output_count", + dst_output_count+src_output_count); +out: + gf_log ("", GF_LOG_DEBUG, "Returning %d", ret); + return ret; +} + int glusterd_use_rsp_dict (dict_t *aggr, dict_t *rsp_dict) { @@ -7404,3 +7551,39 @@ gd_is_remove_brick_committed (glusterd_volinfo_t *volinfo) return _gf_true; } + +gf_boolean_t +glusterd_are_vol_all_peers_up (glusterd_volinfo_t *volinfo, + struct list_head *peers, + char **down_peerstr) +{ + glusterd_peerinfo_t *peerinfo = NULL; + glusterd_brickinfo_t *brickinfo = NULL; + gf_boolean_t ret = _gf_false; + + list_for_each_entry (brickinfo, &volinfo->bricks, brick_list) { + if (!uuid_compare (brickinfo->uuid, MY_UUID)) + continue; + + list_for_each_entry (peerinfo, peers, uuid_list) { + if (uuid_compare (peerinfo->uuid, brickinfo->uuid)) + continue; + + /*Found peer who owns the brick, return false + * if peer is not connected or not friend */ + if (!(peerinfo->connected) || + (peerinfo->state.state != + GD_FRIEND_STATE_BEFRIENDED)) { + *down_peerstr = gf_strdup (peerinfo->hostname); + gf_log ("", GF_LOG_DEBUG, "Peer %s is down. ", + peerinfo->hostname); + goto out; + } + } + } + + ret = _gf_true; +out: + gf_log ("", GF_LOG_DEBUG, "Returning %d", ret); + return ret; +} diff --git a/xlators/mgmt/glusterd/src/glusterd-utils.h b/xlators/mgmt/glusterd/src/glusterd-utils.h index 912b394b4..818b3f4fa 100644 --- a/xlators/mgmt/glusterd/src/glusterd-utils.h +++ b/xlators/mgmt/glusterd/src/glusterd-utils.h @@ -367,7 +367,13 @@ int glusterd_restart_gsyncds (glusterd_conf_t *conf); int glusterd_start_gsync (glusterd_volinfo_t *master_vol, char *slave, - char *glusterd_uuid_str, char **op_errstr); + char *path_list, char *conf_path, + char *glusterd_uuid_str, + char **op_errstr); +int +glusterd_get_local_brickpaths (glusterd_volinfo_t *volinfo, + char **pathlist); + int32_t glusterd_recreate_bricks (glusterd_conf_t *conf); int32_t @@ -471,6 +477,8 @@ int glusterd_volume_heal_use_rsp_dict (dict_t *aggr, dict_t *rsp_dict); int glusterd_use_rsp_dict (dict_t *aggr, dict_t *rsp_dict); +int +glusterd_sys_exec_output_rsp_dict (dict_t *aggr, dict_t *rsp_dict); int32_t glusterd_handle_node_rsp (dict_t *req_ctx, void *pending_entry, glusterd_op_t op, dict_t *rsp_dict, dict_t *op_ctx, @@ -487,6 +495,11 @@ glusterd_profile_volume_brick_rsp (void *pending_entry, dict_t *rsp_dict, dict_t *op_ctx, char **op_errstr, gd_node_type type); +gf_boolean_t +glusterd_are_vol_all_peers_up (glusterd_volinfo_t *volinfo, + struct list_head *peers, + char **down_peerstr); + /* Should be used only when an operation is in progress, as that is the only * time a lock_owner is set */ @@ -531,4 +544,9 @@ gd_peer_uuid_str (glusterd_peerinfo_t *peerinfo); gf_boolean_t gd_is_remove_brick_committed (glusterd_volinfo_t *volinfo); + +gf_boolean_t +glusterd_are_vol_all_peers_up (glusterd_volinfo_t *volinfo, + struct list_head *peers, + char **down_peerstr); #endif diff --git a/xlators/mgmt/glusterd/src/glusterd-volgen.h b/xlators/mgmt/glusterd/src/glusterd-volgen.h index 6a41f47c1..4ff899f4a 100644 --- a/xlators/mgmt/glusterd/src/glusterd-volgen.h +++ b/xlators/mgmt/glusterd/src/glusterd-volgen.h @@ -23,6 +23,7 @@ #define VKEY_DIAG_LAT_MEASUREMENT "diagnostics.latency-measurement" #define VKEY_FEATURES_LIMIT_USAGE "features.limit-usage" #define VKEY_MARKER_XTIME GEOREP".indexing" +#define VKEY_CHANGELOG "changelog.changelog" #define VKEY_FEATURES_QUOTA "features.quota" #define AUTH_ALLOW_MAP_KEY "auth.allow" diff --git a/xlators/mgmt/glusterd/src/glusterd.c b/xlators/mgmt/glusterd/src/glusterd.c index 53ca33ef9..a43c8d542 100644 --- a/xlators/mgmt/glusterd/src/glusterd.c +++ b/xlators/mgmt/glusterd/src/glusterd.c @@ -94,6 +94,9 @@ const char *gd_op_list[GD_OP_MAX + 1] = { [GD_OP_LIST_VOLUME] = "Lists", [GD_OP_CLEARLOCKS_VOLUME] = "Clear locks", [GD_OP_DEFRAG_BRICK_VOLUME] = "Rebalance", + [GD_OP_COPY_FILE] = "Copy File", + [GD_OP_SYS_EXEC] = "Execute system commands", + [GD_OP_GSYNC_CREATE] = "Geo-replication Create", [GD_OP_MAX] = "Invalid op" }; @@ -519,7 +522,7 @@ runinit_gsyncd_setrx (runner_t *runner, glusterd_conf_t *conf) { runinit (runner); runner_add_args (runner, GSYNCD_PREFIX"/gsyncd", "-c", NULL); - runner_argprintf (runner, "%s/"GSYNC_CONF,conf->workdir); + runner_argprintf (runner, "%s/"GSYNC_CONF_TEMPLATE, conf->workdir); runner_add_arg (runner, "--config-set-rx"); } @@ -581,7 +584,7 @@ configure_syncdaemon (glusterd_conf_t *conf) /* gluster-params */ runinit_gsyncd_setrx (&runner, conf); runner_add_args (&runner, "gluster-params", - "xlator-option=*-dht.assert-no-child-down=true", + "aux-gfid-mount xlator-option=*-dht.assert-no-child-down=true", ".", ".", NULL); RUN_GSYNCD_CMD; @@ -598,14 +601,30 @@ configure_syncdaemon (glusterd_conf_t *conf) /* pid-file */ runinit_gsyncd_setrx (&runner, conf); runner_add_arg (&runner, "pid-file"); - runner_argprintf (&runner, "%s/${mastervol}/${eSlave}.pid", georepdir); + runner_argprintf (&runner, "%s/${mastervol}-${slavevol}/${eSlave}.pid", georepdir); runner_add_args (&runner, ".", ".", NULL); RUN_GSYNCD_CMD; /* state-file */ runinit_gsyncd_setrx (&runner, conf); runner_add_arg (&runner, "state-file"); - runner_argprintf (&runner, "%s/${mastervol}/${eSlave}.status", georepdir); + runner_argprintf (&runner, "%s/${mastervol}-${slavevol}/${eSlave}.status", georepdir); + runner_add_args (&runner, ".", ".", NULL); + RUN_GSYNCD_CMD; + + /* state-detail-file */ + runinit_gsyncd_setrx (&runner, conf); + runner_add_arg (&runner, "state-detail-file"); + runner_argprintf (&runner, "%s/${mastervol}-${slavevol}/${eSlave}-detail.status", + georepdir); + runner_add_args (&runner, ".", ".", NULL); + RUN_GSYNCD_CMD; + + /* state-detail-file */ + runinit_gsyncd_setrx (&runner, conf); + runner_add_arg (&runner, "state-detail-file"); + runner_argprintf (&runner, "%s/${mastervol}-${slavevol}/${eSlave}-detail.status", + georepdir); runner_add_args (&runner, ".", ".", NULL); RUN_GSYNCD_CMD; @@ -647,6 +666,18 @@ configure_syncdaemon (glusterd_conf_t *conf) runner_add_args (&runner, "special-sync-mode", "partial", ".", ".", NULL); RUN_GSYNCD_CMD; + /* change-detector == changelog */ + runinit_gsyncd_setrx (&runner, conf); + runner_add_args(&runner, "change-detector", "changelog", ".", ".", NULL); + RUN_GSYNCD_CMD; + + runinit_gsyncd_setrx (&runner, conf); + runner_add_arg(&runner, "working-dir"); + runner_argprintf(&runner, "%s/${mastervol}/${eSlave}", + DEFAULT_VAR_RUN_DIRECTORY); + runner_add_args (&runner, ".", ".", NULL); + RUN_GSYNCD_CMD; + /************ * slave pre-configuration ************/ @@ -660,7 +691,7 @@ configure_syncdaemon (glusterd_conf_t *conf) /* gluster-params */ runinit_gsyncd_setrx (&runner, conf); runner_add_args (&runner, "gluster-params", - "xlator-option=*-dht.assert-no-child-down=true", + "aux-gfid-mount xlator-option=*-dht.assert-no-child-down=true", ".", NULL); RUN_GSYNCD_CMD; @@ -967,6 +998,7 @@ init (xlator_t *this) first_time = 1; } + setenv ("GLUSTERD_WORKING_DIR", workdir, 1); gf_log (this->name, GF_LOG_INFO, "Using %s as working directory", workdir); diff --git a/xlators/mgmt/glusterd/src/glusterd.h b/xlators/mgmt/glusterd/src/glusterd.h index 6bd9431e8..ccdf1c435 100644 --- a/xlators/mgmt/glusterd/src/glusterd.h +++ b/xlators/mgmt/glusterd/src/glusterd.h @@ -47,6 +47,7 @@ #define GLUSTERD_QUORUM_TYPE_KEY "cluster.server-quorum-type" #define GLUSTERD_QUORUM_RATIO_KEY "cluster.server-quorum-ratio" #define GLUSTERD_GLOBAL_OPT_VERSION "global-option-version" +#define GLUSTERD_COMMON_PEM_PUB_FILE "/geo-replication/common_secret.pem.pub" #define GLUSTERD_SERVER_QUORUM "server" @@ -95,6 +96,9 @@ typedef enum glusterd_op_ { GD_OP_CLEARLOCKS_VOLUME, GD_OP_DEFRAG_BRICK_VOLUME, GD_OP_BD_OP, + GD_OP_COPY_FILE, + GD_OP_SYS_EXEC, + GD_OP_GSYNC_CREATE, GD_OP_MAX, } glusterd_op_t; @@ -601,6 +605,12 @@ glusterd_handle_set_volume (rpcsvc_request_t *req); int glusterd_handle_reset_volume (rpcsvc_request_t *req); +int +glusterd_handle_copy_file (rpcsvc_request_t *req); + +int +glusterd_handle_sys_exec (rpcsvc_request_t *req); + int glusterd_handle_gsync_set (rpcsvc_request_t *req); @@ -685,6 +695,12 @@ int glusterd_op_stage_heal_volume (dict_t *dict, char **op_errstr); int glusterd_op_heal_volume (dict_t *dict, char **op_errstr); int glusterd_op_stage_gsync_set (dict_t *dict, char **op_errstr); int glusterd_op_gsync_set (dict_t *dict, char **op_errstr, dict_t *rsp_dict); +int glusterd_op_stage_copy_file (dict_t *dict, char **op_errstr); +int glusterd_op_copy_file (dict_t *dict, char **op_errstr); +int glusterd_op_stage_sys_exec (dict_t *dict, char **op_errstr); +int glusterd_op_sys_exec (dict_t *dict, char **op_errstr, dict_t *rsp_dict); +int glusterd_op_stage_gsync_create (dict_t *dict, char **op_errstr); +int glusterd_op_gsync_create (dict_t *dict, char **op_errstr, dict_t *rsp_dict); int glusterd_op_quota (dict_t *dict, char **op_errstr, dict_t *rsp_dict); int glusterd_op_stage_quota (dict_t *dict, char **op_errstr); int glusterd_op_stage_replace_brick (dict_t *dict, char **op_errstr, @@ -726,7 +742,7 @@ int glusterd_op_statedump_volume_args_get (dict_t *dict, char **volname, char **options, int *option_cnt); int glusterd_op_gsync_args_get (dict_t *dict, char **op_errstr, - char **master, char **slave); + char **master, char **slave, char **host_uuid); /* Synctask part */ int32_t glusterd_op_begin_synctask (rpcsvc_request_t *req, glusterd_op_t op, void *dict); -- cgit