From fbfcb0ad2aac73c2b5ab8950770c1184352bbf24 Mon Sep 17 00:00:00 2001 From: Raghavendra Bhat Date: Thu, 23 Aug 2012 15:32:33 +0530 Subject: glusterd, cli: implement gluster system uuid reset command A commonly faced problem among glusterfs users is: after a fresh installation of glusterfs in a virtual machine, the VM image is cloned to make multiple instances of the server. This breaks glusterd because right after glusterfs installation on the first boot glusterd would have created the node UUID and this gets inherited into the clone. The result is wierd behavior at the time of peer probe where glusterd does not (yet) deal with UUID collisions in a user friendly way. To handle it gluster peer reset command is implemented which upon execution changes the uuid of local glusterd. Change-Id: If207dd2ad93ab94ef1a3253f409c21c442975f87 BUG: 811493 Signed-off-by: Raghavendra Bhat Reviewed-on: http://review.gluster.org/3637 Reviewed-by: Pranith Kumar Karampuri Tested-by: Gluster Build System Reviewed-by: Anand Avati --- cli/src/cli-cmd-system.c | 65 +++++++++++++++++ cli/src/cli-cmd-volume.c | 13 ---- cli/src/cli-cmd.h | 13 ++++ cli/src/cli-rpc-ops.c | 77 +++++++++++++++++++++ rpc/rpc-lib/src/protocol-common.h | 1 + tests/bugs/bug-811493.t | 18 +++++ xlators/mgmt/glusterd/src/glusterd-handler.c | 100 +++++++++++++++++++++++++++ xlators/mgmt/glusterd/src/glusterd.c | 40 ++++++++--- xlators/mgmt/glusterd/src/glusterd.h | 2 + 9 files changed, 305 insertions(+), 24 deletions(-) create mode 100755 tests/bugs/bug-811493.t diff --git a/cli/src/cli-cmd-system.c b/cli/src/cli-cmd-system.c index 255eb605e64..b969c227b31 100644 --- a/cli/src/cli-cmd-system.c +++ b/cli/src/cli-cmd-system.c @@ -278,6 +278,67 @@ cli_cmd_umount_cbk (struct cli_state *state, struct cli_cmd_word *word, return ret; } +int +cli_cmd_uuid_reset_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; + int sent = 0; + int parse_error = 0; + gf_answer_t answer = GF_ANSWER_NO; + char *question = NULL; + cli_local_t *local = NULL; + dict_t *dict = NULL; + xlator_t *this = NULL; + + question = "Resetting uuid changes the uuid of local glusterd. " + "Do you want to continue?"; + + if (wordcount != 3) { + cli_usage_out (word->pattern); + parse_error = 1; + goto out; + } + + proc = &cli_rpc_prog->proctable[GLUSTER_CLI_UUID_RESET]; + + this = THIS; + frame = create_frame (this, this->ctx->pool); + if (!frame) + goto out; + + dict = dict_new (); + if (!dict) { + ret = -1; + goto out; + } + CLI_LOCAL_INIT (local, words, frame, dict); + answer = cli_cmd_get_confirmation (state, question); + + if (GF_ANSWER_NO == answer) { + ret = 0; + goto out; + } + + //send NULL as argument since no dictionary is sent to glusterd + if (proc->fn) { + ret = proc->fn (frame, this, dict); + } + +out: + if (ret) { + cli_cmd_sent_status_get (&sent); + if ((sent == 0) && (parse_error == 0)) + cli_out ("uuid reset failed"); + } + + CLI_STACK_DESTROY (frame); + + return ret; +} + struct cli_cmd cli_system_cmds[] = { { "system:: getspec ", cli_cmd_getspec_cbk, @@ -303,6 +364,10 @@ struct cli_cmd cli_system_cmds[] = { cli_cmd_umount_cbk, "request an umount"}, + { "system:: uuid reset", + cli_cmd_uuid_reset_cbk, + "reset the uuid of glusterd"}, + { "system:: help", cli_cmd_system_help_cbk, "display help for system commands"}, diff --git a/cli/src/cli-cmd-volume.c b/cli/src/cli-cmd-volume.c index f523579a6b2..5b02ef5d9fe 100644 --- a/cli/src/cli-cmd-volume.c +++ b/cli/src/cli-cmd-volume.c @@ -29,19 +29,6 @@ #include "cli1-xdr.h" #include "run.h" -#define CLI_LOCAL_INIT(local, words, frame, dictionary) \ - do { \ - local = cli_local_get (); \ - \ - if (local) { \ - local->words = words; \ - if (dictionary) \ - local->dict = dictionary; \ - if (frame) \ - frame->local = local; \ - } \ - } while (0) - extern struct rpc_clnt *global_rpc; extern rpc_clnt_prog_t *cli_rpc_prog; diff --git a/cli/src/cli-cmd.h b/cli/src/cli-cmd.h index 0ec3167742f..a30a6cfe418 100644 --- a/cli/src/cli-cmd.h +++ b/cli/src/cli-cmd.h @@ -20,6 +20,19 @@ #include "cli.h" #include "list.h" +#define CLI_LOCAL_INIT(local, words, frame, dictionary) \ + do { \ + local = cli_local_get (); \ + \ + if (local) { \ + local->words = words; \ + if (dictionary) \ + local->dict = dictionary; \ + if (frame) \ + frame->local = local; \ + } \ + } while (0) + #define CLI_STACK_DESTROY(_frame) \ do { \ if (_frame) { \ diff --git a/cli/src/cli-rpc-ops.c b/cli/src/cli-rpc-ops.c index 10ff6e7a90e..703289b5b54 100644 --- a/cli/src/cli-rpc-ops.c +++ b/cli/src/cli-rpc-ops.c @@ -891,6 +891,60 @@ out: return ret; } +int +gf_cli3_1_uuid_reset_cbk (struct rpc_req *req, struct iovec *iov, + int count, void *myframe) +{ + gf_cli_rsp rsp = {0,}; + int ret = -1; + cli_local_t *local = NULL; + call_frame_t *frame = NULL; + dict_t *dict = NULL; + + if (-1 == req->rpc_status) { + goto out; + } + + ret = xdr_to_generic (*iov, &rsp, (xdrproc_t)xdr_gf_cli_rsp); + if (ret < 0) { + gf_log ("", GF_LOG_ERROR, "error"); + goto out; + } + + frame = myframe; + local = frame->local; + frame->local = NULL; + + gf_log ("cli", GF_LOG_INFO, "Received resp to uuid reset"); + + if (global_state->mode & GLUSTER_MODE_XML) { + ret = cli_xml_output_dict ("uuidReset", dict, rsp.op_ret, + rsp.op_errno, rsp.op_errstr); + if (ret) + gf_log ("cli", GF_LOG_ERROR, + "Error outputting to xml"); + goto out; + } + + if (rsp.op_ret && strcmp (rsp.op_errstr, "")) + cli_err ("%s", rsp.op_errstr); + else + cli_out ("resetting the peer uuid has been %s", + (rsp.op_ret) ? "unsuccessful": "successful"); + ret = rsp.op_ret; + +out: + cli_cmd_broadcast_response (ret); + cli_local_wipe (local); + if (rsp.dict.dict_val) + free (rsp.dict.dict_val); + if (dict) + dict_unref (dict); + + gf_log ("", GF_LOG_INFO, "Returning with %d", ret); + return ret; +} + int gf_cli_start_volume_cbk (struct rpc_req *req, struct iovec *iov, int count, void *myframe) @@ -2509,6 +2563,28 @@ out: return ret; } +int32_t +gf_cli3_1_uuid_reset (call_frame_t *frame, xlator_t *this, + void *data) +{ + gf_cli_req req = {{0,}}; + int ret = 0; + dict_t *dict = NULL; + + if (!frame || !this || !data) { + ret = -1; + goto out; + } + + dict = data; + ret = cli_to_glusterd (&req, frame, gf_cli3_1_uuid_reset_cbk, + (xdrproc_t)xdr_gf_cli_req, dict, + GLUSTER_CLI_UUID_RESET, this, cli_rpc_prog, + NULL); +out: + gf_log ("cli", GF_LOG_DEBUG, "Returning %d", ret); + return ret; +} int32_t gf_cli_create_volume (call_frame_t *frame, xlator_t *this, @@ -6104,6 +6180,7 @@ struct rpc_clnt_procedure gluster_cli_actors[GLUSTER_CLI_MAXVALUE] = { [GLUSTER_CLI_PROBE] = {"PROBE_QUERY", gf_cli_probe}, [GLUSTER_CLI_DEPROBE] = {"DEPROBE_QUERY", gf_cli_deprobe}, [GLUSTER_CLI_LIST_FRIENDS] = {"LIST_FRIENDS", gf_cli_list_friends}, + [GLUSTER_CLI_UUID_RESET] = {"UUID_RESET", gf_cli3_1_uuid_reset}, [GLUSTER_CLI_CREATE_VOLUME] = {"CREATE_VOLUME", gf_cli_create_volume}, [GLUSTER_CLI_DELETE_VOLUME] = {"DELETE_VOLUME", gf_cli_delete_volume}, [GLUSTER_CLI_START_VOLUME] = {"START_VOLUME", gf_cli_start_volume}, diff --git a/rpc/rpc-lib/src/protocol-common.h b/rpc/rpc-lib/src/protocol-common.h index 0cb7d0a148e..e4a783a7fbb 100644 --- a/rpc/rpc-lib/src/protocol-common.h +++ b/rpc/rpc-lib/src/protocol-common.h @@ -153,6 +153,7 @@ enum gluster_cli_procnum { GLUSTER_CLI_STATEDUMP_VOLUME, GLUSTER_CLI_LIST_VOLUME, GLUSTER_CLI_CLRLOCKS_VOLUME, + GLUSTER_CLI_UUID_RESET, GLUSTER_CLI_MAXVALUE, }; diff --git a/tests/bugs/bug-811493.t b/tests/bugs/bug-811493.t new file mode 100755 index 00000000000..13e99af5798 --- /dev/null +++ b/tests/bugs/bug-811493.t @@ -0,0 +1,18 @@ +#!/bin/bash + +. $(dirname $0)/../include.rc + +cleanup; + +TEST glusterd +TEST pidof glusterd +TEST $CLI system uuid reset; + +uuid1=$(grep UUID /var/lib/glusterd/glusterd.info | cut -f 2 -d "="); + +TEST $CLI system uuid reset; +uuid2=$(grep UUID /var/lib/glusterd/glusterd.info | cut -f 2 -d "="); + +TEST [ $uuid1 != $uuid2 ] + +cleanup diff --git a/xlators/mgmt/glusterd/src/glusterd-handler.c b/xlators/mgmt/glusterd/src/glusterd-handler.c index 592fbbdb260..cec94f89f6c 100644 --- a/xlators/mgmt/glusterd/src/glusterd-handler.c +++ b/xlators/mgmt/glusterd/src/glusterd-handler.c @@ -920,6 +920,105 @@ out: return ret; } +int +glusterd_handle_cli_uuid_reset (rpcsvc_request_t *req) +{ + int ret = -1; + dict_t *dict = NULL; + xlator_t *this = NULL; + glusterd_conf_t *priv = NULL; + uuid_t uuid = {0}; + gf_cli_rsp rsp = {0,}; + gf_cli_req cli_req = {{0,}}; + char msg_str[2048] = {0,}; + + GF_ASSERT (req); + + this = THIS; + priv = this->private; + GF_ASSERT (priv); + + if (!xdr_to_generic (req->msg[0], &cli_req, (xdrproc_t)xdr_gf_cli_req)) { + //failed to decode msg; + req->rpc_err = GARBAGE_ARGS; + goto out; + } + + gf_log ("glusterd", GF_LOG_DEBUG, "Received uuid reset req"); + + if (cli_req.dict.dict_len) { + /* Unserialize the dictionary */ + dict = dict_new (); + + ret = dict_unserialize (cli_req.dict.dict_val, + cli_req.dict.dict_len, + &dict); + if (ret < 0) { + gf_log ("glusterd", GF_LOG_ERROR, + "failed to " + "unserialize req-buffer to dictionary"); + snprintf (msg_str, sizeof (msg_str), "Unable to decode " + "the buffer"); + goto out; + } else { + dict->extra_stdfree = cli_req.dict.dict_val; + } + } + + /* In the above section if dict_unserialize is successful, ret is set + * to zero. + */ + ret = -1; + // Do not allow peer reset if there are any volumes in the cluster + if (!list_empty (&priv->volumes)) { + snprintf (msg_str, sizeof (msg_str), "volumes are already " + "present in the cluster. Resetting uuid is not " + "allowed"); + gf_log (this->name, GF_LOG_WARNING, msg_str); + goto out; + } + + // Do not allow peer reset if trusted storage pool is already formed + if (!list_empty (&priv->peers)) { + snprintf (msg_str, sizeof (msg_str),"trusted storage pool " + "has been already formed. Please detach this peer " + "from the pool and reset its uuid."); + gf_log (this->name, GF_LOG_WARNING, msg_str); + goto out; + } + + uuid_copy (uuid, priv->uuid); + ret = glusterd_uuid_generate_save (); + + if (!uuid_compare (uuid, MY_UUID)) { + snprintf (msg_str, sizeof (msg_str), "old uuid and the new uuid" + " are same. Try gluster peer reset again"); + gf_log (this->name, GF_LOG_ERROR, msg_str); + ret = -1; + goto out; + } + +out: + if (ret) { + rsp.op_ret = -1; + if (msg_str[0] == '\0') + snprintf (msg_str, sizeof (msg_str), "Operation " + "failed"); + rsp.op_errstr = msg_str; + ret = 0; + } else { + rsp.op_errstr = ""; + } + + glusterd_to_cli (req, &rsp, NULL, 0, NULL, + (xdrproc_t)xdr_gf_cli_rsp, dict); + + if (dict) + dict_unref (dict); + + return ret; +} + int glusterd_handle_cli_list_volume (rpcsvc_request_t *req) { @@ -3035,6 +3134,7 @@ rpcsvc_actor_t gd_svc_cli_actors[] = { [GLUSTER_CLI_DEFRAG_VOLUME] = { "CLI_DEFRAG_VOLUME", GLUSTER_CLI_DEFRAG_VOLUME, glusterd_handle_defrag_volume, NULL, 0}, [GLUSTER_CLI_DEPROBE] = { "FRIEND_REMOVE", GLUSTER_CLI_DEPROBE, glusterd_handle_cli_deprobe, NULL, 0}, [GLUSTER_CLI_LIST_FRIENDS] = { "LIST_FRIENDS", GLUSTER_CLI_LIST_FRIENDS, glusterd_handle_cli_list_friends, NULL, 0}, + [GLUSTER_CLI_UUID_RESET] = { "UUID_RESET", GLUSTER_CLI_UUID_RESET, glusterd_handle_cli_uuid_reset, NULL, 0}, [GLUSTER_CLI_START_VOLUME] = { "START_VOLUME", GLUSTER_CLI_START_VOLUME, glusterd_handle_cli_start_volume, NULL, 0}, [GLUSTER_CLI_STOP_VOLUME] = { "STOP_VOLUME", GLUSTER_CLI_STOP_VOLUME, glusterd_handle_cli_stop_volume, NULL, 0}, [GLUSTER_CLI_DELETE_VOLUME] = { "DELETE_VOLUME", GLUSTER_CLI_DELETE_VOLUME, glusterd_handle_cli_delete_volume, NULL, 0}, diff --git a/xlators/mgmt/glusterd/src/glusterd.c b/xlators/mgmt/glusterd/src/glusterd.c index bd9e6e031fa..c4629c795da 100644 --- a/xlators/mgmt/glusterd/src/glusterd.c +++ b/xlators/mgmt/glusterd/src/glusterd.c @@ -43,7 +43,6 @@ #include "glusterd-mountbroker.h" -static uuid_t glusterd_uuid; extern struct rpcsvc_program gluster_handshake_prog; extern struct rpcsvc_program gluster_pmap_prog; extern glusterd_op_info_t opinfo; @@ -93,28 +92,47 @@ glusterd_uuid_init () ret = glusterd_retrieve_uuid (); if (ret == 0) { - uuid_copy (glusterd_uuid, priv->uuid); gf_log (this->name, GF_LOG_INFO, "retrieved UUID: %s", uuid_utoa (priv->uuid)); return 0; } - uuid_generate (glusterd_uuid); + ret = glusterd_uuid_generate_save (); - gf_log (this->name, GF_LOG_INFO, "generated UUID: %s", - uuid_utoa (glusterd_uuid)); + if (ret) { + gf_log ("glusterd", GF_LOG_ERROR, + "Unable to generate and save new UUID"); + return ret; + } + + return 0; +} + +int +glusterd_uuid_generate_save () +{ + int ret = -1; + glusterd_conf_t *priv = NULL; + xlator_t *this = NULL; + + this = THIS; + GF_ASSERT (this); + priv = this->private; + GF_ASSERT (priv); - uuid_copy (priv->uuid, glusterd_uuid); + uuid_generate (priv->uuid); + + gf_log (this->name, GF_LOG_INFO, "generated UUID: %s", + uuid_utoa (priv->uuid)); ret = glusterd_store_global_info (this); - if (ret) { + if (ret) gf_log (this->name, GF_LOG_ERROR, - "Unable to store generated UUID"); - return ret; - } + "Unable to store the generated uuid %s", + uuid_utoa (priv->uuid)); - return 0; + return ret; } int diff --git a/xlators/mgmt/glusterd/src/glusterd.h b/xlators/mgmt/glusterd/src/glusterd.h index fddfabd344f..95353f06514 100644 --- a/xlators/mgmt/glusterd/src/glusterd.h +++ b/xlators/mgmt/glusterd/src/glusterd.h @@ -389,6 +389,8 @@ typedef ssize_t (*gd_serialize_t) (struct iovec outmsg, void *args); int glusterd_uuid_init(); +int glusterd_uuid_generate_save (); + #define MY_UUID (__glusterd_uuid()) static inline unsigned char * -- cgit