From 2676c402bc47ee89b763393e496a013e82d76e54 Mon Sep 17 00:00:00 2001 From: Mohammed Rafi KC Date: Sat, 2 May 2015 17:31:07 +0530 Subject: cli/tiering: Enhance cli output for tiering Fix for handling cli output for attach-tier and detach-tier Change-Id: I4d17f4b09612754fe1b8cec6c2e14927029b9678 BUG: 1211562 Signed-off-by: Mohammed Rafi KC Reviewed-on: http://review.gluster.org/10284 Reviewed-by: Dan Lambright Tested-by: Gluster Build System Tested-by: NetBSD Build System Reviewed-by: Vijay Bellur --- cli/src/cli-cmd-parser.c | 2 +- cli/src/cli-cmd-volume.c | 2 +- cli/src/cli-rpc-ops.c | 378 ++++++++++++++++++++++++- cli/src/cli-xml-output.c | 10 +- cli/src/cli.h | 6 +- rpc/xdr/src/cli1-xdr.x | 3 +- tests/basic/tier/tier.t | 2 +- xlators/mgmt/glusterd/src/glusterd-brick-ops.c | 4 +- xlators/mgmt/glusterd/src/glusterd-rebalance.c | 7 + 9 files changed, 394 insertions(+), 20 deletions(-) diff --git a/cli/src/cli-cmd-parser.c b/cli/src/cli-cmd-parser.c index cf5e80d2f51..d4c846acd0a 100644 --- a/cli/src/cli-cmd-parser.c +++ b/cli/src/cli-cmd-parser.c @@ -1696,7 +1696,7 @@ cli_cmd_volume_detach_tier_parse (const char **words, int wordcount, else command = GF_OP_CMD_DETACH_COMMIT; } else if (!strcmp(word, "stop")) - command = GF_DEFRAG_CMD_STOP_DETACH_TIER; + command = GF_OP_CMD_STOP_DETACH_TIER; else if (!strcmp(word, "status")) command = GF_OP_CMD_STATUS; else diff --git a/cli/src/cli-cmd-volume.c b/cli/src/cli-cmd-volume.c index ba4aac49393..a6df78ff188 100644 --- a/cli/src/cli-cmd-volume.c +++ b/cli/src/cli-cmd-volume.c @@ -996,7 +996,7 @@ cli_cmd_volume_detach_tier_cbk (struct cli_state *state, if (ret) goto out; - ret = dict_set_int32 (options, "count", 1); + ret = dict_set_int32 (options, "count", 0); if (ret) goto out; diff --git a/cli/src/cli-rpc-ops.c b/cli/src/cli-rpc-ops.c index 59f0c6ed9d3..41964e131d9 100644 --- a/cli/src/cli-rpc-ops.c +++ b/cli/src/cli-rpc-ops.c @@ -1970,6 +1970,302 @@ out: return ret; } +int +gf_cli_attach_tier_cbk (struct rpc_req *req, struct iovec *iov, + int count, void *myframe) +{ + gf_cli_rsp rsp = {0,}; + int ret = -1; + char msg[1024] = {0,}; + + if (-1 == req->rpc_status) { + goto out; + } + + ret = xdr_to_generic (*iov, &rsp, (xdrproc_t)xdr_gf_cli_rsp); + if (ret < 0) { + gf_log (((call_frame_t *) myframe)->this->name, GF_LOG_ERROR, + "Failed to decode xdr response"); + goto out; + } + + + gf_log ("cli", GF_LOG_INFO, "Received resp to attach tier"); + + if (rsp.op_ret && strcmp (rsp.op_errstr, "")) + snprintf (msg, sizeof (msg), "%s", rsp.op_errstr); + else + snprintf (msg, sizeof (msg), "Attach tier %s", + (rsp.op_ret) ? "unsuccessful" : "successful"); + + if (global_state->mode & GLUSTER_MODE_XML) { + ret = cli_xml_output_str ("volAttachTier", msg, 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) + cli_err ("volume attach-tier: failed: %s", msg); + else + cli_out ("volume attach-tier: success"); + ret = rsp.op_ret; + +out: + cli_cmd_broadcast_response (ret); + free (rsp.dict.dict_val); + free (rsp.op_errstr); + return ret; +} + +int +gf_cli_detach_tier_cbk (struct rpc_req *req, struct iovec *iov, + int count, void *myframe) +{ + + gf_cli_rsp rsp = {0,}; + int ret = -1; + char msg[1024] = {0,}; + gf1_op_commands cmd = GF_OP_CMD_NONE; + char *cmd_str = "unknown"; + cli_local_t *local = NULL; + call_frame_t *frame = NULL; + char *task_id_str = NULL; + dict_t *rsp_dict = NULL; + + if (-1 == req->rpc_status) { + goto out; + } + + frame = myframe; + local = frame->local; + + 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; + } + + ret = dict_get_int32 (local->dict, "command", (int32_t *)&cmd); + if (ret) { + gf_log ("", GF_LOG_ERROR, "failed to get command"); + goto out; + } + + if (rsp.dict.dict_len) { + rsp_dict = dict_new (); + if (!rsp_dict) { + ret = -1; + goto out; + } + + ret = dict_unserialize (rsp.dict.dict_val, rsp.dict.dict_len, + &rsp_dict); + if (ret) { + gf_log ("cli", GF_LOG_ERROR, + "Failed to unserialize rsp_dict"); + goto out; + } + } + + switch (cmd) { + case GF_OP_CMD_DETACH_START: + cmd_str = "start"; + + ret = dict_get_str (rsp_dict, GF_REMOVE_BRICK_TID_KEY, + &task_id_str); + if (ret) { + gf_log ("cli", GF_LOG_ERROR, + "remove-brick-id is not present in dict"); + } + break; + case GF_OP_CMD_DETACH_COMMIT: + cmd_str = "commit"; + break; + case GF_OP_CMD_DETACH_COMMIT_FORCE: + cmd_str = "commit force"; + break; + default: + cmd_str = "unknown"; + break; + } + + gf_log ("cli", GF_LOG_INFO, "Received resp to detach-tier"); + + if (rsp.op_ret && strcmp (rsp.op_errstr, "")) + snprintf (msg, sizeof (msg), "%s", rsp.op_errstr); + else + snprintf (msg, sizeof (msg), "Detach tier %s %s", cmd_str, + (rsp.op_ret) ? "unsuccessful" : "successful"); + + + if (global_state->mode & GLUSTER_MODE_XML) { + ret = cli_xml_output_vol_remove_brick_detach_tier ( + _gf_false, rsp_dict, + rsp.op_ret, rsp.op_errno, + msg, "volDetachTier"); + + if (ret) + gf_log ("cli", GF_LOG_ERROR, + "Error outputting to xml"); + goto out; + } + + if (rsp.op_ret) { + cli_err ("volume detach-tier %s: failed: %s", cmd_str, + msg); + } else { + cli_out ("volume detach-tier %s: success", cmd_str); + if (GF_OP_CMD_DETACH_START == cmd && task_id_str != NULL) + cli_out ("ID: %s", task_id_str); + if (GF_OP_CMD_DETACH_COMMIT == cmd) + cli_out ("Check the detached bricks to ensure all files" + " are migrated.\nIf files with data are " + "found on the brick path, copy them via a " + "gluster mount point before re-purposing the " + "removed brick. "); + } + + ret = rsp.op_ret; + +out: + cli_cmd_broadcast_response (ret); + free (rsp.dict.dict_val); + free (rsp.op_errstr); + + return ret; +} + +int +gf_cli_detach_tier_status_cbk (struct rpc_req *req, struct iovec *iov, + int count, void *myframe) +{ + gf_cli_rsp rsp = {0,}; + int ret = -1; + dict_t *dict = NULL; + char msg[1024] = {0,}; + int32_t command = 0; + gf1_op_commands cmd = GF_OP_CMD_NONE; + cli_local_t *local = NULL; + call_frame_t *frame = NULL; + char *cmd_str = "unknown"; + + if (-1 == req->rpc_status) { + 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; + } + + if (frame) + local = frame->local; + ret = dict_get_int32 (local->dict, "command", &command); + if (ret) + goto out; + cmd = command; + + switch (cmd) { + case GF_OP_CMD_STOP_DETACH_TIER: + cmd_str = "stop"; + break; + case GF_OP_CMD_STATUS: + cmd_str = "status"; + break; + default: + break; + } + + ret = rsp.op_ret; + if (rsp.op_ret == -1) { + if (strcmp (rsp.op_errstr, "")) + snprintf (msg, sizeof (msg), "volume detach-tier %s: " + "failed: %s", cmd_str, rsp.op_errstr); + else + snprintf (msg, sizeof (msg), "volume detach-tier %s: " + "failed", cmd_str); + + if (global_state->mode & GLUSTER_MODE_XML) + goto xml_output; + + cli_err ("%s", msg); + goto out; + } + + if (rsp.dict.dict_len) { + /* Unserialize the dictionary */ + dict = dict_new (); + + ret = dict_unserialize (rsp.dict.dict_val, + rsp.dict.dict_len, + &dict); + if (ret < 0) { + strncpy (msg, "failed to unserialize req-buffer to " + "dictionary", sizeof (msg)); + + if (global_state->mode & GLUSTER_MODE_XML) { + rsp.op_ret = -1; + goto xml_output; + } + + gf_log ("cli", GF_LOG_ERROR, "%s", msg); + goto out; + } + } +xml_output: + if (global_state->mode & GLUSTER_MODE_XML) { + if (strcmp (rsp.op_errstr, "")) { + ret = cli_xml_output_vol_remove_brick_detach_tier ( + _gf_true, dict, + rsp.op_ret, + rsp.op_errno, + rsp.op_errstr, + "volDetachTier"); + } else { + ret = cli_xml_output_vol_remove_brick_detach_tier + (_gf_true, dict, + rsp.op_ret, + rsp.op_errno, + msg, + "volDetachTier"); + } + goto out; + } + + ret = gf_cli_print_rebalance_status (dict, GF_TASK_TYPE_REMOVE_BRICK); + if (ret) { + gf_log ("cli", GF_LOG_ERROR, "Failed to print remove-brick " + "rebalance status"); + goto out; + } + + if ((cmd == GF_OP_CMD_STOP_DETACH_TIER) && (rsp.op_ret == 0)) { + cli_out ("'detach-tier' process may be in the middle of a " + "file migration.\nThe process will be fully stopped " + "once the migration of the file is complete.\nPlease " + "check detach-tier process for completion before " + "doing any further brick related tasks on the " + "volume."); + } + +out: + free (rsp.dict.dict_val); /* malloced by xdr */ + if (dict) + dict_unref (dict); + cli_cmd_broadcast_response (ret); + return ret; +} + + int gf_cli_add_brick_cbk (struct rpc_req *req, struct iovec *iov, int count, void *myframe) @@ -2106,15 +2402,19 @@ gf_cli3_remove_brick_status_cbk (struct rpc_req *req, struct iovec *iov, xml_output: if (global_state->mode & GLUSTER_MODE_XML) { if (strcmp (rsp.op_errstr, "")) { - ret = cli_xml_output_vol_remove_brick (_gf_true, dict, + ret = cli_xml_output_vol_remove_brick_detach_tier ( + _gf_true, dict, rsp.op_ret, rsp.op_errno, - rsp.op_errstr); + rsp.op_errstr, + "volRemoveBrick"); } else { - ret = cli_xml_output_vol_remove_brick (_gf_true, dict, + ret = cli_xml_output_vol_remove_brick_detach_tier ( + _gf_true, dict, rsp.op_ret, rsp.op_errno, - msg); + msg, + "volRemoveBrick"); } goto out; } @@ -2225,9 +2525,10 @@ gf_cli_remove_brick_cbk (struct rpc_req *req, struct iovec *iov, (rsp.op_ret) ? "unsuccessful": "successful"); if (global_state->mode & GLUSTER_MODE_XML) { - ret = cli_xml_output_vol_remove_brick (_gf_false, rsp_dict, + ret = cli_xml_output_vol_remove_brick_detach_tier ( + _gf_false, rsp_dict, rsp.op_ret, rsp.op_errno, - msg); + msg, "volRemoveBrick"); if (ret) gf_log ("cli", GF_LOG_ERROR, "Error outputting to xml"); @@ -3779,7 +4080,7 @@ gf_cli_attach_tier (call_frame_t *frame, xlator_t *this, if (ret) goto out; - ret = cli_to_glusterd (&req, frame, gf_cli_add_brick_cbk, + ret = cli_to_glusterd (&req, frame, gf_cli_attach_tier_cbk, (xdrproc_t) xdr_gf_cli_req, dict, GLUSTER_CLI_ATTACH_TIER, this, cli_rpc_prog, NULL); @@ -3827,10 +4128,71 @@ int32_t gf_cli_detach_tier (call_frame_t *frame, xlator_t *this, void *data) { - return gf_cli_remove_brick(frame, this, data); + gf_cli_req req = { {0,} }; + gf_cli_req status_req = { {0,} }; + int ret = 0; + dict_t *dict = NULL; + int32_t command = 0; + char *volname = NULL; + int32_t cmd = 0; + + if (!frame || !this || !data) { + ret = -1; + goto out; + } + + dict = data; + + ret = dict_get_str (dict, "volname", &volname); + if (ret) + goto out; + + ret = dict_get_int32 (dict, "command", &command); + if (ret) + goto out; + + if ((command != GF_OP_CMD_STATUS) && + (command != GF_DEFRAG_CMD_STOP_DETACH_TIER)) { + + + ret = cli_to_glusterd (&req, frame, gf_cli_detach_tier_cbk, + (xdrproc_t) xdr_gf_cli_req, dict, + GLUSTER_CLI_REMOVE_BRICK, this, + cli_rpc_prog, NULL); + } else { + /* Need rebalance status to be sent :-) */ + if (command == GF_OP_CMD_STATUS) + cmd |= GF_DEFRAG_CMD_STATUS; + else + cmd |= GF_DEFRAG_CMD_STOP; + + ret = dict_set_int32 (dict, "rebalance-command", (int32_t) cmd); + if (ret) { + gf_log (this->name, GF_LOG_ERROR, + "Failed to set dict"); + goto out; + } + + ret = cli_to_glusterd (&status_req, frame, + gf_cli_detach_tier_status_cbk, + (xdrproc_t) xdr_gf_cli_req, dict, + GLUSTER_CLI_DEFRAG_VOLUME, this, + cli_rpc_prog, NULL); + + } + +out: + gf_log ("cli", GF_LOG_DEBUG, "Returning %d", ret); + + GF_FREE (req.dict.dict_val); + + GF_FREE (status_req.dict.dict_val); + + return ret; } + int32_t gf_cli_remove_brick (call_frame_t *frame, xlator_t *this, void *data) diff --git a/cli/src/cli-xml-output.c b/cli/src/cli-xml-output.c index f9013ed2726..d41aebc8cad 100644 --- a/cli/src/cli-xml-output.c +++ b/cli/src/cli-xml-output.c @@ -3371,8 +3371,10 @@ out: } int -cli_xml_output_vol_remove_brick (gf_boolean_t status_op, dict_t *dict, - int op_ret, int op_errno, char *op_errstr) +cli_xml_output_vol_remove_brick_detach_tier (gf_boolean_t status_op, + dict_t *dict, int op_ret, + int op_errno, char *op_errstr, + const char *op) { #if (HAVE_LIB_XML) int ret = -1; @@ -3388,8 +3390,7 @@ cli_xml_output_vol_remove_brick (gf_boolean_t status_op, dict_t *dict, if (ret) goto out; - /* */ - ret = xmlTextWriterStartElement (writer, (xmlChar *)"volRemoveBrick"); + ret = xmlTextWriterStartElement (writer, (xmlChar *) op); XML_RET_CHECK_AND_GOTO (ret, out); ret = dict_get_str (dict, GF_REMOVE_BRICK_TID_KEY, &task_id_str); @@ -3407,7 +3408,6 @@ cli_xml_output_vol_remove_brick (gf_boolean_t status_op, dict_t *dict, goto out; } - /* */ ret = xmlTextWriterEndElement (writer); XML_RET_CHECK_AND_GOTO (ret, out); diff --git a/cli/src/cli.h b/cli/src/cli.h index 3da58dd22d8..c9283b5b875 100644 --- a/cli/src/cli.h +++ b/cli/src/cli.h @@ -403,8 +403,10 @@ cli_xml_output_vol_rebalance (gf_cli_defrag_type op, dict_t *dict, int op_ret, int op_errno, char *op_errstr); int -cli_xml_output_vol_remove_brick (gf_boolean_t status_op, dict_t *dict, - int op_ret, int op_errno, char *op_errstr); +cli_xml_output_vol_remove_brick_detach_tier (gf_boolean_t status_op, + dict_t *dict, int op_ret, + int op_errno, char *op_errstr, + const char *op); int cli_xml_output_vol_replace_brick (char *op, dict_t *dict, int op_ret, diff --git a/rpc/xdr/src/cli1-xdr.x b/rpc/xdr/src/cli1-xdr.x index cdf8e725788..0d5d3cc360c 100644 --- a/rpc/xdr/src/cli1-xdr.x +++ b/rpc/xdr/src/cli1-xdr.x @@ -52,7 +52,8 @@ enum gf_bitrot_type { GF_OP_CMD_COMMIT_FORCE, GF_OP_CMD_DETACH_START, GF_OP_CMD_DETACH_COMMIT, - GF_OP_CMD_DETACH_COMMIT_FORCE + GF_OP_CMD_DETACH_COMMIT_FORCE, + GF_OP_CMD_STOP_DETACH_TIER }; enum gf_quota_type { diff --git a/tests/basic/tier/tier.t b/tests/basic/tier/tier.t index ce2c7c36c1b..79e171f85bf 100755 --- a/tests/basic/tier/tier.t +++ b/tests/basic/tier/tier.t @@ -125,7 +125,7 @@ TEST $CLI volume rebalance $V0 tier status TEST $CLI volume detach-tier $V0 start -TEST $CLI volume detach-tier $V0 commit +TEST $CLI volume detach-tier $V0 commit force EXPECT "0" file_on_slow_tier d1/data.txt diff --git a/xlators/mgmt/glusterd/src/glusterd-brick-ops.c b/xlators/mgmt/glusterd/src/glusterd-brick-ops.c index d21a7341570..42927108f08 100644 --- a/xlators/mgmt/glusterd/src/glusterd-brick-ops.c +++ b/xlators/mgmt/glusterd/src/glusterd-brick-ops.c @@ -1738,10 +1738,12 @@ glusterd_op_stage_remove_brick (dict_t *dict, char **op_errstr) } case GF_OP_CMD_STOP: + case GF_OP_CMD_STOP_DETACH_TIER: ret = 0; break; case GF_OP_CMD_COMMIT: + case GF_OP_CMD_DETACH_COMMIT: if (volinfo->decommission_in_progress) { errstr = gf_strdup ("use 'force' option as migration " "is in progress"); @@ -1791,7 +1793,6 @@ glusterd_op_stage_remove_brick (dict_t *dict, char **op_errstr) break; - case GF_OP_CMD_DETACH_COMMIT: case GF_OP_CMD_DETACH_COMMIT_FORCE: case GF_OP_CMD_COMMIT_FORCE: break; @@ -2081,6 +2082,7 @@ glusterd_op_remove_brick (dict_t *dict, char **op_errstr) goto out; case GF_OP_CMD_STOP: + case GF_OP_CMD_STOP_DETACH_TIER: { /* Fall back to the old volume file */ cds_list_for_each_entry_safe (brickinfo, tmp, &volinfo->bricks, diff --git a/xlators/mgmt/glusterd/src/glusterd-rebalance.c b/xlators/mgmt/glusterd/src/glusterd-rebalance.c index c14bcd156b4..1566f54695f 100644 --- a/xlators/mgmt/glusterd/src/glusterd-rebalance.c +++ b/xlators/mgmt/glusterd/src/glusterd-rebalance.c @@ -690,6 +690,13 @@ glusterd_op_stage_rebalance (dict_t *dict, char **op_errstr) goto out; } } + if ((strstr(cmd_str, "detach-tier") != NULL) && + (volinfo->rebal.op != GD_OP_REMOVE_BRICK)) { + snprintf (msg, sizeof(msg), "Detach-tier not started."); + ret = -1; + goto out; + } + break; default: break; -- cgit